From 6debc92ae5cf5a23515eb46c2a4df4ff2591eaa8 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 22 Jul 2025 01:41:52 +0300 Subject: [PATCH 1/7] optimize shadow maps generation a bit --- src/graphics/render/ChunksRenderer.cpp | 29 +++++++++++++++++++------- src/graphics/render/WorldRenderer.cpp | 1 - 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 284ebb43..7238cb19 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -185,6 +185,9 @@ const Mesh* ChunksRenderer::retrieveChunk( void ChunksRenderer::drawChunksShadowsPass( const Camera& camera, Shader& shader ) { + Frustum frustum; + frustum.update(camera.getProjView()); + const auto& atlas = assets.require("blocks"); atlas.getTexture()->bind(); @@ -193,19 +196,29 @@ void ChunksRenderer::drawChunksShadowsPass( if (chunk == nullptr) { continue; } + glm::ivec2 pos {chunk->x, chunk->z}; const auto& found = meshes.find({chunk->x, chunk->z}); if (found == meshes.end()) { continue; } - auto mesh = found->second.mesh.get(); - if (mesh) { - glm::vec3 coord( - chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f - ); - glm::mat4 model = glm::translate(glm::mat4(1.0f), coord); - shader.uniformMatrix("u_model", model); - mesh->draw(); + + glm::vec3 coord( + 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 max( + chunk->x * CHUNK_W + CHUNK_W, + chunk->top, + chunk->z * CHUNK_D + CHUNK_D + ); + + if (!frustum.isBoxVisible(min, max)) { + continue; } + glm::mat4 model = glm::translate(glm::mat4(1.0f), coord); + shader.uniformMatrix("u_model", model); + found->second.mesh->draw(); } } diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 93039d2c..065673ba 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -400,7 +400,6 @@ void WorldRenderer::generateShadowsMap( shadowCamera.setProjection(glm::ortho(min.x, max.x, min.y, max.y, 0.1f, 1000.0f)); { - frustumCulling->update(shadowCamera.getProjView()); auto sctx = pctx.sub(); sctx.setDepthTest(true); sctx.setCullFace(true); From 4a6ccf48473177f01d41a470f8e292a69e655c13 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 24 Jul 2025 21:40:00 +0300 Subject: [PATCH 2/7] feat: multiple index buffers per mesh support --- src/graphics/core/Mesh.hpp | 34 ++++++++---- src/graphics/core/Mesh.inl | 71 +++++++++++++++++--------- src/graphics/core/MeshData.hpp | 5 +- src/graphics/render/BlocksRenderer.cpp | 6 ++- src/graphics/render/BlocksRenderer.hpp | 3 +- src/graphics/render/ChunksRenderer.cpp | 3 +- src/graphics/render/commons.hpp | 2 +- 7 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/graphics/core/Mesh.hpp b/src/graphics/core/Mesh.hpp index 3d428322..48c02969 100644 --- a/src/graphics/core/Mesh.hpp +++ b/src/graphics/core/Mesh.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "MeshData.hpp" @@ -8,25 +10,32 @@ struct MeshStats { static int drawCalls; }; +struct IndexBufferData { + const uint32_t* indices; + size_t indicesCount; +}; + template class Mesh { + struct IndexBuffer { + unsigned int ibo; + size_t indexCount; + }; unsigned int vao; unsigned int vbo; - unsigned int ibo; + std::vector ibos; size_t vertexCount; - size_t indexCount; public: explicit Mesh(const MeshData& data); Mesh( const VertexStructure* vertexBuffer, size_t vertices, - const uint32_t* indexBuffer, - size_t indices + std::vector indices ); Mesh(const VertexStructure* vertexBuffer, size_t vertices) - : Mesh(vertexBuffer, vertices, nullptr, 0) {}; + : Mesh(vertexBuffer, vertices, {}) {}; ~Mesh(); @@ -34,18 +43,21 @@ public: /// attributes /// @param vertexBuffer vertex data buffer /// @param vertexCount number of vertices in new buffer - /// @param indexBuffer indices buffer - /// @param indexCount number of values in indices buffer + /// @param indices indices buffer void reload( const VertexStructure* vertexBuffer, size_t vertexCount, - const uint32_t* indexBuffer = nullptr, - size_t indexCount = 0 + const std::vector& indices ); + void reload(const VertexStructure* vertexBuffer, size_t vertexCount) { + static const std::vector indices {}; + reload(vertexBuffer, vertexCount, indices); + } + /// @brief Draw mesh with specified primitives type - /// @param primitive primitives type - void draw(unsigned int primitive) const; + /// @param iboIndex index of used element buffer + void draw(unsigned int primitive, int iboIndex = 0) const; /// @brief Draw mesh as triangles void draw() const; diff --git a/src/graphics/core/Mesh.inl b/src/graphics/core/Mesh.inl index 390c2f9a..778baaf9 100644 --- a/src/graphics/core/Mesh.inl +++ b/src/graphics/core/Mesh.inl @@ -11,13 +11,21 @@ inline constexpr size_t calc_size(const VertexAttribute attrs[]) { return vertexSize; } +template +inline std::vector convert_to_ibd(const MeshData& data) { + std::vector indices; + for (const auto& buffer : data.indices) { + indices.push_back(IndexBufferData {buffer.data(), buffer.size()}); + } + return indices; +} + template Mesh::Mesh(const MeshData& data) : Mesh( data.vertices.data(), data.vertices.size(), - data.indices.data(), - data.indices.size() + convert_to_ibd(data) ) { } @@ -25,10 +33,9 @@ template Mesh::Mesh( const VertexStructure* vertexBuffer, size_t vertices, - const uint32_t* indexBuffer, - size_t indices + std::vector indices ) - : vao(0), vbo(0), ibo(0), vertexCount(0), indexCount(0) { + : vao(0), vbo(0), ibos(), vertexCount(0) { static_assert( calc_size(VertexStructure::ATTRIBUTES) == sizeof(VertexStructure) ); @@ -39,8 +46,9 @@ Mesh::Mesh( glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); - reload(vertexBuffer, vertices, indexBuffer, indices); + reload(vertexBuffer, vertices, std::move(indices)); + glBindVertexArray(vao); // attributes int offset = 0; for (int i = 0; attrs[i].count; i++) { @@ -65,8 +73,8 @@ Mesh::~Mesh() { MeshStats::meshesCount--; glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); - if (ibo != 0) { - glDeleteBuffers(1, &ibo); + for (int i = ibos.size() - 1; i >= 0; i--) { + glDeleteBuffers(1, &ibos[i].ibo); } } @@ -74,11 +82,9 @@ template void Mesh::reload( const VertexStructure* vertexBuffer, size_t vertexCount, - const uint32_t* indexBuffer, - size_t indexCount + const std::vector& indices ) { this->vertexCount = vertexCount; - this->indexCount = indexCount; glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); if (vertexBuffer != nullptr && vertexCount != 0) { @@ -92,30 +98,47 @@ void Mesh::reload( glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW); } - if (indexBuffer != nullptr && indexCount != 0) { - if (ibo == 0) glGenBuffers(1, &ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + for (int i = indices.size(); i < ibos.size(); i++) { + glDeleteBuffers(1, &ibos[i].ibo); + } + ibos.clear(); + + for (int i = 0; i < indices.size(); i++) { + const auto& indexBuffer = indices[i]; + ibos.push_back(IndexBuffer {0, 0}); + glGenBuffers(1, &ibos[i].ibo); + ibos[i].indexCount = indexBuffer.indicesCount; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[i].ibo); glBufferData( GL_ELEMENT_ARRAY_BUFFER, - sizeof(uint32_t) * indexCount, - indexBuffer, + sizeof(uint32_t) * indexBuffer.indicesCount, + indexBuffer.indices, GL_STATIC_DRAW ); - } else if (ibo != 0) { - glDeleteBuffers(1, &ibo); } + glBindVertexArray(0); } template -void Mesh::draw(unsigned int primitive) const { +void Mesh::draw(unsigned int primitive, int iboIndex) const { MeshStats::drawCalls++; - glBindVertexArray(vao); - if (ibo != 0) { - glDrawElements(primitive, indexCount, GL_UNSIGNED_INT, nullptr); - } else { + + if (!ibos.empty()) { + if (iboIndex < ibos.size()) { + glBindVertexArray(vao); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[ + std::min(static_cast(iboIndex), ibos.size()) + ].ibo); + glDrawElements( + primitive, ibos.at(0).indexCount, GL_UNSIGNED_INT, nullptr + ); + glBindVertexArray(0); + } + } else if (vertexCount > 0) { + glBindVertexArray(vao); glDrawArrays(primitive, 0, vertexCount); + glBindVertexArray(0); } - glBindVertexArray(0); } template diff --git a/src/graphics/core/MeshData.hpp b/src/graphics/core/MeshData.hpp index 82954b23..e9a0630c 100644 --- a/src/graphics/core/MeshData.hpp +++ b/src/graphics/core/MeshData.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "typedefs.hpp" @@ -40,7 +41,7 @@ struct VertexAttribute { template struct MeshData { util::Buffer vertices; - util::Buffer indices; + std::vector> indices; util::Buffer attrs; MeshData() = default; @@ -50,7 +51,7 @@ struct MeshData { /// @param attrs vertex attribute sizes (must be null-terminated) MeshData( util::Buffer vertices, - util::Buffer indices, + std::vector> indices, util::Buffer attrs ) : vertices(std::move(vertices)), indices(std::move(indices)), diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index ae9e5d99..45888543 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -706,6 +706,7 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { vertexCount = 0; vertexOffset = 0; indexCount = 0; + denseRender = settings.graphics.denseRender.get(); render(voxels, beginEnds); } @@ -714,7 +715,7 @@ ChunkMeshData BlocksRenderer::createMesh() { return ChunkMeshData{ MeshData( util::Buffer(vertexBuffer.get(), vertexCount), - util::Buffer(indexBuffer.get(), indexCount), + std::vector> {util::Buffer(indexBuffer.get(), indexCount)}, util::Buffer( ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute) ) @@ -727,7 +728,8 @@ ChunkMesh BlocksRenderer::render(const Chunk *chunk, const Chunks *chunks) { build(chunk, chunks); return ChunkMesh{std::make_unique>( - vertexBuffer.get(), vertexCount, indexBuffer.get(), indexCount + vertexBuffer.get(), vertexCount, + std::vector {IndexBufferData {indexBuffer.get(), indexCount}} ), std::move(sortingMesh)}; } diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 7d950ac4..6f1ff0d6 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -33,6 +33,7 @@ class BlocksRenderer { int voxelBufferPadding = 2; bool overflow = false; bool cancelled = false; + bool denseRender = false; const Chunk* chunk = nullptr; std::unique_ptr voxelsBuffer; @@ -137,7 +138,7 @@ class BlocksRenderer { } if ((variant.culling == CullingMode::DISABLED || (variant.culling == CullingMode::OPTIONAL && - settings.graphics.denseRender.get())) && + denseRender)) && vox.id == def.rt.id) { return true; } diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 7238cb19..4f8bfc69 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -89,8 +89,7 @@ ChunksRenderer::ChunksRenderer( logger.info() << "created " << threadPool.getWorkersCount() << " workers"; } -ChunksRenderer::~ChunksRenderer() { -} +ChunksRenderer::~ChunksRenderer() = default; const Mesh* ChunksRenderer::render( const std::shared_ptr& chunk, bool important diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index 905e34cc..9e78d1f5 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -47,7 +47,7 @@ struct ChunkMeshData { }; struct ChunkMesh { - std::unique_ptr > mesh; + std::unique_ptr> mesh; SortingMeshData sortingMeshData; std::unique_ptr > sortedMesh = nullptr; }; From 799d7124474ec581b07bd73c6f40dc4df37c3cd1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 24 Jul 2025 22:51:53 +0300 Subject: [PATCH 3/7] update ContentGfxCache --- src/data/setting.hpp | 2 +- src/frontend/ContentGfxCache.cpp | 40 +++++++++++++++----------- src/frontend/ContentGfxCache.hpp | 21 ++++++++++++-- src/graphics/render/BlocksPreview.cpp | 7 +++-- src/graphics/render/BlocksRenderer.cpp | 34 ++++++++++++++-------- 5 files changed, 69 insertions(+), 35 deletions(-) diff --git a/src/data/setting.hpp b/src/data/setting.hpp index 2afa610c..e2e83348 100644 --- a/src/data/setting.hpp +++ b/src/data/setting.hpp @@ -53,7 +53,7 @@ public: }); } - const T& get() const { + [[nodiscard]] const T& get() const { return value; } diff --git a/src/frontend/ContentGfxCache.cpp b/src/frontend/ContentGfxCache.cpp index 71492626..47443aff 100644 --- a/src/frontend/ContentGfxCache.cpp +++ b/src/frontend/ContentGfxCache.cpp @@ -9,9 +9,11 @@ #include "graphics/core/Atlas.hpp" #include "maths/UVRegion.hpp" #include "voxels/Block.hpp" +#include "debug/Logger.hpp" #include "core_defs.hpp" #include "settings.hpp" +static debug::Logger logger("content-gfx-cache"); ContentGfxCache::ContentGfxCache( const Content& content, @@ -22,27 +24,29 @@ ContentGfxCache::ContentGfxCache( refresh(); } -static void refresh_variant( - const Assets& assets, +void ContentGfxCache::refreshVariant( const Block& def, const Variant& variant, uint8_t variantIndex, - std::unique_ptr& sideregions, - const Atlas& atlas, - const GraphicsSettings& settings, - std::unordered_map& models + const Atlas& atlas ) { + bool denseRender = settings.denseRender.get(); for (uint side = 0; side < 6; side++) { std::string tex = variant.textureFaces[side]; - if (variant.culling == CullingMode::OPTIONAL && - !settings.denseRender.get() && atlas.has(tex + "_opaque")) { - tex = tex + "_opaque"; + std::string texOpaque = tex + "_opaque"; + + if (!atlas.has(tex)) { + tex = TEXTURE_NOTFOUND; } - if (atlas.has(tex)) { - sideregions[(def.rt.id * 6 + side) * MAX_VARIANTS + variantIndex] = atlas.get(tex); - } else if (atlas.has(TEXTURE_NOTFOUND)) { - sideregions[(def.rt.id * 6 + side) * MAX_VARIANTS + variantIndex] = atlas.get(TEXTURE_NOTFOUND); + + if (!atlas.has(texOpaque)) { + texOpaque = tex; + } else if (variant.culling == CullingMode::OPTIONAL && !denseRender) { + tex = texOpaque; } + size_t index = getRegionIndex(def.rt.id, variantIndex, side, false); + sideregions[index] = atlas.get(tex); + sideregions[index + 1] = atlas.get(texOpaque); } if (variant.model.type == BlockModelType::CUSTOM) { auto model = assets.require(variant.model.name); @@ -63,11 +67,11 @@ static void refresh_variant( } void ContentGfxCache::refresh(const Block& def, const Atlas& atlas) { - refresh_variant(assets, def, def.defaults, 0, sideregions, atlas, settings, models); + refreshVariant(def, def.defaults, 0, atlas); if (def.variants) { const auto& variants = def.variants->variants; for (int i = 1; i < variants.size() - 1; i++) { - refresh_variant(assets, def, variants[i], i, sideregions, atlas, settings, models); + refreshVariant(def, variants[i], i, atlas); } def.variants->variants.at(0) = def.defaults; } @@ -75,7 +79,11 @@ void ContentGfxCache::refresh(const Block& def, const Atlas& atlas) { void ContentGfxCache::refresh() { auto indices = content.getIndices(); - sideregions = std::make_unique(indices->blocks.count() * 6 * MAX_VARIANTS); + size_t size = indices->blocks.count() * GFXC_SIDES * GFXC_MAX_VARIANTS * 2; + + logger.info() << "uv cache size is " << (sizeof(UVRegion) * size) << " B"; + + sideregions = std::make_unique(size); const auto& atlas = assets.require("blocks"); const auto& blocks = indices->blocks.getIterable(); diff --git a/src/frontend/ContentGfxCache.hpp b/src/frontend/ContentGfxCache.hpp index fdeec60d..8eda04e5 100644 --- a/src/frontend/ContentGfxCache.hpp +++ b/src/frontend/ContentGfxCache.hpp @@ -14,9 +14,11 @@ class Assets; class Atlas; class Block; struct UVRegion; +struct Variant; struct GraphicsSettings; -inline constexpr int MAX_VARIANTS = 16; +inline constexpr int GFXC_MAX_VARIANTS = 16; +inline constexpr int GFXC_SIDES = 6; class ContentGfxCache { const Content& content; @@ -26,6 +28,13 @@ class ContentGfxCache { // array of block sides uv regions (6 per block) std::unique_ptr sideregions; std::unordered_map models; + + void refreshVariant( + const Block& def, + const Variant& variant, + uint8_t variantIndex, + const Atlas& atlas + ); public: ContentGfxCache( const Content& content, @@ -34,8 +43,14 @@ public: ); ~ContentGfxCache(); - inline const UVRegion& getRegion(blockid_t id, uint8_t variant, int side) const { - return sideregions[(id * 6 + side) * MAX_VARIANTS + variant]; + static inline size_t getRegionIndex( + blockid_t id, uint8_t variant, int side, bool opaque + ) { + return ((id * GFXC_SIDES + side) * GFXC_MAX_VARIANTS + variant) * 2 + opaque; + } + + inline const UVRegion& getRegion(blockid_t id, uint8_t variant, int side, bool dense) const { + return sideregions[getRegionIndex(id, variant, side, !dense)]; } const model::Model& getModel(blockid_t id) const; diff --git a/src/graphics/render/BlocksPreview.cpp b/src/graphics/render/BlocksPreview.cpp index 77df92de..9a1bf97d 100644 --- a/src/graphics/render/BlocksPreview.cpp +++ b/src/graphics/render/BlocksPreview.cpp @@ -27,9 +27,10 @@ std::unique_ptr BlocksPreview::draw( ){ display::clear(); blockid_t id = def.rt.id; - const UVRegion texfaces[6]{cache.getRegion(id, 0, 0), cache.getRegion(id, 0, 1), - cache.getRegion(id, 0, 2), cache.getRegion(id, 0, 3), - cache.getRegion(id, 0, 4), cache.getRegion(id, 0, 5)}; + const UVRegion texfaces[6] { + cache.getRegion(id, 0, 0, true), cache.getRegion(id, 0, 1, true), + cache.getRegion(id, 0, 2, true), cache.getRegion(id, 0, 3, true), + cache.getRegion(id, 0, 4, true), cache.getRegion(id, 0, 5, true)}; glm::vec3 offset(0.1f, 0.5f, 0.1f); switch (def.defaults.model.type) { diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 45888543..d52fea6c 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -477,6 +477,7 @@ glm::vec4 BlocksRenderer::pickSoftLight( void BlocksRenderer::render( const voxel* voxels, int beginEnds[256][2] ) { + bool denseRender = this->denseRender; for (const auto drawGroup : *content.drawGroups) { int begin = beginEnds[drawGroup][0]; if (begin == 0) { @@ -497,12 +498,12 @@ void BlocksRenderer::render( continue; } const UVRegion texfaces[6] { - cache.getRegion(id, variantId, 0), - cache.getRegion(id, variantId, 1), - cache.getRegion(id, variantId, 2), - cache.getRegion(id, variantId, 3), - cache.getRegion(id, variantId, 4), - cache.getRegion(id, variantId, 5) + cache.getRegion(id, variantId, 0, denseRender), + cache.getRegion(id, variantId, 1, denseRender), + cache.getRegion(id, variantId, 2, denseRender), + cache.getRegion(id, variantId, 3, denseRender), + cache.getRegion(id, variantId, 4, denseRender), + cache.getRegion(id, variantId, 5, denseRender) }; int x = i % CHUNK_W; int y = i / (CHUNK_D * CHUNK_W); @@ -550,6 +551,8 @@ SortingMeshData BlocksRenderer::renderTranslucent( AABB aabb {}; bool aabbInit = false; size_t totalSize = 0; + + bool denseRender = this->denseRender; for (const auto drawGroup : *content.drawGroups) { int begin = beginEnds[drawGroup][0]; if (begin == 0) { @@ -570,12 +573,12 @@ SortingMeshData BlocksRenderer::renderTranslucent( continue; } const UVRegion texfaces[6] { - cache.getRegion(id, variantId, 0), - cache.getRegion(id, variantId, 1), - cache.getRegion(id, variantId, 2), - cache.getRegion(id, variantId, 3), - cache.getRegion(id, variantId, 4), - cache.getRegion(id, variantId, 5) + cache.getRegion(id, variantId, 0, denseRender), + cache.getRegion(id, variantId, 1, denseRender), + cache.getRegion(id, variantId, 2, denseRender), + cache.getRegion(id, variantId, 3, denseRender), + cache.getRegion(id, variantId, 4, denseRender), + cache.getRegion(id, variantId, 5, denseRender) }; int x = i % CHUNK_W; int y = i / (CHUNK_D * CHUNK_W); @@ -706,9 +709,16 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { vertexCount = 0; vertexOffset = 0; indexCount = 0; + denseRender = settings.graphics.denseRender.get(); + // denseRender = false; render(voxels, beginEnds); + + // denseRender = settings.graphics.denseRender.get(); + // if (denseRender) { + + // } } ChunkMeshData BlocksRenderer::createMesh() { From fbde46afa734c85256803ecc71c9824650ac4318 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 25 Jul 2025 00:54:54 +0300 Subject: [PATCH 4/7] feat: distance-based dense render optimization --- src/graphics/core/Mesh.inl | 6 +- src/graphics/render/BlocksRenderer.cpp | 80 ++++++++++++++++++-------- src/graphics/render/BlocksRenderer.hpp | 17 ++++-- src/graphics/render/ChunksRenderer.cpp | 17 ++++-- src/graphics/render/ChunksRenderer.hpp | 4 +- src/graphics/render/WorldRenderer.cpp | 2 +- 6 files changed, 87 insertions(+), 39 deletions(-) diff --git a/src/graphics/core/Mesh.inl b/src/graphics/core/Mesh.inl index 778baaf9..c4cec966 100644 --- a/src/graphics/core/Mesh.inl +++ b/src/graphics/core/Mesh.inl @@ -126,11 +126,9 @@ void Mesh::draw(unsigned int primitive, int iboIndex) const { if (!ibos.empty()) { if (iboIndex < ibos.size()) { glBindVertexArray(vao); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[ - std::min(static_cast(iboIndex), ibos.size()) - ].ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibos[iboIndex].ibo); glDrawElements( - primitive, ibos.at(0).indexCount, GL_UNSIGNED_INT, nullptr + primitive, ibos.at(iboIndex).indexCount, GL_UNSIGNED_INT, nullptr ); glBindVertexArray(0); } diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index d52fea6c..1f14d2c7 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -20,6 +20,7 @@ BlocksRenderer::BlocksRenderer( ) : content(content), vertexBuffer(std::make_unique(capacity)), indexBuffer(std::make_unique(capacity)), + denseIndexBuffer(std::make_unique(capacity)), vertexCount(0), vertexOffset(0), indexCount(0), @@ -475,9 +476,10 @@ glm::vec4 BlocksRenderer::pickSoftLight( } void BlocksRenderer::render( - const voxel* voxels, int beginEnds[256][2] + const voxel* voxels, const int beginEnds[256][2] ) { bool denseRender = this->denseRender; + bool densePass = this->densePass; for (const auto drawGroup : *content.drawGroups) { int begin = beginEnds[drawGroup][0]; if (begin == 0) { @@ -494,16 +496,19 @@ void BlocksRenderer::render( if (id == 0 || variant.drawGroup != drawGroup || state.segment) { continue; } + if (denseRender != (variant.culling == CullingMode::OPTIONAL)) { + continue; + } if (def.translucent) { continue; } const UVRegion texfaces[6] { - cache.getRegion(id, variantId, 0, denseRender), - cache.getRegion(id, variantId, 1, denseRender), - cache.getRegion(id, variantId, 2, denseRender), - cache.getRegion(id, variantId, 3, denseRender), - cache.getRegion(id, variantId, 4, denseRender), - cache.getRegion(id, variantId, 5, denseRender) + 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); @@ -514,16 +519,19 @@ void BlocksRenderer::render( def.ambientOcclusion); 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); break; } case BlockModelType::CUSTOM: { + if (!denseRender) blockCustomModel( {x, y, z}, def, @@ -552,7 +560,7 @@ SortingMeshData BlocksRenderer::renderTranslucent( bool aabbInit = false; size_t totalSize = 0; - bool denseRender = this->denseRender; + bool densePass = this->densePass; for (const auto drawGroup : *content.drawGroups) { int begin = beginEnds[drawGroup][0]; if (begin == 0) { @@ -573,12 +581,12 @@ SortingMeshData BlocksRenderer::renderTranslucent( continue; } const UVRegion texfaces[6] { - cache.getRegion(id, variantId, 0, denseRender), - cache.getRegion(id, variantId, 1, denseRender), - cache.getRegion(id, variantId, 2, denseRender), - cache.getRegion(id, variantId, 3, denseRender), - cache.getRegion(id, variantId, 4, denseRender), - cache.getRegion(id, variantId, 5, denseRender) + 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); @@ -703,29 +711,45 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { vertexCount = 0; vertexOffset = indexCount = 0; + denseRender = false; + densePass = false; + sortingMesh = renderTranslucent(voxels, beginEnds); overflow = false; vertexCount = 0; vertexOffset = 0; indexCount = 0; + denseIndexCount = 0; - denseRender = settings.graphics.denseRender.get(); - // denseRender = false; - + denseRender = false; //settings.graphics.denseRender.get(); + densePass = false; render(voxels, beginEnds); - // denseRender = settings.graphics.denseRender.get(); - // if (denseRender) { - - // } + size_t endIndex = indexCount; + + 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() { - return ChunkMeshData{ + return ChunkMeshData { MeshData( util::Buffer(vertexBuffer.get(), vertexCount), - std::vector> {util::Buffer(indexBuffer.get(), indexCount)}, + std::vector> { + util::Buffer(indexBuffer.get(), indexCount), + util::Buffer(denseIndexBuffer.get(), denseIndexCount), + }, util::Buffer( 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>( vertexBuffer.get(), vertexCount, - std::vector {IndexBufferData {indexBuffer.get(), indexCount}} + std::vector { + IndexBufferData {indexBuffer.get(), indexCount}, + IndexBufferData {denseIndexBuffer.get(), denseIndexCount}, + } ), std::move(sortingMesh)}; } VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const { 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)); +} diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 6f1ff0d6..a954fad6 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -26,13 +26,16 @@ class BlocksRenderer { const Content& content; std::unique_ptr vertexBuffer; std::unique_ptr indexBuffer; + std::unique_ptr denseIndexBuffer; size_t vertexCount; size_t vertexOffset; size_t indexCount; + size_t denseIndexCount; size_t capacity; int voxelBufferPadding = 2; bool overflow = false; bool cancelled = false; + bool densePass = false; bool denseRender = false; const Chunk* chunk = nullptr; std::unique_ptr voxelsBuffer; @@ -136,10 +139,12 @@ class BlocksRenderer { if ((otherDrawGroup && (otherDrawGroup != variant.drawGroup)) || !blockVariant.rt.solid) { return true; } - if ((variant.culling == CullingMode::DISABLED || - (variant.culling == CullingMode::OPTIONAL && - denseRender)) && - vox.id == def.rt.id) { + if (densePass) { + return variant.culling == CullingMode::OPTIONAL; + } else if (variant.culling == CullingMode::OPTIONAL) { + return false; + } + if (variant.culling == CullingMode::DISABLED && vox.id == def.rt.id) { return true; } 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(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]); public: BlocksRenderer( @@ -166,6 +171,8 @@ public: ChunkMeshData createMesh(); VoxelsVolume* getVoxelsBuffer() const; + size_t getMemoryConsumption() const; + bool isCancelled() const { return cancelled; } diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 4f8bfc69..e3c1afb9 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -18,6 +18,9 @@ static debug::Logger logger("chunks-render"); 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, RendererResult> { const Chunks& chunks; BlocksRenderer renderer; @@ -87,6 +90,9 @@ ChunksRenderer::ChunksRenderer( level->content, cache, settings ); logger.info() << "created " << threadPool.getWorkersCount() << " workers"; + logger.info() << "memory consumption is " + << renderer->getMemoryConsumption() * threadPool.getWorkersCount() + << " B"; } ChunksRenderer::~ChunksRenderer() = default; @@ -182,7 +188,7 @@ const Mesh* ChunksRenderer::retrieveChunk( } void ChunksRenderer::drawChunksShadowsPass( - const Camera& camera, Shader& shader + const Camera& camera, Shader& shader, const Camera& playerCamera ) { Frustum frustum; 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 ); - 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( chunk->x * CHUNK_W + CHUNK_W, chunk->top, @@ -217,7 +223,9 @@ void ChunksRenderer::drawChunksShadowsPass( } glm::mat4 model = glm::translate(glm::mat4(1.0f), coord); 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); 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++; } } diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index fcc8b07d..70925343 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -73,7 +73,9 @@ public: const std::shared_ptr& 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); diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 065673ba..30a25430 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -406,7 +406,7 @@ void WorldRenderer::generateShadowsMap( sctx.setViewport({resolution, resolution}); shadowMap.bind(); setupWorldShader(shadowsShader, shadowCamera, settings, 0.0f); - chunks->drawChunksShadowsPass(shadowCamera, shadowsShader); + chunks->drawChunksShadowsPass(shadowCamera, shadowsShader, camera); shadowMap.unbind(); } } From 6d88b7c3d14d9eefef4737857274b341e2bb3b49 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 25 Jul 2025 12:45:28 +0300 Subject: [PATCH 5/7] add dense-render-distance setting --- src/graphics/render/ChunksRenderer.cpp | 13 ++++++++----- src/io/settings_io.cpp | 1 + src/settings.hpp | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index e3c1afb9..bb816c37 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -18,9 +18,6 @@ static debug::Logger logger("chunks-render"); 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, RendererResult> { const Chunks& chunks; BlocksRenderer renderer; @@ -197,6 +194,9 @@ void ChunksRenderer::drawChunksShadowsPass( atlas.getTexture()->bind(); + auto denseDistance = settings.graphics.denseRenderDistance.get(); + auto denseDistance2 = denseDistance * denseDistance; + for (const auto& chunk : chunks.getChunks()) { if (chunk == nullptr) { continue; @@ -225,7 +225,7 @@ void ChunksRenderer::drawChunksShadowsPass( shader.uniformMatrix("u_model", model); 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); + (min + max) * 0.5f * glm::vec3(1, 0, 1)) < denseDistance2); } } @@ -262,6 +262,9 @@ void ChunksRenderer::drawChunks( visibleChunks = 0; shader.uniform1i("u_alphaClip", true); + auto denseDistance = settings.graphics.denseRenderDistance.get(); + auto denseDistance2 = denseDistance * denseDistance; + // TODO: minimize draw calls number for (int i = indices.size()-1; i >= 0; i--) { auto& chunk = chunks.getChunks()[indices[i].index]; @@ -274,7 +277,7 @@ void ChunksRenderer::drawChunks( glm::mat4 model = glm::translate(glm::mat4(1.0f), coord); shader.uniformMatrix("u_model", model); 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); + (coord + glm::vec3(CHUNK_W * 0.5f, 0.0f, CHUNK_D * 0.5f))) < denseDistance2); visibleChunks++; } } diff --git a/src/io/settings_io.cpp b/src/io/settings_io.cpp index 000e965b..cdbf567e 100644 --- a/src/io/settings_io.cpp +++ b/src/io/settings_io.cpp @@ -77,6 +77,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) { builder.add("advanced-render", &settings.graphics.advancedRender); builder.add("ssao", &settings.graphics.ssao); builder.add("shadows-quality", &settings.graphics.shadowsQuality); + builder.add("dense-render-distance", &settings.graphics.denseRenderDistance); builder.section("ui"); builder.add("language", &settings.ui.language); diff --git a/src/settings.hpp b/src/settings.hpp index e8826800..fb968e1b 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -81,6 +81,8 @@ struct GraphicsSettings { FlagSetting ssao {true}; /// @brief Shadows quality IntegerSetting shadowsQuality {0, 0, 3}; + /// @brief Dense render distance + IntegerSetting denseRenderDistance {40, 0, 10'000}; }; struct DebugSettings { From 705e398bc3ea82fc4f213f1d6b7f00332a32e48d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 25 Jul 2025 21:21:18 +0300 Subject: [PATCH 6/7] improve u_gamma support & update default dense-render-distance value --- res/shaders/effect.glslf | 1 + res/shaders/effects/deferred_lighting.glsl | 2 ++ res/shaders/lib/shadows.glsl | 2 +- src/settings.hpp | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/res/shaders/effect.glslf b/res/shaders/effect.glslf index 2b6307ef..687aeeae 100644 --- a/res/shaders/effect.glslf +++ b/res/shaders/effect.glslf @@ -18,6 +18,7 @@ uniform mat4 u_view; uniform mat4 u_inverseView; uniform vec3 u_sunDir; uniform vec3 u_cameraPos; +uniform float u_gamma; #include <__effect__> diff --git a/res/shaders/effects/deferred_lighting.glsl b/res/shaders/effects/deferred_lighting.glsl index f8f10401..c314df02 100644 --- a/res/shaders/effects/deferred_lighting.glsl +++ b/res/shaders/effects/deferred_lighting.glsl @@ -29,6 +29,8 @@ vec4 effect() { light = max(light, emission); + light = pow(light, u_gamma); + vec3 fogColor = texture(u_skybox, dir).rgb; float fog = calc_fog(length(u_view * vec4((modelpos.xyz - u_cameraPos) * FOG_POS_SCALE, 0.0)) / 256.0); return vec4(mix(texture(u_screen, v_uv).rgb * mix(1.0, light, 1.0), fogColor, fog), 1.0); diff --git a/res/shaders/lib/shadows.glsl b/res/shaders/lib/shadows.glsl index 6fede28b..71ef4776 100644 --- a/res/shaders/lib/shadows.glsl +++ b/res/shaders/lib/shadows.glsl @@ -35,7 +35,7 @@ float calc_shadow( } shadow /= 9.0; } else { - shadow = 0.5; + shadow = 0.0; } return shadow; } diff --git a/src/settings.hpp b/src/settings.hpp index fb968e1b..d4c21688 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -82,7 +82,7 @@ struct GraphicsSettings { /// @brief Shadows quality IntegerSetting shadowsQuality {0, 0, 3}; /// @brief Dense render distance - IntegerSetting denseRenderDistance {40, 0, 10'000}; + IntegerSetting denseRenderDistance {56, 0, 10'000}; }; struct DebugSettings { From 7cf073f0791d7df459a97859004c0707783452f8 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 25 Jul 2025 22:28:28 +0300 Subject: [PATCH 7/7] fix: skybox is not visible behind translucent blocks --- res/preload.json | 1 + res/shaders/entity.glslf | 15 ++------- res/shaders/entity.glslv | 35 ++++--------------- res/shaders/lib/commons.glsl | 9 +---- res/shaders/lib/lighting.glsl | 5 +++ res/shaders/lib/sky.glsl | 14 ++++++++ res/shaders/lib/world_fragment_header.glsl | 17 ++++++++++ res/shaders/lib/world_uniforms.glsl | 15 +++++++++ res/shaders/lib/world_vertex_header.glsl | 17 ++++++++++ res/shaders/main.glslf | 19 ++--------- res/shaders/main.glslv | 37 +++++--------------- res/shaders/translucent.glslf | 38 +++++++++++++++++++++ res/shaders/translucent.glslv | 39 ++++++++++++++++++++++ src/graphics/render/WorldRenderer.cpp | 18 +++++++--- 14 files changed, 183 insertions(+), 96 deletions(-) create mode 100644 res/shaders/lib/sky.glsl create mode 100644 res/shaders/lib/world_fragment_header.glsl create mode 100644 res/shaders/lib/world_uniforms.glsl create mode 100644 res/shaders/lib/world_vertex_header.glsl create mode 100644 res/shaders/translucent.glslf create mode 100644 res/shaders/translucent.glslv diff --git a/res/preload.json b/res/preload.json index eb41f40d..887b0e26 100644 --- a/res/preload.json +++ b/res/preload.json @@ -5,6 +5,7 @@ "main", "lines", "entity", + "translucent", "background", "skybox_gen", "shadows" diff --git a/res/shaders/entity.glslf b/res/shaders/entity.glslf index 4d4fadba..f3293adb 100644 --- a/res/shaders/entity.glslf +++ b/res/shaders/entity.glslf @@ -3,27 +3,18 @@ layout (location = 1) out vec4 f_position; layout (location = 2) out vec4 f_normal; layout (location = 3) out vec4 f_emission; -in float a_distance; -in float a_fog; -in vec2 a_texCoord; -in vec3 a_dir; -in vec3 a_normal; -in vec3 a_position; -in vec3 a_realnormal; +#include + in vec4 a_color; -in vec4 a_modelpos; -in float a_emission; uniform sampler2D u_texture0; -uniform samplerCube u_skybox; + uniform vec3 u_fogColor; uniform float u_fogFactor; uniform float u_fogCurve; uniform bool u_alphaClip; uniform vec3 u_sunDir; -#include - void main() { vec4 texColor = texture(u_texture0, a_texCoord); float alpha = a_color.a * texColor.a; diff --git a/res/shaders/entity.glslv b/res/shaders/entity.glslv index d7b6d3e0..c337ddb2 100644 --- a/res/shaders/entity.glslv +++ b/res/shaders/entity.glslv @@ -6,44 +6,23 @@ layout (location = 2) in vec3 v_color; layout (location = 3) in vec4 v_light; layout (location = 4) in vec4 v_normal; -out float a_distance; -out float a_fog; -out vec2 a_texCoord; -out vec3 a_dir; -out vec3 a_normal; -out vec3 a_position; -out vec3 a_realnormal; -out vec4 a_color; -out vec4 a_modelpos; -out float a_emission; - -uniform mat4 u_model; -uniform mat4 u_proj; -uniform mat4 u_view; -uniform vec3 u_cameraPos; -uniform float u_gamma; -uniform float u_opacity; -uniform float u_timer; -uniform samplerCube u_skybox; - -uniform vec3 u_torchlightColor; -uniform float u_torchlightDistance; - +#include #include #include +#include + +out vec4 a_color; void main() { a_modelpos = u_model * vec4(v_position, 1.0); vec3 pos3d = a_modelpos.xyz - u_cameraPos; - a_modelpos.xyz = apply_planet_curvature(a_modelpos.xyz, pos3d); a_realnormal = v_normal.xyz * 2.0 - 1.0; a_normal = calc_screen_normal(a_realnormal); - vec3 light = v_light.rgb; - float torchlight = calc_torch_light(a_realnormal, a_modelpos.xyz); - light += torchlight * u_torchlightColor; - a_color = vec4(pow(light, vec3(u_gamma)), 1.0f); + a_color = vec4(calc_torch_light( + v_light.rgb, a_realnormal, a_modelpos.xyz, u_torchlightColor, u_gamma + ), 1.0); a_texCoord = v_texCoord; a_dir = a_modelpos.xyz - u_cameraPos; diff --git a/res/shaders/lib/commons.glsl b/res/shaders/lib/commons.glsl index 3701fcc3..e13b0ce1 100644 --- a/res/shaders/lib/commons.glsl +++ b/res/shaders/lib/commons.glsl @@ -1,14 +1,7 @@ #ifndef COMMONS_GLSL_ #define COMMONS_GLSL_ -#include -vec3 pick_sky_color(samplerCube cubemap) { - vec3 skyLightColor = texture(cubemap, vec3(0.4f, 0.0f, 0.4f)).rgb; - skyLightColor *= SKY_LIGHT_TINT; - skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL); - skyLightColor = max(MIN_SKY_LIGHT, skyLightColor); - return skyLightColor; -} +#include vec3 apply_planet_curvature(vec3 modelPos, vec3 pos3d) { modelPos.y -= pow(length(pos3d.xz) * CURVATURE_FACTOR, 3.0f); diff --git a/res/shaders/lib/lighting.glsl b/res/shaders/lib/lighting.glsl index c9e14920..54e076ae 100644 --- a/res/shaders/lib/lighting.glsl +++ b/res/shaders/lib/lighting.glsl @@ -6,6 +6,11 @@ float calc_torch_light(vec3 normal, vec3 modelpos) { * max(0.0, -dot(normal, normalize(modelpos - u_cameraPos))); } +vec3 calc_torch_light(vec3 light, vec3 normal, vec3 modelpos, vec3 torchLightColor, float gamma) { + float torchlight = calc_torch_light(normal, modelpos); + return pow(light + torchlight * torchLightColor, vec3(gamma)); +} + vec3 calc_screen_normal(vec3 normal) { return transpose(inverse(mat3(u_view * u_model))) * normal; } diff --git a/res/shaders/lib/sky.glsl b/res/shaders/lib/sky.glsl new file mode 100644 index 00000000..771f37f2 --- /dev/null +++ b/res/shaders/lib/sky.glsl @@ -0,0 +1,14 @@ +#ifndef COMMONS_SKY_ +#define COMMONS_SKY_ + +#include + +vec3 pick_sky_color(samplerCube cubemap) { + vec3 skyLightColor = texture(cubemap, vec3(0.4f, 0.0f, 0.4f)).rgb; + skyLightColor *= SKY_LIGHT_TINT; + skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL); + skyLightColor = max(MIN_SKY_LIGHT, skyLightColor); + return skyLightColor; +} + +#endif // COMMONS_SKY_ diff --git a/res/shaders/lib/world_fragment_header.glsl b/res/shaders/lib/world_fragment_header.glsl new file mode 100644 index 00000000..8e6e88bd --- /dev/null +++ b/res/shaders/lib/world_fragment_header.glsl @@ -0,0 +1,17 @@ +#ifndef GLSL_WORLD_FRAGMENT_HEADER_ +#define GLSL_WORLD_FRAGMENT_HEADER_ + +in float a_distance; +in float a_fog; +in vec2 a_texCoord; +in vec3 a_dir; +in vec3 a_normal; +in vec3 a_position; +in vec3 a_realnormal; +in vec3 a_skyLight; +in vec4 a_modelpos; +in float a_emission; + +#include + +#endif // GLSL_WORLD_FRAGMENT_HEADER_ diff --git a/res/shaders/lib/world_uniforms.glsl b/res/shaders/lib/world_uniforms.glsl new file mode 100644 index 00000000..20c8f529 --- /dev/null +++ b/res/shaders/lib/world_uniforms.glsl @@ -0,0 +1,15 @@ +#ifndef GLSL_WORLD_UNIFORMS_ +#define GLSL_WORLD_UNIFORMS_ + +uniform mat4 u_model; +uniform mat4 u_proj; +uniform mat4 u_view; +uniform vec3 u_cameraPos; +uniform float u_gamma; +uniform float u_opacity; +uniform float u_timer; +uniform samplerCube u_skybox; +uniform vec3 u_torchlightColor; +uniform float u_torchlightDistance; + +#endif // GLSL_WORLD_UNIFORMS_ diff --git a/res/shaders/lib/world_vertex_header.glsl b/res/shaders/lib/world_vertex_header.glsl new file mode 100644 index 00000000..9e755027 --- /dev/null +++ b/res/shaders/lib/world_vertex_header.glsl @@ -0,0 +1,17 @@ +#ifndef GLSL_WORLD_VERTEX_HEADER_ +#define GLSL_WORLD_VERTEX_HEADER_ + +out float a_distance; +out float a_fog; +out vec2 a_texCoord; +out vec3 a_dir; +out vec3 a_normal; +out vec3 a_position; +out vec3 a_realnormal; +out vec3 a_skyLight; +out vec4 a_modelpos; +out float a_emission; + +#include + +#endif // GLSL_WORLD_VERTEX_HEADER_ diff --git a/res/shaders/main.glslf b/res/shaders/main.glslf index f7336d9a..115cb927 100644 --- a/res/shaders/main.glslf +++ b/res/shaders/main.glslf @@ -3,20 +3,11 @@ layout (location = 1) out vec4 f_position; layout (location = 2) out vec4 f_normal; layout (location = 3) out vec4 f_emission; -in float a_distance; -in float a_fog; -in vec2 a_texCoord; -in vec3 a_dir; -in vec3 a_normal; -in vec3 a_position; -in vec3 a_realnormal; -in vec3 a_skyLight; -in vec4 a_modelpos; +#include + in vec4 a_torchLight; -in float a_emission; uniform sampler2D u_texture0; -uniform samplerCube u_skybox; uniform vec3 u_sunDir; // flags @@ -24,8 +15,6 @@ uniform bool u_alphaClip; uniform bool u_debugLights; uniform bool u_debugNormals; -#include - void main() { vec4 texColor = texture(u_texture0, a_texCoord); float alpha = texColor.a; @@ -39,9 +28,7 @@ void main() { } if (u_debugLights) texColor.rgb = u_debugNormals ? (a_normal * 0.5 + 0.5) : vec3(1.0); - else if (u_debugNormals) { - texColor.rgb *= a_normal * 0.5 + 0.5; - } + f_color = texColor; f_color.rgb *= min(vec3(1.0), a_torchLight.rgb + a_skyLight); diff --git a/res/shaders/main.glslv b/res/shaders/main.glslv index 4d50e5d9..3d722029 100644 --- a/res/shaders/main.glslv +++ b/res/shaders/main.glslv @@ -5,44 +5,23 @@ layout (location = 1) in vec2 v_texCoord; layout (location = 2) in vec4 v_light; layout (location = 3) in vec4 v_normal; -out float a_distance; -out float a_fog; -out vec2 a_texCoord; -out vec3 a_dir; -out vec3 a_normal; -out vec3 a_position; -out vec3 a_realnormal; -out vec4 a_torchLight; -out vec3 a_skyLight; -out vec4 a_modelpos; -out float a_emission; - -uniform mat4 u_model; -uniform mat4 u_proj; -uniform mat4 u_view; -uniform vec3 u_cameraPos; -uniform float u_gamma; -uniform float u_timer; -uniform samplerCube u_skybox; - -uniform vec3 u_torchlightColor; -uniform float u_torchlightDistance; - +#include #include #include +#include + +out vec4 a_torchLight; void main() { a_modelpos = u_model * vec4(v_position, 1.0f); vec3 pos3d = a_modelpos.xyz - u_cameraPos; - a_modelpos.xyz = apply_planet_curvature(a_modelpos.xyz, pos3d); a_realnormal = v_normal.xyz * 2.0 - 1.0; a_normal = calc_screen_normal(a_realnormal); - vec3 light = v_light.rgb; - float torchlight = calc_torch_light(a_realnormal, a_modelpos.xyz); - a_torchLight = vec4(pow(light + torchlight * u_torchlightColor, vec3(u_gamma)), 1.0f); - + a_torchLight = vec4(calc_torch_light( + v_light.rgb, a_realnormal, a_modelpos.xyz, u_torchlightColor, u_gamma + ), 1.0); a_texCoord = v_texCoord; a_dir = a_modelpos.xyz - u_cameraPos; @@ -51,9 +30,11 @@ void main() { mat4 viewmodel = u_view * u_model; a_distance = length(viewmodel * vec4(pos3d, 0.0)); + #ifndef ADVANCED_RENDER a_fog = calc_fog(length(viewmodel * vec4(pos3d * FOG_POS_SCALE, 0.0)) / 256.0); #endif + a_emission = v_normal.w; vec4 viewmodelpos = u_view * a_modelpos; diff --git a/res/shaders/translucent.glslf b/res/shaders/translucent.glslf new file mode 100644 index 00000000..e5a852ac --- /dev/null +++ b/res/shaders/translucent.glslf @@ -0,0 +1,38 @@ +layout (location = 0) out vec4 f_color; + +#include + +in vec4 a_torchLight; + +uniform sampler2D u_texture0; +uniform vec3 u_sunDir; + +// flags +uniform bool u_alphaClip; +uniform bool u_debugLights; +uniform bool u_debugNormals; + +#include + +void main() { + vec4 texColor = texture(u_texture0, a_texCoord); + float alpha = texColor.a; + if (u_alphaClip) { + if (alpha < 0.2f) + discard; + alpha = 1.0; + } else { + if (alpha < 0.002f) + discard; + } + if (u_debugLights) + texColor.rgb = u_debugNormals ? (a_normal * 0.5 + 0.5) : vec3(1.0); + + f_color = texColor; + f_color.rgb *= min(vec3(1.0), a_torchLight.rgb + a_skyLight + * calc_shadow(a_modelpos, a_realnormal, length(a_position))); + + vec3 fogColor = texture(u_skybox, a_dir).rgb; + f_color = mix(f_color, vec4(fogColor, 1.0), a_fog); + f_color.a = alpha; +} diff --git a/res/shaders/translucent.glslv b/res/shaders/translucent.glslv new file mode 100644 index 00000000..8c429e97 --- /dev/null +++ b/res/shaders/translucent.glslv @@ -0,0 +1,39 @@ +#include + +layout (location = 0) in vec3 v_position; +layout (location = 1) in vec2 v_texCoord; +layout (location = 2) in vec4 v_light; +layout (location = 3) in vec4 v_normal; + +#include +#include +#include +#include + +out vec4 a_torchLight; + +void main() { + a_modelpos = u_model * vec4(v_position, 1.0f); + vec3 pos3d = a_modelpos.xyz - u_cameraPos; + + a_realnormal = v_normal.xyz * 2.0 - 1.0; + a_normal = calc_screen_normal(a_realnormal); + + a_torchLight = vec4(calc_torch_light( + v_light.rgb, a_realnormal, a_modelpos.xyz, u_torchlightColor, u_gamma + ), 1.0); + a_texCoord = v_texCoord; + + a_dir = a_modelpos.xyz - u_cameraPos; + vec3 skyLightColor = pick_sky_color(u_skybox); + a_skyLight = skyLightColor.rgb*v_light.a; + + mat4 viewmodel = u_view * u_model; + a_distance = length(viewmodel * vec4(pos3d, 0.0)); + a_fog = calc_fog(length(viewmodel * vec4(pos3d * FOG_POS_SCALE, 0.0)) / 256.0); + a_emission = v_normal.w; + + vec4 viewmodelpos = u_view * a_modelpos; + a_position = viewmodelpos.xyz; + gl_Position = u_proj * viewmodelpos; +} diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 30a25430..e8511fa5 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -220,8 +220,6 @@ void WorldRenderer::renderLevel( if (hudVisible) { renderLines(camera, linesShader, ctx); } - shader.use(); - chunks->drawSortedMeshes(camera, shader); if (!pause) { scripting::on_frontend_render(); @@ -431,6 +429,7 @@ void WorldRenderer::draw( auto& mainShader = assets.require("main"); auto& entityShader = assets.require("entity"); + auto& translucentShader = assets.require("translucent"); auto& deferredShader = assets.require("deferred_lighting").getShader(); const auto& settings = engine.getSettings(); @@ -463,6 +462,7 @@ void WorldRenderer::draw( mainShader.recompile(); entityShader.recompile(); deferredShader.recompile(); + translucentShader.recompile(); prevCTShaderSettings = currentSettings; } @@ -525,6 +525,7 @@ void WorldRenderer::draw( { DrawContext ctx = pctx.sub(); ctx.setDepthTest(true); + if (gbufferPipeline) { postProcessing.bindDepthBuffer(); } else { @@ -533,6 +534,16 @@ void WorldRenderer::draw( // Drawing background sky plane skybox->draw(ctx, camera, assets, worldInfo.daytime, clouds); + { + auto sctx = ctx.sub(); + sctx.setCullFace(true); + skybox->bind(); + translucentShader.use(); + setupWorldShader(translucentShader, camera, settings, fogFactor); + chunks->drawSortedMeshes(camera, translucentShader); + skybox->unbind(); + } + entityShader.use(); setupWorldShader(entityShader, camera, settings, fogFactor); @@ -552,8 +563,7 @@ void WorldRenderer::draw( glBindFramebuffer(GL_FRAMEBUFFER, 0); } postProcessing.render(pctx, assets, timer, camera); - - skybox->unbind(); + if (player.currentCamera == player.fpCamera) { DrawContext ctx = pctx.sub(); ctx.setDepthTest(true);