From 25b7deaef7d0592ef098301e7a9d2b98f9ef9ee0 Mon Sep 17 00:00:00 2001 From: Jukitsu Date: Sun, 26 Nov 2023 21:42:10 +0100 Subject: [PATCH] Chunk mesh cleanup for Smooth Lightning --- Jukcraft/Jukcraft.vcxproj | 2 + Jukcraft/Jukcraft.vcxproj.filters | 2 + Jukcraft/src/renderer/chunk/Mesh.cpp | 90 +++++++++++++++++++++++ Jukcraft/src/renderer/chunk/Mesh.h | 25 +++++++ Jukcraft/src/world/chunk/Chunk.cpp | 62 ++++++---------- Jukcraft/src/world/chunk/Chunk.h | 11 +-- Jukcraft/src/world/chunk/ChunkManager.cpp | 10 --- 7 files changed, 145 insertions(+), 57 deletions(-) create mode 100644 Jukcraft/src/renderer/chunk/Mesh.cpp create mode 100644 Jukcraft/src/renderer/chunk/Mesh.h diff --git a/Jukcraft/Jukcraft.vcxproj b/Jukcraft/Jukcraft.vcxproj index 2d44c6e..d626ac4 100644 --- a/Jukcraft/Jukcraft.vcxproj +++ b/Jukcraft/Jukcraft.vcxproj @@ -166,6 +166,7 @@ + @@ -193,6 +194,7 @@ Create + diff --git a/Jukcraft/Jukcraft.vcxproj.filters b/Jukcraft/Jukcraft.vcxproj.filters index 4aed35f..22b1469 100644 --- a/Jukcraft/Jukcraft.vcxproj.filters +++ b/Jukcraft/Jukcraft.vcxproj.filters @@ -130,6 +130,7 @@ world\chunk + @@ -179,5 +180,6 @@ world\chunk + \ No newline at end of file diff --git a/Jukcraft/src/renderer/chunk/Mesh.cpp b/Jukcraft/src/renderer/chunk/Mesh.cpp new file mode 100644 index 0000000..ce03918 --- /dev/null +++ b/Jukcraft/src/renderer/chunk/Mesh.cpp @@ -0,0 +1,90 @@ +#include "pch.h" +#include "renderer/chunk/Mesh.h" + +namespace Jukcraft { + static constexpr float smooth(float a, float b, float c, float d) { + if (!(a && b && c && d)) { + std::array l = { + a, + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity() + }; + if (b) + l[1] = b; + if (c) + l[2] = c; + if (d) + l[3] = d; + float min_val = *std::min_element(l.begin(), l.end()); + float a = std::max(a, min_val); + float b = std::max(b, min_val); + float c = std::max(c, min_val); + float d = std::max(d, min_val); + return a + b + c + d / 4.0f; + } + + } + + float ao(float s1, float s2, float c) { + if (s1 && s2) + return 0.25; + + return 1.0f - (s1 + s2 + c) / 4.0f; + } + + Mesh::Mesh(size_t size) :size(size) { + vbo.allocate(CHUNK_DIM * CHUNK_DIM * CHUNK_HEIGHT * 24, nullptr); + + vao.bindLayout(gfx::VertexArrayLayout{ + { + { 1, false }, + { 1, false } + } + }); + vao.bindVertexBuffer(vbo.getTargetBuffer(), 0, gfx::VertexBufferLayout{ + {{ 0, 0 }, { 1, offsetof(VertexData, lightData)}}, + 0, + sizeof(VertexData) + }); + vao.bindIndexBuffer(Renderer::GetChunkIbo()); + + icbo.allocate(sizeof(DrawIndirectCommand), nullptr); + } + + Mesh::~Mesh() { + + } + + void Mesh::begin() { + vbo.beginEditRegion(0, size); + quadCount = 0; + } + + void Mesh::pushQuad(const Quad& quad, const glm::uvec3& localPos, uint8_t textureID, uint8_t light) { + for (const Vertex& vertex : quad.vertices) { + uint32_t v = ((vertex.pos.y + localPos.y) << 22) | ((vertex.pos.x + localPos.x) << 17) | ((vertex.pos.z + localPos.z) << 12) | (vertex.texUV << 10) | (textureID << 2) | (vertex.shading); + vbo.push({ v, light }); + } + quadCount++; + } + + void Mesh::end() { + vbo.endEditRegion(); + DrawIndirectCommand cmd; + cmd.count = quadCount * 6; + cmd.instanceCount = 1; + cmd.firstIndex = 0; + cmd.baseVertex = 0; + cmd.baseInstance = 0; + icbo.beginEditRegion(0, 1); + icbo.editRegion(0, 1, &cmd); + icbo.endEditRegion(); + } + + void Mesh::draw() { + Renderer::MultiDrawElementsIndirect(vao, icbo.getTargetBuffer()); + } + + +} \ No newline at end of file diff --git a/Jukcraft/src/renderer/chunk/Mesh.h b/Jukcraft/src/renderer/chunk/Mesh.h new file mode 100644 index 0000000..952d359 --- /dev/null +++ b/Jukcraft/src/renderer/chunk/Mesh.h @@ -0,0 +1,25 @@ +#pragma once +#include "renderer/gfx/buffers/DynamicBuffer.h" +#include "blocks/Block.h" + +namespace Jukcraft { + + class Mesh { + public: + Mesh(size_t size); + ~Mesh(); + void begin(); + void pushQuad(const Quad& quad, const glm::uvec3& localPos, uint8_t textureID, uint8_t light); + void end(); + void draw(); + private: + size_t size; + size_t quadCount; + gfx::VertexArray vao; + + gfx::DynamicBuffer vbo; + gfx::DynamicBuffer icbo; + std::vector vertices; + std::vector indices; + }; +} \ No newline at end of file diff --git a/Jukcraft/src/world/chunk/Chunk.cpp b/Jukcraft/src/world/chunk/Chunk.cpp index ced1a24..2fa6e71 100644 --- a/Jukcraft/src/world/chunk/Chunk.cpp +++ b/Jukcraft/src/world/chunk/Chunk.cpp @@ -2,9 +2,12 @@ #include "renderer/Renderer.h" #include "world/chunk/Chunk.h" + namespace Jukcraft { + + Chunk::Chunk(const glm::ivec2& chunkPos, const std::vector& blockTypes) - :blockTypes(blockTypes), chunkPos(chunkPos) + :blockTypes(blockTypes), chunkPos(chunkPos), mesh(CHUNK_DIM * CHUNK_DIM * CHUNK_HEIGHT * 6 * 4) { blocks = new BlockID * *[CHUNK_HEIGHT]; for (size_t j = 0; j < CHUNK_HEIGHT; j++) { @@ -15,6 +18,17 @@ namespace Jukcraft { } } + for (uint8_t ly = 0; ly < CHUNK_HEIGHT / 2; ly++) + for (uint8_t lx = 0; lx < CHUNK_DIM; lx++) + for (uint8_t lz = 0; lz < CHUNK_DIM; lz++) { + if (ly == CHUNK_HEIGHT / 2 - 1) + setBlock(glm::uvec3(lx, ly, lz), 2); + else if (ly >= CHUNK_HEIGHT / 2 - 3 && ly < CHUNK_HEIGHT / 2 - 1) + setBlock(glm::uvec3(lx, ly, lz), 3); + else + setBlock(glm::uvec3(lx, ly, lz), 1); + } + lightMap = new uint8_t * *[CHUNK_HEIGHT]; for (size_t j = 0; j < CHUNK_HEIGHT; j++) { lightMap[j] = new uint8_t * [CHUNK_DIM]; @@ -24,22 +38,6 @@ namespace Jukcraft { } } - vbo.allocate(CHUNK_DIM * CHUNK_DIM * CHUNK_HEIGHT * 24, nullptr); - - vao.bindLayout(gfx::VertexArrayLayout{ - { - { 1, false }, - { 1, false } - } - }); - vao.bindVertexBuffer(vbo.getTargetBuffer(), 0, gfx::VertexBufferLayout{ - {{ 0, 0 }, { 1, offsetof(VertexData, lightData)}}, - 0, - sizeof(VertexData) - }); - vao.bindIndexBuffer(Renderer::GetChunkIbo()); - - icbo.allocate(sizeof(DrawIndirectCommand), nullptr); } Chunk::~Chunk() { @@ -68,16 +66,10 @@ namespace Jukcraft { } - void Chunk::pushQuad(const Quad& quad, const glm::uvec3& localPos, uint8_t textureID, uint8_t light) { - for (const Vertex& vertex : quad.vertices) { - uint32_t v = ((vertex.pos.y + localPos.y) << 22) | ((vertex.pos.x + localPos.x) << 17) | ((vertex.pos.z + localPos.z) << 12) | (vertex.texUV << 10) | (textureID << 2) | (vertex.shading); - vbo.push({ v, light }); - } - } void Chunk::buildCubeLayer() { - vbo.beginEditRegion(0, CHUNK_DIM * CHUNK_DIM * CHUNK_HEIGHT * 24); - uint32_t quad_count = 0; + mesh.begin(); + uint32_t quadCount = 0; for (uint8_t y = 0; y < CHUNK_HEIGHT; y++) for (uint8_t x = 0; x < CHUNK_DIM; x++) for (uint8_t z = 0; z < CHUNK_DIM; z++) { @@ -96,24 +88,16 @@ namespace Jukcraft { Chunk* neighbourChunk = getNeighbourChunk(localPos + IDIRECTIONS[i]); if (neighbourChunk) light = neighbourChunk->getRawLight(ToLocalPos(localPos + IDIRECTIONS[i])); - pushQuad(type.getModel().getQuads()[i], localPos, type.getTextureLayout()[i], light); - quad_count++; + mesh.pushQuad(type.getModel().getQuads()[i], localPos, type.getTextureLayout()[i], light); + quadCount++; } } } } - vbo.endEditRegion(); - - DrawIndirectCommand cmd; - cmd.count = quad_count * 6; - cmd.instanceCount = 1; - cmd.firstIndex = 0; - cmd.baseVertex = 0; - cmd.baseInstance = 0; - icbo.beginEditRegion(0, 1); - icbo.editRegion(0, 1, &cmd); - icbo.endEditRegion(); + mesh.end(); + + drawable = true; } @@ -143,6 +127,6 @@ namespace Jukcraft { void Chunk::drawCubeLayer() { if (!drawable) return; - Renderer::MultiDrawElementsIndirect(vao, icbo.getTargetBuffer()); + mesh.draw(); } } \ No newline at end of file diff --git a/Jukcraft/src/world/chunk/Chunk.h b/Jukcraft/src/world/chunk/Chunk.h index 352bdef..b56ea1c 100644 --- a/Jukcraft/src/world/chunk/Chunk.h +++ b/Jukcraft/src/world/chunk/Chunk.h @@ -1,7 +1,6 @@ #pragma once #include "renderer/Renderer.h" -#include "renderer/gfx/buffers/DynamicBuffer.h" -#include "blocks/Block.h" +#include "renderer/chunk/Mesh.h" #include namespace Jukcraft { @@ -99,7 +98,6 @@ namespace Jukcraft { lightMap[(uint8_t)localPos.y][(uint8_t)localPos.x][(uint8_t)localPos.z] = (lightMap[(uint8_t)localPos.y][(uint8_t)localPos.x][(uint8_t)localPos.z] & 0xF) | (value << 4); } private: - void pushQuad(const Quad& quad, const glm::uvec3& localPos, uint8_t textureID, uint8_t light); struct { std::weak_ptr east; std::weak_ptr west; @@ -111,13 +109,10 @@ namespace Jukcraft { uint8_t*** lightMap; + Mesh mesh; + const std::vector& blockTypes; - gfx::VertexArray vao; - gfx::DynamicBuffer vbo; - gfx::DynamicBuffer icbo; - std::vector vertices; - std::vector indices; bool drawable = false; glm::ivec2 chunkPos; diff --git a/Jukcraft/src/world/chunk/ChunkManager.cpp b/Jukcraft/src/world/chunk/ChunkManager.cpp index 38e8a55..0dfd330 100644 --- a/Jukcraft/src/world/chunk/ChunkManager.cpp +++ b/Jukcraft/src/world/chunk/ChunkManager.cpp @@ -12,16 +12,6 @@ namespace Jukcraft { = std::make_shared(glm::ivec2(x, z), blocks); chunksToUpdates.insert(chunk); chunksToLight.insert(chunk); - for (uint8_t ly = 0; ly < CHUNK_HEIGHT / 2; ly++) - for (uint8_t lx = 0; lx < CHUNK_DIM; lx++) - for (uint8_t lz = 0; lz < CHUNK_DIM; lz++) { - if (ly == CHUNK_HEIGHT / 2 - 1) - chunk->setBlock(glm::uvec3(lx, ly, lz), std::rand() % 2 ? 2 : 0); - else if (ly >= CHUNK_HEIGHT / 2 - 3 && ly < CHUNK_HEIGHT / 2 - 1) - chunk->setBlock(glm::uvec3(lx, ly, lz), std::rand() % 2 ? 3 : 0); - else - chunk->setBlock(glm::uvec3(lx, ly, lz), std::rand() % 2 ? 1 : 0); - } if (z > 0) { std::shared_ptr& northernChunk = chunks[x][z - 1]; northernChunk->neighbourChunks.south = chunk;