refactor: meshes build queue instead of retrieveChunk

This commit is contained in:
MihailRis 2026-08-02 22:35:03 +03:00
parent 4ae3dcf1ae
commit 2a2169cff0
3 changed files with 112 additions and 93 deletions

View file

@ -11,8 +11,10 @@
#include "world/Level.hpp" #include "world/Level.hpp"
#include "window/Camera.hpp" #include "window/Camera.hpp"
#include "maths/FrustumCulling.hpp" #include "maths/FrustumCulling.hpp"
#include "maths/util.hpp"
#include "util/listutil.hpp" #include "util/listutil.hpp"
#include "util/ObjectsPool.hpp" #include "util/ObjectsPool.hpp"
#include "util/timeutil.hpp"
#include "settings.hpp" #include "settings.hpp"
#include "content/Content.hpp" #include "content/Content.hpp"
@ -162,76 +164,63 @@ void ChunksRenderer::clear() {
threadPool.clearQueue(); threadPool.clearQueue();
} }
const ChunkMesh* ChunksRenderer::getOrRender(
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
) {
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
if (found == meshes.end()) {
return render(chunk, important, lowPriority);
}
if (chunk->flags.modified && chunk->flags.lighted) {
render(chunk, important, lowPriority);
}
return &found->second;
}
void ChunksRenderer::update() { void ChunksRenderer::update() {
threadPool.pullResults(); threadPool.pullResults();
enqueuedInFrame = 0; enqueuedInFrame = 0;
}
const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk( int width = chunks.getWidth();
size_t index, const Camera& camera, bool culling int halfWidth = width / 2;
) { int halfHeight = chunks.getHeight() / 2;
auto chunk = chunks.getChunks()[index]; int centerX = chunks.getOffsetX() + halfWidth;
if (chunk == nullptr) { int centerY = chunks.getOffsetY() + halfHeight;
return nullptr;
} meshBuildQueue.clear();
if (!chunk->flags.lighted) { auto& chunksArray = chunks.getChunks();
const auto& found = meshes.find({chunk->x, chunk->z}); for (int index = 0; index < chunks.getVolume(); index++) {
if (found == meshes.end()) { const auto& chunk = chunks.getChunks()[index];
return nullptr; if (chunk == nullptr || !chunk->flags.lighted) {
} else { continue;
return found->second.mesh.get(); }
int x = chunk->x;
int z = chunk->z;
if (chunk->flags.modified || meshes.find({x, z}) == meshes.end()) {
meshBuildQueue.emplace_back(x - centerX, z - centerY);
} }
} }
float distance = glm::distance( std::sort(
camera.position, meshBuildQueue.begin(),
glm::vec3( meshBuildQueue.end(),
(chunk->x + 0.5f) * CHUNK_W, [](const glm::ivec2& a, const glm::ivec2& b) {
camera.position.y, return util::length2(a) < util::length2(b);
(chunk->z + 0.5f) * CHUNK_D }
)
); );
auto mesh = getOrRender(
chunk,
distance < CHUNK_W * 1.5f,
distance > CHUNK_W * settings.chunks.loadDistance.get() * 0.5
);
if (mesh == nullptr) {
return nullptr;
}
if (chunk->flags.dirtyHeights) {
chunk->updateHeights();
}
if (culling) {
const auto& meshAABB = mesh->meshAABB;
auto aabbMin = meshAABB.min();
auto aabbMax = meshAABB.max();
glm::vec3 min(
chunk->x * CHUNK_W + std::min(0.0f, aabbMin.x),
chunk->bottom,
chunk->z * CHUNK_D + std::min(0.0f, aabbMin.z)
);
glm::vec3 max(
chunk->x * CHUNK_W + aabbMax.x,
chunk->top,
chunk->z * CHUNK_D + aabbMax.z
);
if (!frustum.isBoxVisible(min, max)) return nullptr; const int topN = 10;
int top = std::min<int>(meshBuildQueue.size(), topN);
for (int i = 0; i < top; i++) {
glm::ivec2 offset = meshBuildQueue[i];
size_t index =
(offset.y + halfHeight) * width + offset.x + halfWidth;
auto& chunk = chunksArray[index];
assert(chunk != nullptr);
float distance = glm::distance(
glm::vec3 (centerX, 0.0f, centerY),
glm::vec3(
(chunk->x + 0.5f) * CHUNK_W,
0,
(chunk->z + 0.5f) * CHUNK_D
)
);
bool important = distance < CHUNK_W * 1.5f;
bool lowPriority = distance > CHUNK_W * settings.chunks.loadDistance.get() * 0.5;
if (chunk->flags.dirtyHeights) {
chunk->updateHeights();
}
render(chunk, important, lowPriority);
} }
return mesh->mesh.get();
} }
void ChunksRenderer::drawShadowsPass( void ChunksRenderer::drawShadowsPass(
@ -318,16 +307,43 @@ void ChunksRenderer::drawChunks(
// TODO: minimize draw calls number // TODO: minimize draw calls number
for (int i = indices.size()-1; i >= 0; i--) { for (int i = indices.size()-1; i >= 0; i--) {
auto& chunk = chunks.getChunks()[indices[i].index]; auto& chunk = chunks.getChunks()[indices[i].index];
auto mesh = retrieveChunk(indices[i].index, camera, culling); if (chunk == nullptr) {
if (mesh == nullptr) {
continue; continue;
} }
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
if (found == meshes.end()) {
continue;
}
auto& mesh = found->second;
if (mesh.mesh == nullptr) {
continue;
}
if (culling) {
const auto& meshAABB = mesh.meshAABB;
auto aabbMin = meshAABB.min();
auto aabbMax = meshAABB.max();
glm::vec3 min(
chunk->x * CHUNK_W + std::min(0.0f, aabbMin.x),
chunk->bottom,
chunk->z * CHUNK_D + std::min(0.0f, aabbMin.z)
);
glm::vec3 max(
chunk->x * CHUNK_W + aabbMax.x,
chunk->top,
chunk->z * CHUNK_D + aabbMax.z
);
if (!frustum.isBoxVisible(min, max)) {
continue;
}
}
glm::vec3 coord( glm::vec3 coord(
chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f
); );
glm::mat4 model = glm::translate(glm::mat4(1.0f), coord); glm::mat4 model = glm::translate(glm::mat4(1.0f), coord);
shader.uniformMatrix("u_model", model); shader.uniformMatrix("u_model", model);
mesh->draw(GL_TRIANGLES, glm::distance2(camera.position * glm::vec3(1, 0, 1), mesh.mesh->draw(GL_TRIANGLES, glm::distance2(camera.position * glm::vec3(1, 0, 1),
(coord + glm::vec3(CHUNK_W * 0.5f, 0.0f, CHUNK_D * 0.5f))) < denseDistance2); (coord + glm::vec3(CHUNK_W * 0.5f, 0.0f, CHUNK_D * 0.5f))) < denseDistance2);
visibleChunks++; visibleChunks++;
} }

View file

@ -1,16 +1,17 @@
#pragma once #pragma once
#define GLM_ENABLE_EXPERIMENTAL
#include "util/ThreadPool.hpp"
#include "commons.hpp"
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp> #include <glm/gtx/hash.hpp>
#include "util/ThreadPool.hpp"
#include "commons.hpp"
template<typename VertexStructure> class Mesh; template<typename VertexStructure> class Mesh;
class Chunk; class Chunk;
class Level; class Level;
@ -44,22 +45,6 @@ struct RendererJob {
}; };
class ChunksRenderer { class ChunksRenderer {
const Chunks& chunks;
const Assets& assets;
const Frustum& frustum;
const EngineSettings& settings;
std::unique_ptr<BlocksRenderer> renderer;
std::unordered_map<glm::ivec2, ChunkMesh> meshes;
std::unordered_map<glm::ivec2, bool> inwork;
std::vector<ChunksSortEntry> indices;
util::ThreadPool<RendererJob, RendererResult> threadPool;
const Mesh<ChunkVertex>* retrieveChunk(
size_t index, const Camera& camera, bool culling
);
std::shared_ptr<VoxelsRenderVolume> prepareVoxelsVolume(const Chunk& chunk);
size_t enqueuedInFrame = 0;
public: public:
ChunksRenderer( ChunksRenderer(
const Level& level, const Level& level,
@ -71,16 +56,9 @@ public:
); );
virtual ~ChunksRenderer(); virtual ~ChunksRenderer();
const ChunkMesh* render(
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
);
void unload(const Chunk* chunk); void unload(const Chunk* chunk);
void clear(); void clear();
const ChunkMesh* getOrRender(
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
);
void drawShadowsPass( void drawShadowsPass(
const Camera& camera, Shader& shader, const Camera& playerCamera const Camera& camera, Shader& shader, const Camera& playerCamera
); );
@ -92,4 +70,25 @@ public:
void update(); void update();
static size_t visibleChunks; static size_t visibleChunks;
private:
const Chunks& chunks;
const Assets& assets;
const Frustum& frustum;
const EngineSettings& settings;
std::unique_ptr<BlocksRenderer> renderer;
std::unordered_map<glm::ivec2, ChunkMesh> meshes;
std::unordered_map<glm::ivec2, bool> inwork;
std::vector<ChunksSortEntry> indices;
util::ThreadPool<RendererJob, RendererResult> threadPool;
std::vector<glm::ivec2> meshBuildQueue;
size_t enqueuedInFrame = 0;
std::shared_ptr<VoxelsRenderVolume> prepareVoxelsVolume(const Chunk& chunk);
const ChunkMesh* render(
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
);
}; };

View file

@ -109,12 +109,16 @@ namespace util {
/// @return integer square of vector length /// @return integer square of vector length
/// @note glm::length2 does not support integer vectors /// @note glm::length2 does not support integer vectors
inline int length2(const glm::ivec3& a) { inline long long int length2(const glm::ivec2& a) {
return a.x * a.x + a.y * a.y;
}
inline long long int length2(const glm::ivec3& a) {
return a.x * a.x + a.y * a.y + a.z * a.z; return a.x * a.x + a.y * a.y + a.z * a.z;
} }
/// @return integer square of vector length /// @return integer square of vector length
inline int length2(int x, int y, int z) { inline long long int length2(int x, int y, int z) {
return x * x + y * y + z * z; return x * x + y * y + z * z;
} }