remove unnecessary drawGroup-based loops

This commit is contained in:
MihailRis 2026-07-06 01:05:44 +03:00
parent c73b036099
commit 30ab6c2f5e
4 changed files with 180 additions and 195 deletions

View file

@ -10,15 +10,14 @@
#include "frontend/ContentGfxCache.hpp" #include "frontend/ContentGfxCache.hpp"
const glm::vec3 BlocksRenderer::SUN_VECTOR(0.528265, 0.833149, -0.163704); const glm::vec3 BlocksRenderer::SUN_VECTOR(0.528265, 0.833149, -0.163704);
const float DIRECTIONAL_LIGHT_FACTOR = 0.3f; constexpr float DIRECTIONAL_LIGHT_FACTOR = 0.3f;
BlocksRenderer::BlocksRenderer( BlocksRenderer::BlocksRenderer(
size_t capacity, size_t capacity,
const Content& content, const Block* const* blockDefs,
const ContentGfxCache& cache, const ContentGfxCache& cache,
const EngineSettings& settings const EngineSettings& settings
) : content(content), ) : vertexBuffer(std::make_unique<ChunkVertex[]>(capacity)),
vertexBuffer(std::make_unique<ChunkVertex[]>(capacity)),
indexBuffer(std::make_unique<uint32_t[]>(capacity)), indexBuffer(std::make_unique<uint32_t[]>(capacity)),
denseIndexBuffer(std::make_unique<uint32_t[]>(capacity)), denseIndexBuffer(std::make_unique<uint32_t[]>(capacity)),
vertexCount(0), vertexCount(0),
@ -28,7 +27,7 @@ BlocksRenderer::BlocksRenderer(
cache(cache), cache(cache),
settings(settings) settings(settings)
{ {
blockDefsCache = content.getIndices()->blocks.getDefs(); blockDefsCache = blockDefs;
} }
BlocksRenderer::~BlocksRenderer() = default; BlocksRenderer::~BlocksRenderer() = default;
@ -482,84 +481,78 @@ glm::vec4 BlocksRenderer::pickSoftLight(
} }
void BlocksRenderer::render( void BlocksRenderer::render(
const voxel* voxels, const int beginEnds[256][2] const voxel* voxels, int totalBegin, int totalEnd
) { ) {
bool denseRender = this->denseRender; bool denseRender = this->denseRender;
bool densePass = this->densePass; bool densePass = this->densePass;
bool enableAO = settings.graphics.softLighting.get(); bool enableAO = settings.graphics.softLighting.get();
for (const auto drawGroup : *content.drawGroups) {
int begin = beginEnds[drawGroup][0]; for (int i = totalBegin; i < totalEnd; i++) {
if (begin == 0) { const voxel& vox = voxels[i];
blockid_t id = vox.id;
blockstate state = vox.state;
const auto& def = *blockDefsCache[id];
uint8_t variantId = def.getVariantIndex(state.userbits);
const auto& variant = def.getVariant(variantId);
if (id == 0 || state.segment) {
continue; continue;
} }
int end = beginEnds[drawGroup][1]; if (denseRender != (variant.culling == CullingMode::OPTIONAL)) {
for (int i = begin-1; i <= end; i++) { continue;
const voxel& vox = voxels[i]; }
blockid_t id = vox.id; if (def.translucent) {
blockstate state = vox.state; continue;
const auto& def = *blockDefsCache[id]; }
uint8_t variantId = def.getVariantIndex(state.userbits); const UVRegion texfaces[6] {
const auto& variant = def.getVariant(variantId); cache.getRegion(id, variantId, 0, densePass),
if (id == 0 || variant.drawGroup != drawGroup || state.segment) { cache.getRegion(id, variantId, 1, densePass),
continue; cache.getRegion(id, variantId, 2, densePass),
cache.getRegion(id, variantId, 3, densePass),
cache.getRegion(id, variantId, 4, densePass),
cache.getRegion(id, variantId, 5, densePass)
};
int x = i % CHUNK_W;
int y = i / (CHUNK_D * CHUNK_W);
int z = (i / CHUNK_D) % CHUNK_W;
switch (def.getModel(state.userbits).type) {
case BlockModelType::BLOCK:
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
def.ambientOcclusion && enableAO);
break;
case BlockModelType::XSPRITE: {
if (!denseRender)
blockXSprite(x, y, z, glm::vec3(1.0f),
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
break;
} }
if (denseRender != (variant.culling == CullingMode::OPTIONAL)) { case BlockModelType::AABB: {
continue; if (!denseRender)
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion && enableAO);
break;
} }
if (def.translucent) { case BlockModelType::CUSTOM: {
continue; if (!denseRender)
} blockCustomModel(
const UVRegion texfaces[6] { {x, y, z},
cache.getRegion(id, variantId, 0, densePass), def,
cache.getRegion(id, variantId, 1, densePass), vox.state,
cache.getRegion(id, variantId, 2, densePass), !def.shadeless,
cache.getRegion(id, variantId, 3, densePass), def.ambientOcclusion && enableAO
cache.getRegion(id, variantId, 4, densePass), );
cache.getRegion(id, variantId, 5, densePass) break;
};
int x = i % CHUNK_W;
int y = i / (CHUNK_D * CHUNK_W);
int z = (i / CHUNK_D) % CHUNK_W;
switch (def.getModel(state.userbits).type) {
case BlockModelType::BLOCK:
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
def.ambientOcclusion && enableAO);
break;
case BlockModelType::XSPRITE: {
if (!denseRender)
blockXSprite(x, y, z, glm::vec3(1.0f),
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
break;
}
case BlockModelType::AABB: {
if (!denseRender)
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion && enableAO);
break;
}
case BlockModelType::CUSTOM: {
if (!denseRender)
blockCustomModel(
{x, y, z},
def,
vox.state,
!def.shadeless,
def.ambientOcclusion && enableAO
);
break;
}
default:
break;
}
if (overflow) {
return;
} }
default:
break;
}
if (overflow) {
return;
} }
} }
} }
SortingMeshData BlocksRenderer::renderTranslucent( SortingMeshData BlocksRenderer::renderTranslucent(
const voxel* voxels, int beginEnds[256][2] const voxel* voxels, int totalBegin, int totalEnd
) { ) {
SortingMeshData sortingMesh {{}}; SortingMeshData sortingMesh {{}};
@ -569,106 +562,98 @@ SortingMeshData BlocksRenderer::renderTranslucent(
bool densePass = this->densePass; bool densePass = this->densePass;
bool enableAO = settings.graphics.softLighting.get(); bool enableAO = settings.graphics.softLighting.get();
for (const auto drawGroup : *content.drawGroups) { for (int i = totalBegin; i < totalEnd; i++) {
int begin = beginEnds[drawGroup][0]; const voxel& vox = voxels[i];
if (begin == 0) { blockid_t id = vox.id;
blockstate state = vox.state;
const auto& def = *blockDefsCache[id];
uint8_t variantId = def.getVariantIndex(state.userbits);
if (id == 0 || state.segment) {
continue; continue;
} }
int end = beginEnds[drawGroup][1]; if (!def.translucent) {
for (int i = begin-1; i <= end; i++) { continue;
const voxel& vox = voxels[i];
blockid_t id = vox.id;
blockstate state = vox.state;
const auto& def = *blockDefsCache[id];
uint8_t variantId = def.getVariantIndex(state.userbits);
const auto& variant = def.getVariant(variantId);
if (id == 0 || variant.drawGroup != drawGroup || state.segment) {
continue;
}
if (!def.translucent) {
continue;
}
const UVRegion texfaces[6] {
cache.getRegion(id, variantId, 0, densePass),
cache.getRegion(id, variantId, 1, densePass),
cache.getRegion(id, variantId, 2, densePass),
cache.getRegion(id, variantId, 3, densePass),
cache.getRegion(id, variantId, 4, densePass),
cache.getRegion(id, variantId, 5, densePass)
};
int x = i % CHUNK_W;
int y = i / (CHUNK_D * CHUNK_W);
int z = (i / CHUNK_D) % CHUNK_W;
switch (def.getModel(state.userbits).type) {
case BlockModelType::BLOCK:
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
def.ambientOcclusion && enableAO);
break;
case BlockModelType::XSPRITE: {
blockXSprite(x, y, z, glm::vec3(1.0f),
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
break;
}
case BlockModelType::AABB: {
blockAABB(
{x, y, z},
texfaces,
&def,
vox.state.rotation,
!def.shadeless,
def.ambientOcclusion && enableAO
);
break;
}
case BlockModelType::CUSTOM: {
blockCustomModel(
{x, y, z},
def,
vox.state,
!def.shadeless,
def.ambientOcclusion && enableAO
);
break;
}
default:
break;
}
if (vertexCount == 0) {
continue;
}
SortingMeshEntry entry {
glm::vec3(
x + chunk->x * CHUNK_W + 0.5f,
y + 0.5f,
z + chunk->z * CHUNK_D + 0.5f
),
util::Buffer<ChunkVertex>(indexCount), 0};
totalSize += entry.vertexData.size();
for (int j = 0; j < indexCount; j++) {
std::memcpy(
entry.vertexData.data() + j,
vertexBuffer.get() + indexBuffer[j],
sizeof(ChunkVertex)
);
ChunkVertex& vertex = entry.vertexData[j];
if (!aabbInit) {
aabbInit = true;
aabb.a = aabb.b = vertex.position;
} else {
aabb.addPoint(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;
}
sortingMesh.entries.push_back(std::move(entry));
vertexCount = 0;
vertexOffset = indexCount = 0;
} }
const UVRegion texfaces[6] {
cache.getRegion(id, variantId, 0, densePass),
cache.getRegion(id, variantId, 1, densePass),
cache.getRegion(id, variantId, 2, densePass),
cache.getRegion(id, variantId, 3, densePass),
cache.getRegion(id, variantId, 4, densePass),
cache.getRegion(id, variantId, 5, densePass)
};
int x = i % CHUNK_W;
int y = i / (CHUNK_D * CHUNK_W);
int z = (i / CHUNK_D) % CHUNK_W;
switch (def.getModel(state.userbits).type) {
case BlockModelType::BLOCK:
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
def.ambientOcclusion && enableAO);
break;
case BlockModelType::XSPRITE: {
blockXSprite(x, y, z, glm::vec3(1.0f),
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
break;
}
case BlockModelType::AABB: {
blockAABB(
{x, y, z},
texfaces,
&def,
vox.state.rotation,
!def.shadeless,
def.ambientOcclusion && enableAO
);
break;
}
case BlockModelType::CUSTOM: {
blockCustomModel(
{x, y, z},
def,
vox.state,
!def.shadeless,
def.ambientOcclusion && enableAO
);
break;
}
default:
break;
}
if (vertexCount == 0) {
continue;
}
SortingMeshEntry entry {
glm::vec3(
x + chunk->x * CHUNK_W + 0.5f,
y + 0.5f,
z + chunk->z * CHUNK_D + 0.5f
),
util::Buffer<ChunkVertex>(indexCount), 0};
totalSize += entry.vertexData.size();
for (int j = 0; j < indexCount; j++) {
std::memcpy(
entry.vertexData.data() + j,
vertexBuffer.get() + indexBuffer[j],
sizeof(ChunkVertex)
);
ChunkVertex& vertex = entry.vertexData[j];
if (!aabbInit) {
aabbInit = true;
aabb.a = aabb.b = vertex.position;
} else {
aabb.addPoint(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;
}
sortingMesh.entries.push_back(std::move(entry));
vertexCount = 0;
vertexOffset = indexCount = 0;
} }
// additional powerful optimization // additional powerful optimization
@ -710,19 +695,16 @@ void BlocksRenderer::build(
int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D); int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D);
int totalEnd = chunk->top * (CHUNK_W * CHUNK_D); int totalEnd = chunk->top * (CHUNK_W * CHUNK_D);
bool hasTranslucent = false; bool hasTranslucent = false;
int beginEnds[256][2] {};
for (int i = totalBegin; i < totalEnd; i++) { for (int i = totalBegin; i < totalEnd; i++) {
const voxel& vox = voxels[i]; const voxel& vox = voxels[i];
blockid_t id = vox.id; blockid_t id = vox.id;
const auto& def = *blockDefsCache[id]; const auto& def = *blockDefsCache[id];
const auto& variant = def.getVariantByBits(vox.state.userbits); if (def.translucent) {
hasTranslucent = def.translucent || hasTranslucent; hasTranslucent = true;
break;
if (beginEnds[variant.drawGroup][0] == 0) {
beginEnds[variant.drawGroup][0] = i + 1;
} }
beginEnds[variant.drawGroup][1] = i;
} }
cancelled = false; cancelled = false;
@ -734,7 +716,7 @@ void BlocksRenderer::build(
densePass = false; densePass = false;
if (hasTranslucent) { if (hasTranslucent) {
sortingMesh = renderTranslucent(voxels, beginEnds); sortingMesh = renderTranslucent(voxels, totalBegin, totalEnd);
} else { } else {
sortingMesh = {}; sortingMesh = {};
} }
@ -747,13 +729,13 @@ void BlocksRenderer::build(
denseRender = false; denseRender = false;
densePass = false; densePass = false;
render(voxels, beginEnds); render(voxels, totalBegin, totalEnd);
size_t endIndex = indexCount; size_t endIndex = indexCount;
denseRender = true; denseRender = true;
densePass = settings.graphics.denseRender.get(); densePass = settings.graphics.denseRender.get();
render(voxels, beginEnds); render(voxels, totalBegin, totalEnd);
denseIndexCount = indexCount; denseIndexCount = indexCount;
for (size_t i = 0; i < denseIndexCount; i++) { for (size_t i = 0; i < denseIndexCount; i++) {
@ -762,7 +744,7 @@ void BlocksRenderer::build(
indexCount = endIndex; indexCount = endIndex;
densePass = false; densePass = false;
render(voxels, beginEnds); render(voxels, totalBegin, totalEnd);
} }
ChunkMeshData BlocksRenderer::createMesh() { ChunkMeshData BlocksRenderer::createMesh() {

View file

@ -25,7 +25,7 @@ class BlocksRenderer final {
public: public:
BlocksRenderer( BlocksRenderer(
size_t capacity, size_t capacity,
const Content& content, const Block* const* blockDefs,
const ContentGfxCache& cache, const ContentGfxCache& cache,
const EngineSettings& settings const EngineSettings& settings
); );
@ -44,7 +44,6 @@ public:
} }
private: private:
static const glm::vec3 SUN_VECTOR; static const glm::vec3 SUN_VECTOR;
const Content& content;
std::unique_ptr<ChunkVertex[]> vertexBuffer; std::unique_ptr<ChunkVertex[]> vertexBuffer;
std::unique_ptr<uint32_t[]> indexBuffer; std::unique_ptr<uint32_t[]> indexBuffer;
std::unique_ptr<uint32_t[]> denseIndexBuffer; std::unique_ptr<uint32_t[]> denseIndexBuffer;
@ -145,13 +144,16 @@ private:
); );
// Does block allow to see other blocks sides (is it transparent) // Does block allow to see other blocks sides (is it transparent)
inline bool isOpen(const glm::ivec3& pos, const Block& def, const Variant& variant) const { bool isOpen(const glm::ivec3& pos, const Block& def, const Variant& variant) const {
const auto& vox = voxelsBuffer->pickBlock( const auto& vox = voxelsBuffer->pickBlock(
chunk->x * CHUNK_W + pos.x, pos.y, chunk->z * CHUNK_D + pos.z chunk->x * CHUNK_W + pos.x, pos.y, chunk->z * CHUNK_D + pos.z
); );
if (vox.id == BLOCK_VOID) { if (vox.id == BLOCK_VOID) {
return false; return false;
} }
if (def.rt.id == vox.id && def.rt.solid && variant.culling == CullingMode::DEFAULT) {
return false;
}
const auto& block = *blockDefsCache[vox.id]; const auto& block = *blockDefsCache[vox.id];
const auto& blockVariant = block.getVariantByBits(vox.state.userbits); const auto& blockVariant = block.getVariantByBits(vox.state.userbits);
uint8_t otherDrawGroup = blockVariant.drawGroup; uint8_t otherDrawGroup = blockVariant.drawGroup;
@ -178,6 +180,6 @@ private:
float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up
) const; ) const;
void render(const voxel* voxels, const int beginEnds[256][2]); void render(const voxel* voxels, int totalBegin, int totalEnd);
SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]); SortingMeshData renderTranslucent(const voxel* voxels, int totalBegin, int totalEnd);
}; };

View file

@ -14,6 +14,7 @@
#include "util/listutil.hpp" #include "util/listutil.hpp"
#include "util/ObjectsPool.hpp" #include "util/ObjectsPool.hpp"
#include "settings.hpp" #include "settings.hpp"
#include "content/Content.hpp"
static debug::Logger logger("chunks-render"); static debug::Logger logger("chunks-render");
@ -33,7 +34,7 @@ public:
settings.graphics.denseRender.get() settings.graphics.denseRender.get()
? settings.graphics.chunkMaxVerticesDense.get() ? settings.graphics.chunkMaxVerticesDense.get()
: settings.graphics.chunkMaxVertices.get(), : settings.graphics.chunkMaxVertices.get(),
level.content, level.content.getIndices()->blocks.getDefs(),
cache, cache,
settings settings
) { ) {
@ -92,7 +93,7 @@ ChunksRenderer::ChunksRenderer(
threadPool.setStopOnFail(false); threadPool.setStopOnFail(false);
renderer = std::make_unique<BlocksRenderer>( renderer = std::make_unique<BlocksRenderer>(
settings.graphics.chunkMaxVertices.get(), settings.graphics.chunkMaxVertices.get(),
level.content, cache, settings level.content.getIndices()->blocks.getDefs(), cache, settings
); );
logger.info() << "created " << threadPool.getWorkersCount() << " workers"; logger.info() << "created " << threadPool.getWorkersCount() << " workers";
logger.info() << "memory consumption is " logger.info() << "memory consumption is "
@ -126,7 +127,7 @@ const ChunkMesh* ChunksRenderer::render(
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
) { ) {
glm::ivec2 key(chunk->x, chunk->z); glm::ivec2 key(chunk->x, chunk->z);
if (important) { if (important || true) {
ChunkMesh mesh {}; ChunkMesh mesh {};
auto voxelsBuffer = prepareVoxelsVolume(*chunk); auto voxelsBuffer = prepareVoxelsVolume(*chunk);
mesh = renderer->render(chunk.get(), *voxelsBuffer); mesh = renderer->render(chunk.get(), *voxelsBuffer);

View file

@ -66,7 +66,7 @@ public:
return lights.get(); return lights.get();
} }
inline blockid_t pickBlockId(int bx, int by, int bz) const { blockid_t pickBlockId(int bx, int by, int bz) const {
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h || if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h ||
bz >= z + d) { bz >= z + d) {
return BLOCK_VOID; return BLOCK_VOID;
@ -75,7 +75,7 @@ public:
} }
inline voxel pickBlock(int bx, int by, int bz) const { voxel pickBlock(int bx, int by, int bz) const {
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h || if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h ||
bz >= z + d) { bz >= z + d) {
return {BLOCK_VOID, {}}; return {BLOCK_VOID, {}};
@ -83,7 +83,7 @@ public:
return voxels[vox_index(bx - x, by - y, bz - z, w, d)]; return voxels[vox_index(bx - x, by - y, bz - z, w, d)];
} }
inline light_t pickLight(int bx, int by, int bz) const { light_t pickLight(int bx, int by, int bz) const {
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h || if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h ||
bz >= z + d) { bz >= z + d) {
return 0; return 0;
@ -103,10 +103,10 @@ private:
template <int w, int h, int d> template <int w, int h, int d>
class StaticVoxelsVolume { class StaticVoxelsVolume {
public: public:
static inline constexpr size_t size = w * h * d; static constexpr size_t size = w * h * d;
static inline constexpr int width = w; static constexpr int width = w;
static inline constexpr int height = h; static constexpr int height = h;
static inline constexpr int depth = d; static constexpr int depth = d;
StaticVoxelsVolume() StaticVoxelsVolume()
: StaticVoxelsVolume(0, 0, 0) {} : StaticVoxelsVolume(0, 0, 0) {}
@ -142,7 +142,7 @@ public:
return lights; return lights;
} }
inline blockid_t pickBlockId(uint bx, uint by, uint bz) const { blockid_t pickBlockId(uint bx, uint by, uint bz) const {
bx -= x; bx -= x;
by -= y; by -= y;
bz -= z; bz -= z;
@ -153,7 +153,7 @@ public:
} }
inline const voxel& pickBlock(uint bx, uint by, uint bz) const { const voxel& pickBlock(uint bx, uint by, uint bz) const {
bx -= x; bx -= x;
by -= y; by -= y;
bz -= z; bz -= z;
@ -164,7 +164,7 @@ public:
return voxels[vox_index(bx, by, bz, w, d)]; return voxels[vox_index(bx, by, bz, w, d)];
} }
inline light_t pickLight(uint bx, uint by, uint bz) const { light_t pickLight(uint bx, uint by, uint bz) const {
bx -= x; bx -= x;
by -= y; by -= y;
bz -= z; bz -= z;