mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-10 21:41:50 +00:00
fix cross-chunk culling for extended blocks with precise mesh AABBs
This commit is contained in:
parent
27ce16db27
commit
4dc1fdbe05
4 changed files with 105 additions and 29 deletions
|
|
@ -74,6 +74,15 @@ void BlocksRenderer::index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint3
|
||||||
vertexOffset += 4;
|
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
|
/// @brief Add face with precalculated lights
|
||||||
void BlocksRenderer::face(
|
void BlocksRenderer::face(
|
||||||
const glm::vec3& coord,
|
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.u2, region.v2, lights[2] * tint, axisZ, 0);
|
||||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, lights[3] * 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);
|
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(
|
void BlocksRenderer::vertexAO(
|
||||||
|
|
@ -144,17 +161,37 @@ void BlocksRenderer::faceAO(
|
||||||
|
|
||||||
glm::vec4 tint(d);
|
glm::vec4 tint(d);
|
||||||
const float nh = 0.75f; // push AO sample a bit farther along normal
|
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);
|
auto p0 = coord + (-X - Y + Z) * s;
|
||||||
vertexAO(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, nh, axisX, axisY, axisZ);
|
auto p1 = coord + ( X - Y + Z) * s;
|
||||||
vertexAO(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, nh, axisX, axisY, axisZ);
|
auto p2 = coord + ( X + Y + Z) * s;
|
||||||
vertexAO(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, nh, axisX, axisY, axisZ);
|
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 {
|
} else {
|
||||||
auto axisZ = glm::normalize(Z);
|
auto axisZ = glm::normalize(Z);
|
||||||
glm::vec4 tint(1.0f);
|
glm::vec4 tint(1.0f);
|
||||||
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisZ, 1);
|
auto p0 = coord + (-X - Y + Z) * s;
|
||||||
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisZ, 1);
|
auto p1 = coord + ( X - Y + Z) * s;
|
||||||
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisZ, 1);
|
auto p2 = coord + ( X + Y + Z) * s;
|
||||||
vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisZ, 1);
|
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);
|
index(0, 1, 2, 0, 2, 3);
|
||||||
}
|
}
|
||||||
|
|
@ -646,6 +683,9 @@ SortingMeshData BlocksRenderer::renderTranslucent(
|
||||||
aabb.addPoint(vertex.position);
|
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.x += chunk->x * CHUNK_W + 0.5f;
|
||||||
vertex.position.y += 0.5f;
|
vertex.position.y += 0.5f;
|
||||||
vertex.position.z += chunk->z * CHUNK_D + 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) {
|
void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
|
||||||
this->chunk = chunk;
|
this->chunk = chunk;
|
||||||
|
// reset local AABB accumulation
|
||||||
|
localAabbInit = false;
|
||||||
|
localAabb = AABB{glm::vec3(0.0f), glm::vec3(0.0f)};
|
||||||
voxelsBuffer->setPosition(
|
voxelsBuffer->setPosition(
|
||||||
chunk->x * CHUNK_W - voxelBufferPadding, 0,
|
chunk->x * CHUNK_W - voxelBufferPadding, 0,
|
||||||
chunk->z * CHUNK_D - voxelBufferPadding);
|
chunk->z * CHUNK_D - voxelBufferPadding);
|
||||||
|
|
@ -758,7 +801,8 @@ ChunkMeshData BlocksRenderer::createMesh() {
|
||||||
ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute)
|
ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
std::move(sortingMesh)
|
std::move(sortingMesh),
|
||||||
|
localAabbInit ? localAabb : AABB{glm::vec3(0.0f), glm::vec3(0.0f)}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "maths/util.hpp"
|
#include "maths/util.hpp"
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
#include "maths/aabb.hpp"
|
||||||
|
|
||||||
template<typename VertexStructure> class Mesh;
|
template<typename VertexStructure> class Mesh;
|
||||||
class Content;
|
class Content;
|
||||||
|
|
@ -48,6 +49,9 @@ class BlocksRenderer {
|
||||||
util::PseudoRandom randomizer;
|
util::PseudoRandom randomizer;
|
||||||
|
|
||||||
SortingMeshData sortingMesh;
|
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(
|
void vertex(
|
||||||
const glm::vec3& coord,
|
const glm::vec3& coord,
|
||||||
|
|
@ -172,6 +176,7 @@ public:
|
||||||
ChunkMesh render(const Chunk* chunk, const Chunks* chunks);
|
ChunkMesh render(const Chunk* chunk, const Chunks* chunks);
|
||||||
ChunkMeshData createMesh();
|
ChunkMeshData createMesh();
|
||||||
VoxelsVolume* getVoxelsBuffer() const;
|
VoxelsVolume* getVoxelsBuffer() const;
|
||||||
|
inline const AABB& getLocalAabb() const { return localAabb; }
|
||||||
|
|
||||||
size_t getMemoryConsumption() const;
|
size_t getMemoryConsumption() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "maths/FrustumCulling.hpp"
|
#include "maths/FrustumCulling.hpp"
|
||||||
#include "util/listutil.hpp"
|
#include "util/listutil.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
static debug::Logger logger("chunks-render");
|
static debug::Logger logger("chunks-render");
|
||||||
|
|
||||||
|
|
@ -76,6 +77,7 @@ ChunksRenderer::ChunksRenderer(
|
||||||
meshes[result.key] = ChunkMesh {
|
meshes[result.key] = ChunkMesh {
|
||||||
std::make_unique<Mesh<ChunkVertex>>(meshData.mesh),
|
std::make_unique<Mesh<ChunkVertex>>(meshData.mesh),
|
||||||
std::move(meshData.sortingMesh)};
|
std::move(meshData.sortingMesh)};
|
||||||
|
meshes[result.key].localAabb = meshData.localAabb;
|
||||||
}
|
}
|
||||||
inwork.erase(result.key);
|
inwork.erase(result.key);
|
||||||
},
|
},
|
||||||
|
|
@ -103,6 +105,8 @@ const Mesh<ChunkVertex>* ChunksRenderer::render(
|
||||||
meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh {
|
meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh {
|
||||||
std::move(mesh.mesh), std::move(mesh.sortingMeshData)
|
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();
|
return meshes[glm::ivec2(chunk->x, chunk->z)].mesh.get();
|
||||||
}
|
}
|
||||||
glm::ivec2 key(chunk->x, chunk->z);
|
glm::ivec2 key(chunk->x, chunk->z);
|
||||||
|
|
@ -175,17 +179,21 @@ const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
||||||
chunk->updateHeights();
|
chunk->updateHeights();
|
||||||
}
|
}
|
||||||
if (culling) {
|
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 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D);
|
||||||
glm::vec3 max(
|
glm::vec3 max(chunk->x * CHUNK_W + CHUNK_W, chunk->top, chunk->z * CHUNK_D + CHUNK_D);
|
||||||
chunk->x * CHUNK_W + CHUNK_W,
|
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
||||||
chunk->top,
|
if (found != meshes.end()) {
|
||||||
chunk->z * CHUNK_D + CHUNK_D
|
const auto& aabb = found->second.localAabb;
|
||||||
);
|
if (aabb.size().x > 0.0f || aabb.size().y > 0.0f || aabb.size().z > 0.0f) {
|
||||||
// Expand bounds to include possible overhang from extended blocks rendered by this chunk
|
min = glm::vec3(chunk->x * CHUNK_W + aabb.min().x + 0.5f,
|
||||||
const float overhang = 4.0f; // blocks
|
(std::max)(static_cast<float>(chunk->bottom), aabb.min().y + 0.5f),
|
||||||
min.x -= overhang; min.z -= overhang;
|
chunk->z * CHUNK_D + aabb.min().z + 0.5f);
|
||||||
max.x += overhang; max.z += overhang;
|
max = glm::vec3(chunk->x * CHUNK_W + aabb.max().x + 0.5f,
|
||||||
|
(std::min)(static_cast<float>(chunk->top), aabb.max().y + 0.5f),
|
||||||
|
chunk->z * CHUNK_D + aabb.max().z + 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!frustum.isBoxVisible(min, max)) return nullptr;
|
if (!frustum.isBoxVisible(min, max)) return nullptr;
|
||||||
}
|
}
|
||||||
return mesh;
|
return mesh;
|
||||||
|
|
@ -224,7 +232,19 @@ void ChunksRenderer::drawShadowsPass(
|
||||||
chunk->top,
|
chunk->top,
|
||||||
chunk->z * CHUNK_D + CHUNK_D
|
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<float>(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<float>(chunk->top), aabb.max().y + 0.5f),
|
||||||
|
chunk->z * CHUNK_D + aabb.max().z + 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!frustum.isBoxVisible(min, max)) {
|
if (!frustum.isBoxVisible(min, max)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -331,15 +351,19 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) {
|
||||||
|
|
||||||
if (culling) {
|
if (culling) {
|
||||||
glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D);
|
glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D);
|
||||||
glm::vec3 max(
|
glm::vec3 max(chunk->x * CHUNK_W + CHUNK_W, chunk->top, chunk->z * CHUNK_D + CHUNK_D);
|
||||||
chunk->x * CHUNK_W + CHUNK_W,
|
const auto& found2 = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
||||||
chunk->top,
|
if (found2 != meshes.end()) {
|
||||||
chunk->z * CHUNK_D + CHUNK_D
|
const auto& aabb = found2->second.localAabb;
|
||||||
);
|
if (aabb.size().x > 0.0f || aabb.size().y > 0.0f || aabb.size().z > 0.0f) {
|
||||||
const float overhang = 4.0f;
|
min = glm::vec3(chunk->x * CHUNK_W + aabb.min().x + 0.5f,
|
||||||
min.x -= overhang; min.z -= overhang;
|
(std::max)(static_cast<float>(chunk->bottom), aabb.min().y + 0.5f),
|
||||||
max.x += overhang; max.z += overhang;
|
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<float>(chunk->top), aabb.max().y + 0.5f),
|
||||||
|
chunk->z * CHUNK_D + aabb.max().z + 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!frustum.isBoxVisible(min, max)) continue;
|
if (!frustum.isBoxVisible(min, max)) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "graphics/core/MeshData.hpp"
|
#include "graphics/core/MeshData.hpp"
|
||||||
#include "util/Buffer.hpp"
|
#include "util/Buffer.hpp"
|
||||||
|
#include "maths/aabb.hpp"
|
||||||
|
|
||||||
/// @brief Chunk mesh vertex format
|
/// @brief Chunk mesh vertex format
|
||||||
struct ChunkVertex {
|
struct ChunkVertex {
|
||||||
|
|
@ -44,10 +45,12 @@ struct SortingMeshData {
|
||||||
struct ChunkMeshData {
|
struct ChunkMeshData {
|
||||||
MeshData<ChunkVertex> mesh;
|
MeshData<ChunkVertex> mesh;
|
||||||
SortingMeshData sortingMesh;
|
SortingMeshData sortingMesh;
|
||||||
|
AABB localAabb; // mesh-space (chunk-local) bounds for precise culling
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ChunkMesh {
|
struct ChunkMesh {
|
||||||
std::unique_ptr<Mesh<ChunkVertex>> mesh;
|
std::unique_ptr<Mesh<ChunkVertex>> mesh;
|
||||||
SortingMeshData sortingMeshData;
|
SortingMeshData sortingMeshData;
|
||||||
std::unique_ptr<Mesh<ChunkVertex> > sortedMesh = nullptr;
|
std::unique_ptr<Mesh<ChunkVertex> > sortedMesh = nullptr;
|
||||||
|
AABB localAabb; // mesh-space (chunk-local) bounds for precise culling
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue