diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 2e1ecf858..304168e4d 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -74,6 +74,15 @@ void BlocksRenderer::index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint3 vertexOffset += 4; } +static inline void expand_aabb(AABB& aabb, bool& init, const glm::vec3& p) { + if (!init) { + aabb.a = aabb.b = p; + init = true; + } else { + aabb.addPoint(p); + } +} + /// @brief Add face with precalculated lights void BlocksRenderer::face( const glm::vec3& coord, @@ -98,6 +107,14 @@ void BlocksRenderer::face( vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, lights[2] * tint, axisZ, 0); vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, lights[3] * tint, axisZ, 0); index(0, 1, 3, 1, 2, 3); + + // Expand local opaque AABB while vertices are still in chunk-local space + if (!densePass) { + expand_aabb(localAabb, localAabbInit, coord + (-X - Y + Z) * s); + expand_aabb(localAabb, localAabbInit, coord + ( X - Y + Z) * s); + expand_aabb(localAabb, localAabbInit, coord + ( X + Y + Z) * s); + expand_aabb(localAabb, localAabbInit, coord + (-X + Y + Z) * s); + } } void BlocksRenderer::vertexAO( @@ -144,17 +161,37 @@ void BlocksRenderer::faceAO( glm::vec4 tint(d); const float nh = 0.75f; // push AO sample a bit farther along normal - vertexAO(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, nh, axisX, axisY, axisZ); - vertexAO(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, nh, axisX, axisY, axisZ); - vertexAO(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, nh, axisX, axisY, axisZ); - vertexAO(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, nh, axisX, axisY, axisZ); + auto p0 = coord + (-X - Y + Z) * s; + auto p1 = coord + ( X - Y + Z) * s; + auto p2 = coord + ( X + Y + Z) * s; + auto p3 = coord + (-X + Y + Z) * s; + vertexAO(p0, region.u1, region.v1, tint, nh, axisX, axisY, axisZ); + vertexAO(p1, region.u2, region.v1, tint, nh, axisX, axisY, axisZ); + vertexAO(p2, region.u2, region.v2, tint, nh, axisX, axisY, axisZ); + vertexAO(p3, region.u1, region.v2, tint, nh, axisX, axisY, axisZ); + if (!densePass) { + expand_aabb(localAabb, localAabbInit, p0); + expand_aabb(localAabb, localAabbInit, p1); + expand_aabb(localAabb, localAabbInit, p2); + expand_aabb(localAabb, localAabbInit, p3); + } } else { auto axisZ = glm::normalize(Z); glm::vec4 tint(1.0f); - vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisZ, 1); - vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisZ, 1); - vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisZ, 1); - vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisZ, 1); + auto p0 = coord + (-X - Y + Z) * s; + auto p1 = coord + ( X - Y + Z) * s; + auto p2 = coord + ( X + Y + Z) * s; + auto p3 = coord + (-X + Y + Z) * s; + vertex(p0, region.u1, region.v1, tint, axisZ, 1); + vertex(p1, region.u2, region.v1, tint, axisZ, 1); + vertex(p2, region.u2, region.v2, tint, axisZ, 1); + vertex(p3, region.u1, region.v2, tint, axisZ, 1); + if (!densePass) { + expand_aabb(localAabb, localAabbInit, p0); + expand_aabb(localAabb, localAabbInit, p1); + expand_aabb(localAabb, localAabbInit, p2); + expand_aabb(localAabb, localAabbInit, p3); + } } index(0, 1, 2, 0, 2, 3); } @@ -646,6 +683,9 @@ SortingMeshData BlocksRenderer::renderTranslucent( aabb.addPoint(vertex.position); } + // also widen overall local AABB for translucent geometry + expand_aabb(localAabb, localAabbInit, vertex.position); + vertex.position.x += chunk->x * CHUNK_W + 0.5f; vertex.position.y += 0.5f; vertex.position.z += chunk->z * CHUNK_D + 0.5f; @@ -681,6 +721,9 @@ SortingMeshData BlocksRenderer::renderTranslucent( void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { this->chunk = chunk; + // reset local AABB accumulation + localAabbInit = false; + localAabb = AABB{glm::vec3(0.0f), glm::vec3(0.0f)}; voxelsBuffer->setPosition( chunk->x * CHUNK_W - voxelBufferPadding, 0, chunk->z * CHUNK_D - voxelBufferPadding); @@ -758,7 +801,8 @@ ChunkMeshData BlocksRenderer::createMesh() { ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute) ) ), - std::move(sortingMesh) + std::move(sortingMesh), + localAabbInit ? localAabb : AABB{glm::vec3(0.0f), glm::vec3(0.0f)} }; } diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 7a22e1d35..ceeef96e5 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -11,6 +11,7 @@ #include "maths/util.hpp" #include "commons.hpp" #include "settings.hpp" +#include "maths/aabb.hpp" template class Mesh; class Content; @@ -48,6 +49,9 @@ class BlocksRenderer { util::PseudoRandom randomizer; SortingMeshData sortingMesh; + // Accumulated local-space AABB over opaque build pass + AABB localAabb {glm::vec3(0.0f), glm::vec3(0.0f)}; + bool localAabbInit = false; void vertex( const glm::vec3& coord, @@ -172,6 +176,7 @@ public: ChunkMesh render(const Chunk* chunk, const Chunks* chunks); ChunkMeshData createMesh(); VoxelsVolume* getVoxelsBuffer() const; + inline const AABB& getLocalAabb() const { return localAabb; } size_t getMemoryConsumption() const; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index a50234b7f..07db9e7c4 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -13,6 +13,7 @@ #include "maths/FrustumCulling.hpp" #include "util/listutil.hpp" #include "settings.hpp" +#include static debug::Logger logger("chunks-render"); @@ -76,6 +77,7 @@ ChunksRenderer::ChunksRenderer( meshes[result.key] = ChunkMesh { std::make_unique>(meshData.mesh), std::move(meshData.sortingMesh)}; + meshes[result.key].localAabb = meshData.localAabb; } inwork.erase(result.key); }, @@ -103,6 +105,8 @@ const Mesh* ChunksRenderer::render( meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh { std::move(mesh.mesh), std::move(mesh.sortingMeshData) }; + // propagate local aabb from immediate path too + meshes[glm::ivec2(chunk->x, chunk->z)].localAabb = renderer->getLocalAabb(); return meshes[glm::ivec2(chunk->x, chunk->z)].mesh.get(); } glm::ivec2 key(chunk->x, chunk->z); @@ -175,17 +179,21 @@ const Mesh* ChunksRenderer::retrieveChunk( chunk->updateHeights(); } if (culling) { + // Prefer precise per-mesh local AABB if present glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D); - glm::vec3 max( - chunk->x * CHUNK_W + CHUNK_W, - chunk->top, - chunk->z * CHUNK_D + CHUNK_D - ); - // Expand bounds to include possible overhang from extended blocks rendered by this chunk - const float overhang = 4.0f; // blocks - min.x -= overhang; min.z -= overhang; - max.x += overhang; max.z += overhang; - + glm::vec3 max(chunk->x * CHUNK_W + CHUNK_W, chunk->top, chunk->z * CHUNK_D + CHUNK_D); + auto found = meshes.find(glm::ivec2(chunk->x, chunk->z)); + if (found != meshes.end()) { + const auto& aabb = found->second.localAabb; + if (aabb.size().x > 0.0f || aabb.size().y > 0.0f || aabb.size().z > 0.0f) { + min = glm::vec3(chunk->x * CHUNK_W + aabb.min().x + 0.5f, + (std::max)(static_cast(chunk->bottom), aabb.min().y + 0.5f), + chunk->z * CHUNK_D + aabb.min().z + 0.5f); + max = glm::vec3(chunk->x * CHUNK_W + aabb.max().x + 0.5f, + (std::min)(static_cast(chunk->top), aabb.max().y + 0.5f), + chunk->z * CHUNK_D + aabb.max().z + 0.5f); + } + } if (!frustum.isBoxVisible(min, max)) return nullptr; } return mesh; @@ -224,7 +232,19 @@ void ChunksRenderer::drawShadowsPass( chunk->top, chunk->z * CHUNK_D + CHUNK_D ); - + // Prefer precise per-mesh bounds if available + const auto& found2 = meshes.find(glm::ivec2(chunk->x, chunk->z)); + if (found2 != meshes.end()) { + const auto& aabb = found2->second.localAabb; + if (aabb.size().x > 0.0f || aabb.size().y > 0.0f || aabb.size().z > 0.0f) { + min = glm::vec3(chunk->x * CHUNK_W + aabb.min().x + 0.5f, + (std::max)(static_cast(chunk->bottom), aabb.min().y + 0.5f), + chunk->z * CHUNK_D + aabb.min().z + 0.5f); + max = glm::vec3(chunk->x * CHUNK_W + aabb.max().x + 0.5f, + (std::min)(static_cast(chunk->top), aabb.max().y + 0.5f), + chunk->z * CHUNK_D + aabb.max().z + 0.5f); + } + } if (!frustum.isBoxVisible(min, max)) { continue; } @@ -331,15 +351,19 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { if (culling) { glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D); - glm::vec3 max( - chunk->x * CHUNK_W + CHUNK_W, - chunk->top, - chunk->z * CHUNK_D + CHUNK_D - ); - const float overhang = 4.0f; - min.x -= overhang; min.z -= overhang; - max.x += overhang; max.z += overhang; - + glm::vec3 max(chunk->x * CHUNK_W + CHUNK_W, chunk->top, chunk->z * CHUNK_D + CHUNK_D); + const auto& found2 = meshes.find(glm::ivec2(chunk->x, chunk->z)); + if (found2 != meshes.end()) { + const auto& aabb = found2->second.localAabb; + if (aabb.size().x > 0.0f || aabb.size().y > 0.0f || aabb.size().z > 0.0f) { + min = glm::vec3(chunk->x * CHUNK_W + aabb.min().x + 0.5f, + (std::max)(static_cast(chunk->bottom), aabb.min().y + 0.5f), + chunk->z * CHUNK_D + aabb.min().z + 0.5f); + max = glm::vec3(chunk->x * CHUNK_W + aabb.max().x + 0.5f, + (std::min)(static_cast(chunk->top), aabb.max().y + 0.5f), + chunk->z * CHUNK_D + aabb.max().z + 0.5f); + } + } if (!frustum.isBoxVisible(min, max)) continue; } diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index 9e78d1f53..77cc2cfd3 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -8,6 +8,7 @@ #include "graphics/core/MeshData.hpp" #include "util/Buffer.hpp" +#include "maths/aabb.hpp" /// @brief Chunk mesh vertex format struct ChunkVertex { @@ -44,10 +45,12 @@ struct SortingMeshData { struct ChunkMeshData { MeshData mesh; SortingMeshData sortingMesh; + AABB localAabb; // mesh-space (chunk-local) bounds for precise culling }; struct ChunkMesh { std::unique_ptr> mesh; SortingMeshData sortingMeshData; std::unique_ptr > sortedMesh = nullptr; + AABB localAabb; // mesh-space (chunk-local) bounds for precise culling };