diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 6df7967ea..2e1ecf858 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -104,11 +104,14 @@ void BlocksRenderer::vertexAO( const glm::vec3& coord, float u, float v, const glm::vec4& tint, + float normalHalfLen, const glm::vec3& axisX, const glm::vec3& axisY, const glm::vec3& axisZ ) { - auto pos = coord+axisZ*0.5f+(axisX+axisY)*0.5f; + // Sample AO in world-voxel grid with a slightly longer reach along the normal + // to avoid sampling the same chunk voxel when faces reside over neighbor chunk. + auto pos = coord + axisZ * normalHalfLen + (axisX + axisY) * 0.5f; auto light = pickSoftLight( glm::ivec3(std::round(pos.x), std::round(pos.y), std::round(pos.z)), axisX, @@ -140,10 +143,11 @@ void BlocksRenderer::faceAO( auto axisZ = glm::normalize(Z); glm::vec4 tint(d); - vertexAO(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisX, axisY, axisZ); - vertexAO(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisX, axisY, axisZ); - vertexAO(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisX, axisY, axisZ); - vertexAO(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisX, axisY, axisZ); + 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); } else { auto axisZ = glm::normalize(Z); glm::vec4 tint(1.0f); diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index a954fad6e..7a22e1d35 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -32,7 +32,8 @@ class BlocksRenderer { size_t indexCount; size_t denseIndexCount; size_t capacity; - int voxelBufferPadding = 2; + // Increased to better cover cross-chunk sampling for extended blocks (e.g., 3x3x3) + int voxelBufferPadding = 4; bool overflow = false; bool cancelled = false; bool densePass = false; @@ -61,6 +62,7 @@ class BlocksRenderer { void vertexAO( const glm::vec3& coord, float u, float v, const glm::vec4& brightness, + float normalHalfLen, const glm::vec3& axisX, const glm::vec3& axisY, const glm::vec3& axisZ diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index b0dfaec3e..a50234b7f 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -181,6 +181,10 @@ const Mesh* ChunksRenderer::retrieveChunk( 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; if (!frustum.isBoxVisible(min, max)) return nullptr; } @@ -332,6 +336,9 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { 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; if (!frustum.isBoxVisible(min, max)) continue; }