From caa73fed353fbe7ab3498d865ec87142bd3aa75e Mon Sep 17 00:00:00 2001 From: Martin Gerhardy Date: Tue, 2 Apr 2024 17:08:59 +0200 Subject: [PATCH] VOXELRENDER: fixed invalid face culling for negative scaling values fixes parts of issue #440 --- src/modules/voxelrender/MeshState.cpp | 14 ++++++++++++++ src/modules/voxelrender/MeshState.h | 8 ++++++++ src/modules/voxelrender/RawVolumeRenderer.cpp | 4 ++++ src/modules/voxelrender/SceneGraphRenderer.cpp | 8 ++++++++ 4 files changed, 34 insertions(+) diff --git a/src/modules/voxelrender/MeshState.cpp b/src/modules/voxelrender/MeshState.cpp index 83c8d8843..09ee383aa 100644 --- a/src/modules/voxelrender/MeshState.cpp +++ b/src/modules/voxelrender/MeshState.cpp @@ -394,6 +394,20 @@ void MeshState::hide(int idx, bool hide) { _volumeData[idx]._hidden = hide; } +video::Face MeshState::cullFace(int idx) const { + if (idx < 0 || idx >= MAX_VOLUMES) { + return video::Face::Back; + } + return _volumeData[idx]._cullFace; +} + +void MeshState::setCullFace(int idx, video::Face face) { + if (idx < 0 || idx >= MAX_VOLUMES) { + return; + } + _volumeData[idx]._cullFace = face; +} + bool MeshState::grayed(int idx) const { if (idx < 0 || idx >= MAX_VOLUMES) { return true; diff --git a/src/modules/voxelrender/MeshState.h b/src/modules/voxelrender/MeshState.h index 98d0b0015..93d613647 100644 --- a/src/modules/voxelrender/MeshState.h +++ b/src/modules/voxelrender/MeshState.h @@ -13,6 +13,7 @@ #include "core/collection/PriorityQueue.h" #include "core/concurrent/ThreadPool.h" #include "palette/Palette.h" +#include "video/Types.h" #include "voxel/ChunkMesh.h" #include "voxel/Mesh.h" @@ -44,6 +45,9 @@ class MeshState { core::Optional _palette; bool _hidden = false; bool _gray = false; + // if all axes scale positive: cull the back face + // if one or three axes are negative, then cull the front face + video::Face _cullFace = video::Face::Back; int _reference = -1; glm::mat4 _model{1.0f}; glm::vec3 _pivot{0.0f}; @@ -164,6 +168,10 @@ class MeshState { void gray(int idx, bool gray); bool grayed(int idx) const; + // for scaling on 1 or 3 axes negative we need to flip the face culling + video::Face cullFace(int idx) const; + void setCullFace(int idx, video::Face face); + /** * @brief In case of a reference - this gives us the index for the * referenced object diff --git a/src/modules/voxelrender/RawVolumeRenderer.cpp b/src/modules/voxelrender/RawVolumeRenderer.cpp index 5e048062c..07c402325 100644 --- a/src/modules/voxelrender/RawVolumeRenderer.cpp +++ b/src/modules/voxelrender/RawVolumeRenderer.cpp @@ -18,6 +18,7 @@ #include "video/Camera.h" #include "video/FrameBufferConfig.h" #include "video/Renderer.h" +#include "video/ScopedFaceCull.h" #include "video/ScopedFrameBuffer.h" #include "video/ScopedPolygonMode.h" #include "video/ScopedState.h" @@ -494,6 +495,7 @@ void RawVolumeRenderer::render(RenderContext &renderContext, const video::Camera var.pivot = _meshState->pivot(idx); _shadowMapUniformBlock.update(var); _shadowMapShader.setBlock(_shadowMapUniformBlock.getBlockUniformBuffer()); + video::ScopedFaceCull scopedFaceCull(_meshState->cullFace(idx)); static_assert(sizeof(voxel::IndexType) == sizeof(uint32_t), "Index type doesn't match"); video::drawElements(video::Primitive::Triangles, indices); } @@ -562,6 +564,7 @@ void RawVolumeRenderer::render(RenderContext &renderContext, const video::Camera core_assert_always(_voxelData.update(_voxelShaderVertData)); video::ScopedPolygonMode polygonMode(mode); + video::ScopedFaceCull scopedFaceCull(_meshState->cullFace(idx)); video::ScopedBuffer scopedBuf(_state[bufferIndex]._vertexBuffer[MeshType_Opaque]); if (normals) { core_assert_always(_voxelNormShader.setFrag(_voxelData.getFragUniformBuffer())); @@ -617,6 +620,7 @@ void RawVolumeRenderer::render(RenderContext &renderContext, const video::Camera core_assert_always(_voxelData.update(_voxelShaderVertData)); video::ScopedPolygonMode polygonMode(mode); + video::ScopedFaceCull scopedFaceCull(_meshState->cullFace(idx)); video::ScopedBuffer scopedBuf(_state[bufferIndex]._vertexBuffer[MeshType_Transparency]); if (normals) { core_assert_always(_voxelNormShader.setFrag(_voxelData.getFragUniformBuffer())); diff --git a/src/modules/voxelrender/SceneGraphRenderer.cpp b/src/modules/voxelrender/SceneGraphRenderer.cpp index 35dab9e96..67a63e7c4 100644 --- a/src/modules/voxelrender/SceneGraphRenderer.cpp +++ b/src/modules/voxelrender/SceneGraphRenderer.cpp @@ -216,12 +216,20 @@ void SceneGraphRenderer::prepare(const RenderContext &renderContext) { } if (sceneMode) { const scenegraph::FrameTransform &transform = sceneGraph.transformForFrame(node, frame); + const int negative = (int)std::signbit(transform.scale.x) + (int)std::signbit(transform.scale.y) + + (int)std::signbit(transform.scale.z); + if (negative == 1 || negative == 3) { + meshState->setCullFace(id, video::Face::Front); + } else { + meshState->setCullFace(id, video::Face::Back); + } const glm::mat4 worldMatrix = transform.worldMatrix(); const glm::vec3 maxs = worldMatrix * glm::vec4(region.getUpperCorner(), 1.0f); const glm::vec3 mins = worldMatrix * glm::vec4(region.getLowerCorner(), 1.0f); const glm::vec3 pivot = transform.scale * node.pivot() * glm::vec3(region.getDimensionsInVoxels()); meshState->setModelMatrix(id, worldMatrix, pivot, mins, maxs); } else { + meshState->setCullFace(id, video::Face::Back); meshState->setModelMatrix(id, glm::mat4(1.0f), glm::vec3(0.0f), region.getLowerCorner(), region.getUpperCorner()); }