feat: distance-based dense render optimization
This commit is contained in:
parent
799d712447
commit
fbde46afa7
@ -126,11 +126,9 @@ void Mesh<VertexStructure>::draw(unsigned int primitive, int iboIndex) const {
|
|||||||
if (!ibos.empty()) {
|
if (!ibos.empty()) {
|
||||||
if (iboIndex < ibos.size()) {
|
if (iboIndex < ibos.size()) {
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[iboIndex].ibo);
|
||||||
std::min(static_cast<size_t>(iboIndex), ibos.size())
|
|
||||||
].ibo);
|
|
||||||
glDrawElements(
|
glDrawElements(
|
||||||
primitive, ibos.at(0).indexCount, GL_UNSIGNED_INT, nullptr
|
primitive, ibos.at(iboIndex).indexCount, GL_UNSIGNED_INT, nullptr
|
||||||
);
|
);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ BlocksRenderer::BlocksRenderer(
|
|||||||
) : content(content),
|
) : 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)),
|
||||||
vertexCount(0),
|
vertexCount(0),
|
||||||
vertexOffset(0),
|
vertexOffset(0),
|
||||||
indexCount(0),
|
indexCount(0),
|
||||||
@ -475,9 +476,10 @@ glm::vec4 BlocksRenderer::pickSoftLight(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BlocksRenderer::render(
|
void BlocksRenderer::render(
|
||||||
const voxel* voxels, int beginEnds[256][2]
|
const voxel* voxels, const int beginEnds[256][2]
|
||||||
) {
|
) {
|
||||||
bool denseRender = this->denseRender;
|
bool denseRender = this->denseRender;
|
||||||
|
bool densePass = this->densePass;
|
||||||
for (const auto drawGroup : *content.drawGroups) {
|
for (const auto drawGroup : *content.drawGroups) {
|
||||||
int begin = beginEnds[drawGroup][0];
|
int begin = beginEnds[drawGroup][0];
|
||||||
if (begin == 0) {
|
if (begin == 0) {
|
||||||
@ -494,16 +496,19 @@ void BlocksRenderer::render(
|
|||||||
if (id == 0 || variant.drawGroup != drawGroup || state.segment) {
|
if (id == 0 || variant.drawGroup != drawGroup || state.segment) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (denseRender != (variant.culling == CullingMode::OPTIONAL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (def.translucent) {
|
if (def.translucent) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const UVRegion texfaces[6] {
|
const UVRegion texfaces[6] {
|
||||||
cache.getRegion(id, variantId, 0, denseRender),
|
cache.getRegion(id, variantId, 0, densePass),
|
||||||
cache.getRegion(id, variantId, 1, denseRender),
|
cache.getRegion(id, variantId, 1, densePass),
|
||||||
cache.getRegion(id, variantId, 2, denseRender),
|
cache.getRegion(id, variantId, 2, densePass),
|
||||||
cache.getRegion(id, variantId, 3, denseRender),
|
cache.getRegion(id, variantId, 3, densePass),
|
||||||
cache.getRegion(id, variantId, 4, denseRender),
|
cache.getRegion(id, variantId, 4, densePass),
|
||||||
cache.getRegion(id, variantId, 5, denseRender)
|
cache.getRegion(id, variantId, 5, densePass)
|
||||||
};
|
};
|
||||||
int x = i % CHUNK_W;
|
int x = i % CHUNK_W;
|
||||||
int y = i / (CHUNK_D * CHUNK_W);
|
int y = i / (CHUNK_D * CHUNK_W);
|
||||||
@ -514,16 +519,19 @@ void BlocksRenderer::render(
|
|||||||
def.ambientOcclusion);
|
def.ambientOcclusion);
|
||||||
break;
|
break;
|
||||||
case BlockModelType::XSPRITE: {
|
case BlockModelType::XSPRITE: {
|
||||||
|
if (!denseRender)
|
||||||
blockXSprite(x, y, z, glm::vec3(1.0f),
|
blockXSprite(x, y, z, glm::vec3(1.0f),
|
||||||
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
|
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BlockModelType::AABB: {
|
case BlockModelType::AABB: {
|
||||||
|
if (!denseRender)
|
||||||
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
|
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
|
||||||
!def.shadeless, def.ambientOcclusion);
|
!def.shadeless, def.ambientOcclusion);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BlockModelType::CUSTOM: {
|
case BlockModelType::CUSTOM: {
|
||||||
|
if (!denseRender)
|
||||||
blockCustomModel(
|
blockCustomModel(
|
||||||
{x, y, z},
|
{x, y, z},
|
||||||
def,
|
def,
|
||||||
@ -552,7 +560,7 @@ SortingMeshData BlocksRenderer::renderTranslucent(
|
|||||||
bool aabbInit = false;
|
bool aabbInit = false;
|
||||||
size_t totalSize = 0;
|
size_t totalSize = 0;
|
||||||
|
|
||||||
bool denseRender = this->denseRender;
|
bool densePass = this->densePass;
|
||||||
for (const auto drawGroup : *content.drawGroups) {
|
for (const auto drawGroup : *content.drawGroups) {
|
||||||
int begin = beginEnds[drawGroup][0];
|
int begin = beginEnds[drawGroup][0];
|
||||||
if (begin == 0) {
|
if (begin == 0) {
|
||||||
@ -573,12 +581,12 @@ SortingMeshData BlocksRenderer::renderTranslucent(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const UVRegion texfaces[6] {
|
const UVRegion texfaces[6] {
|
||||||
cache.getRegion(id, variantId, 0, denseRender),
|
cache.getRegion(id, variantId, 0, densePass),
|
||||||
cache.getRegion(id, variantId, 1, denseRender),
|
cache.getRegion(id, variantId, 1, densePass),
|
||||||
cache.getRegion(id, variantId, 2, denseRender),
|
cache.getRegion(id, variantId, 2, densePass),
|
||||||
cache.getRegion(id, variantId, 3, denseRender),
|
cache.getRegion(id, variantId, 3, densePass),
|
||||||
cache.getRegion(id, variantId, 4, denseRender),
|
cache.getRegion(id, variantId, 4, densePass),
|
||||||
cache.getRegion(id, variantId, 5, denseRender)
|
cache.getRegion(id, variantId, 5, densePass)
|
||||||
};
|
};
|
||||||
int x = i % CHUNK_W;
|
int x = i % CHUNK_W;
|
||||||
int y = i / (CHUNK_D * CHUNK_W);
|
int y = i / (CHUNK_D * CHUNK_W);
|
||||||
@ -703,29 +711,45 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
|
|||||||
vertexCount = 0;
|
vertexCount = 0;
|
||||||
vertexOffset = indexCount = 0;
|
vertexOffset = indexCount = 0;
|
||||||
|
|
||||||
|
denseRender = false;
|
||||||
|
densePass = false;
|
||||||
|
|
||||||
sortingMesh = renderTranslucent(voxels, beginEnds);
|
sortingMesh = renderTranslucent(voxels, beginEnds);
|
||||||
|
|
||||||
overflow = false;
|
overflow = false;
|
||||||
vertexCount = 0;
|
vertexCount = 0;
|
||||||
vertexOffset = 0;
|
vertexOffset = 0;
|
||||||
indexCount = 0;
|
indexCount = 0;
|
||||||
|
denseIndexCount = 0;
|
||||||
|
|
||||||
denseRender = settings.graphics.denseRender.get();
|
denseRender = false; //settings.graphics.denseRender.get();
|
||||||
// denseRender = false;
|
densePass = false;
|
||||||
|
|
||||||
render(voxels, beginEnds);
|
render(voxels, beginEnds);
|
||||||
|
|
||||||
// denseRender = settings.graphics.denseRender.get();
|
size_t endIndex = indexCount;
|
||||||
// if (denseRender) {
|
|
||||||
|
|
||||||
// }
|
denseRender = true;
|
||||||
|
densePass = true;
|
||||||
|
render(voxels, beginEnds);
|
||||||
|
|
||||||
|
denseIndexCount = indexCount;
|
||||||
|
for (size_t i = 0; i < denseIndexCount; i++) {
|
||||||
|
denseIndexBuffer[i] = indexBuffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
indexCount = endIndex;
|
||||||
|
densePass = false;
|
||||||
|
render(voxels, beginEnds);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkMeshData BlocksRenderer::createMesh() {
|
ChunkMeshData BlocksRenderer::createMesh() {
|
||||||
return ChunkMeshData{
|
return ChunkMeshData {
|
||||||
MeshData(
|
MeshData(
|
||||||
util::Buffer(vertexBuffer.get(), vertexCount),
|
util::Buffer(vertexBuffer.get(), vertexCount),
|
||||||
std::vector<util::Buffer<uint32_t>> {util::Buffer(indexBuffer.get(), indexCount)},
|
std::vector<util::Buffer<uint32_t>> {
|
||||||
|
util::Buffer(indexBuffer.get(), indexCount),
|
||||||
|
util::Buffer(denseIndexBuffer.get(), denseIndexCount),
|
||||||
|
},
|
||||||
util::Buffer(
|
util::Buffer(
|
||||||
ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute)
|
ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute)
|
||||||
)
|
)
|
||||||
@ -739,10 +763,18 @@ ChunkMesh BlocksRenderer::render(const Chunk *chunk, const Chunks *chunks) {
|
|||||||
|
|
||||||
return ChunkMesh{std::make_unique<Mesh<ChunkVertex>>(
|
return ChunkMesh{std::make_unique<Mesh<ChunkVertex>>(
|
||||||
vertexBuffer.get(), vertexCount,
|
vertexBuffer.get(), vertexCount,
|
||||||
std::vector<IndexBufferData> {IndexBufferData {indexBuffer.get(), indexCount}}
|
std::vector<IndexBufferData> {
|
||||||
|
IndexBufferData {indexBuffer.get(), indexCount},
|
||||||
|
IndexBufferData {denseIndexBuffer.get(), denseIndexCount},
|
||||||
|
}
|
||||||
), std::move(sortingMesh)};
|
), std::move(sortingMesh)};
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const {
|
VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const {
|
||||||
return voxelsBuffer.get();
|
return voxelsBuffer.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t BlocksRenderer::getMemoryConsumption() const {
|
||||||
|
size_t volume = voxelsBuffer->getW() * voxelsBuffer->getH() * voxelsBuffer->getD();
|
||||||
|
return capacity * (sizeof(ChunkVertex) + sizeof(uint32_t) * 2) + volume * (sizeof(voxel) + sizeof(light_t));
|
||||||
|
}
|
||||||
|
|||||||
@ -26,13 +26,16 @@ class BlocksRenderer {
|
|||||||
const Content& content;
|
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;
|
||||||
size_t vertexCount;
|
size_t vertexCount;
|
||||||
size_t vertexOffset;
|
size_t vertexOffset;
|
||||||
size_t indexCount;
|
size_t indexCount;
|
||||||
|
size_t denseIndexCount;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
int voxelBufferPadding = 2;
|
int voxelBufferPadding = 2;
|
||||||
bool overflow = false;
|
bool overflow = false;
|
||||||
bool cancelled = false;
|
bool cancelled = false;
|
||||||
|
bool densePass = false;
|
||||||
bool denseRender = false;
|
bool denseRender = false;
|
||||||
const Chunk* chunk = nullptr;
|
const Chunk* chunk = nullptr;
|
||||||
std::unique_ptr<VoxelsVolume> voxelsBuffer;
|
std::unique_ptr<VoxelsVolume> voxelsBuffer;
|
||||||
@ -136,10 +139,12 @@ class BlocksRenderer {
|
|||||||
if ((otherDrawGroup && (otherDrawGroup != variant.drawGroup)) || !blockVariant.rt.solid) {
|
if ((otherDrawGroup && (otherDrawGroup != variant.drawGroup)) || !blockVariant.rt.solid) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((variant.culling == CullingMode::DISABLED ||
|
if (densePass) {
|
||||||
(variant.culling == CullingMode::OPTIONAL &&
|
return variant.culling == CullingMode::OPTIONAL;
|
||||||
denseRender)) &&
|
} else if (variant.culling == CullingMode::OPTIONAL) {
|
||||||
vox.id == def.rt.id) {
|
return false;
|
||||||
|
}
|
||||||
|
if (variant.culling == CullingMode::DISABLED && vox.id == def.rt.id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return !vox.id;
|
return !vox.id;
|
||||||
@ -150,7 +155,7 @@ class BlocksRenderer {
|
|||||||
glm::vec4 pickSoftLight(const glm::ivec3& coord, const glm::ivec3& right, const glm::ivec3& up) const;
|
glm::vec4 pickSoftLight(const glm::ivec3& coord, const glm::ivec3& right, const glm::ivec3& up) const;
|
||||||
glm::vec4 pickSoftLight(float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up) const;
|
glm::vec4 pickSoftLight(float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up) const;
|
||||||
|
|
||||||
void render(const voxel* voxels, int beginEnds[256][2]);
|
void render(const voxel* voxels, const int beginEnds[256][2]);
|
||||||
SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]);
|
SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]);
|
||||||
public:
|
public:
|
||||||
BlocksRenderer(
|
BlocksRenderer(
|
||||||
@ -166,6 +171,8 @@ public:
|
|||||||
ChunkMeshData createMesh();
|
ChunkMeshData createMesh();
|
||||||
VoxelsVolume* getVoxelsBuffer() const;
|
VoxelsVolume* getVoxelsBuffer() const;
|
||||||
|
|
||||||
|
size_t getMemoryConsumption() const;
|
||||||
|
|
||||||
bool isCancelled() const {
|
bool isCancelled() const {
|
||||||
return cancelled;
|
return cancelled;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,9 @@ static debug::Logger logger("chunks-render");
|
|||||||
|
|
||||||
size_t ChunksRenderer::visibleChunks = 0;
|
size_t ChunksRenderer::visibleChunks = 0;
|
||||||
|
|
||||||
|
inline constexpr int DENSE_DISTANCE = 64;
|
||||||
|
inline constexpr int DENSE_DISTANCE2 = DENSE_DISTANCE * DENSE_DISTANCE;
|
||||||
|
|
||||||
class RendererWorker : public util::Worker<std::shared_ptr<Chunk>, RendererResult> {
|
class RendererWorker : public util::Worker<std::shared_ptr<Chunk>, RendererResult> {
|
||||||
const Chunks& chunks;
|
const Chunks& chunks;
|
||||||
BlocksRenderer renderer;
|
BlocksRenderer renderer;
|
||||||
@ -87,6 +90,9 @@ ChunksRenderer::ChunksRenderer(
|
|||||||
level->content, cache, settings
|
level->content, cache, settings
|
||||||
);
|
);
|
||||||
logger.info() << "created " << threadPool.getWorkersCount() << " workers";
|
logger.info() << "created " << threadPool.getWorkersCount() << " workers";
|
||||||
|
logger.info() << "memory consumption is "
|
||||||
|
<< renderer->getMemoryConsumption() * threadPool.getWorkersCount()
|
||||||
|
<< " B";
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunksRenderer::~ChunksRenderer() = default;
|
ChunksRenderer::~ChunksRenderer() = default;
|
||||||
@ -182,7 +188,7 @@ const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ChunksRenderer::drawChunksShadowsPass(
|
void ChunksRenderer::drawChunksShadowsPass(
|
||||||
const Camera& camera, Shader& shader
|
const Camera& camera, Shader& shader, const Camera& playerCamera
|
||||||
) {
|
) {
|
||||||
Frustum frustum;
|
Frustum frustum;
|
||||||
frustum.update(camera.getProjView());
|
frustum.update(camera.getProjView());
|
||||||
@ -205,7 +211,7 @@ void ChunksRenderer::drawChunksShadowsPass(
|
|||||||
pos.x * CHUNK_W + 0.5f, 0.5f, pos.y * CHUNK_D + 0.5f
|
pos.x * CHUNK_W + 0.5f, 0.5f, pos.y * CHUNK_D + 0.5f
|
||||||
);
|
);
|
||||||
|
|
||||||
glm::vec3 min(pos.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->x * CHUNK_W + CHUNK_W,
|
||||||
chunk->top,
|
chunk->top,
|
||||||
@ -217,7 +223,9 @@ void ChunksRenderer::drawChunksShadowsPass(
|
|||||||
}
|
}
|
||||||
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);
|
||||||
found->second.mesh->draw();
|
found->second.mesh->draw(GL_TRIANGLES,
|
||||||
|
glm::distance2(playerCamera.position * glm::vec3(1, 0, 1),
|
||||||
|
(min + max) * 0.5f * glm::vec3(1, 0, 1)) < DENSE_DISTANCE2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +273,8 @@ void ChunksRenderer::drawChunks(
|
|||||||
);
|
);
|
||||||
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();
|
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))) < DENSE_DISTANCE2);
|
||||||
visibleChunks++;
|
visibleChunks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,9 @@ public:
|
|||||||
const std::shared_ptr<Chunk>& chunk, bool important
|
const std::shared_ptr<Chunk>& chunk, bool important
|
||||||
);
|
);
|
||||||
|
|
||||||
void drawChunksShadowsPass(const Camera& camera, Shader& shader);
|
void drawChunksShadowsPass(
|
||||||
|
const Camera& camera, Shader& shader, const Camera& playerCamera
|
||||||
|
);
|
||||||
|
|
||||||
void drawChunks(const Camera& camera, Shader& shader);
|
void drawChunks(const Camera& camera, Shader& shader);
|
||||||
|
|
||||||
|
|||||||
@ -406,7 +406,7 @@ void WorldRenderer::generateShadowsMap(
|
|||||||
sctx.setViewport({resolution, resolution});
|
sctx.setViewport({resolution, resolution});
|
||||||
shadowMap.bind();
|
shadowMap.bind();
|
||||||
setupWorldShader(shadowsShader, shadowCamera, settings, 0.0f);
|
setupWorldShader(shadowsShader, shadowCamera, settings, 0.0f);
|
||||||
chunks->drawChunksShadowsPass(shadowCamera, shadowsShader);
|
chunks->drawChunksShadowsPass(shadowCamera, shadowsShader, camera);
|
||||||
shadowMap.unbind();
|
shadowMap.unbind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user