From 80d32972133c128051e093f2a31128a7047e489e Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Sat, 8 Apr 2023 17:17:47 +0200 Subject: [PATCH] chunkmesher: keep a table of vertices to avoid duplicates --- include/chunk.hpp | 11 ++- include/chunkmesher.hpp | 4 + src/chunk.cpp | 11 ++- src/chunkgenerator.cpp | 2 +- src/chunkmesher.cpp | 179 +++++++++++++++++++++++----------------- 5 files changed, 124 insertions(+), 83 deletions(-) diff --git a/include/chunk.hpp b/include/chunk.hpp index 2fdc6e7..f0fff78 100644 --- a/include/chunk.hpp +++ b/include/chunk.hpp @@ -1,6 +1,8 @@ #ifndef CHUNK_H #define CHUNK_H +#define GLM_ENABLE_EXPERIMENTAL +#include #include #include #include @@ -8,6 +10,7 @@ #include #include #include +#include #include #include "block.hpp" @@ -15,7 +18,7 @@ #include "intervalmap.hpp" #include "shader.hpp" -#define CHUNK_SIZE 16 +#define CHUNK_SIZE 32 #define CHUNK_VOLUME (CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE) #define CHUNK_MAX_INDEX (CHUNK_VOLUME - 1) @@ -50,7 +53,7 @@ namespace Chunk std::unique_ptr getBlocksArray(int* len) { return (this->blocks.toArray(len)); } public: - GLuint VAO{0}, VBO{0}, EBO{0}, colorBuffer{0}, vIndex{0}; + GLuint VAO{0}, VBO{0}, EBO{0}, colorBuffer{0}, nIndices{0}; std::mutex mutex_state; @@ -58,6 +61,10 @@ namespace Chunk std::vector colors; std::vector indices; + std::unordered_map > vertices_map; // index, + // normal, + std::vector index_to_vertex; + private: glm::vec3 position{}; IntervalMap blocks{}; diff --git a/include/chunkmesher.hpp b/include/chunkmesher.hpp index 5f50b98..78bcda7 100644 --- a/include/chunkmesher.hpp +++ b/include/chunkmesher.hpp @@ -4,6 +4,10 @@ #include #include +#include +#include +#include + #include #include diff --git a/src/chunk.cpp b/src/chunk.cpp index c96f7ef..041710f 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -29,15 +29,18 @@ namespace Chunk Chunk ::~Chunk() { - glDeleteBuffers(1, &(this->colorBuffer)); - glDeleteBuffers(1, &(this->VBO)); - glDeleteBuffers(1, &(this->EBO)); - glDeleteVertexArrays(1, &(this->VAO)); + vertices_map.clear(); + index_to_vertex.clear(); vertices.clear(); indices.clear(); colors.clear(); + glDeleteBuffers(1, &(this->colorBuffer)); + glDeleteBuffers(1, &(this->VBO)); + glDeleteBuffers(1, &(this->EBO)); + glDeleteVertexArrays(1, &(this->VAO)); + mutex_state.unlock(); } diff --git a/src/chunkgenerator.cpp b/src/chunkgenerator.cpp index 8ff0d36..7bf5b0b 100644 --- a/src/chunkgenerator.cpp +++ b/src/chunkgenerator.cpp @@ -23,7 +23,7 @@ void generateNoise3D(Chunk::Chunk *chunk); void generateChunk(Chunk::Chunk *chunk) { - generateNoise3D(chunk); + generateNoise(chunk); } Block block; diff --git a/src/chunkmesher.cpp b/src/chunkmesher.cpp index 2821eca..c3a340c 100755 --- a/src/chunkmesher.cpp +++ b/src/chunkmesher.cpp @@ -1,6 +1,3 @@ -#include -#include - #include "block.hpp" #include "chunk.hpp" #include "chunkmesher.hpp" @@ -8,8 +5,15 @@ #include "spacefilling.hpp" #include "utils.hpp" +#include +#include +#include + + namespace chunkmesher{ +int indexCount{0}; + void mesh(Chunk::Chunk* chunk) { @@ -29,10 +33,13 @@ void mesh(Chunk::Chunk* chunk) */ // Cleanup previous data + chunk->vertices_map.clear(); + chunk->index_to_vertex.clear(); + indexCount = 0; chunk->vertices.clear(); chunk->indices.clear(); chunk->colors.clear(); - chunk->vIndex = 0; + chunk->nIndices = 0; // Abort if chunk is empty if(chunk->getState(Chunk::CHUNK_STATE_EMPTY)) return; @@ -184,8 +191,26 @@ void mesh(Chunk::Chunk* chunk) void sendtogpu(Chunk::Chunk* chunk) { - if (chunk->vIndex > 0) + if (chunk->indices.size() > 0) { + for(int i = 0; i < chunk->index_to_vertex.size(); i++){ + glm::vec3 v = chunk->index_to_vertex[i]; + auto t = chunk->vertices_map.at(v);; + glm::vec3 n = std::get<1>(t); + glm::vec3 c = std::get<2>(t); + + chunk->vertices.push_back(v.x); + chunk->vertices.push_back(v.y); + chunk->vertices.push_back(v.z); + + chunk->vertices.push_back(n.x); + chunk->vertices.push_back(n.y); + chunk->vertices.push_back(n.z); + + chunk->colors.push_back(c.x); + chunk->colors.push_back(c.y); + chunk->colors.push_back(c.z); + } // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). glBindVertexArray(chunk->VAO); @@ -215,9 +240,11 @@ void sendtogpu(Chunk::Chunk* chunk) glBindVertexArray(0); // save the number of indices of the mesh, it is needed later for drawing - chunk->vIndex = (GLuint)(chunk->indices.size()); + chunk->nIndices = (GLuint)(chunk->indices.size()); // once data has been sent to the GPU, it can be cleared from system RAM + chunk->vertices_map.clear(); + chunk->index_to_vertex.clear(); chunk->vertices.clear(); chunk->indices.clear(); chunk->colors.clear(); @@ -230,7 +257,7 @@ void sendtogpu(Chunk::Chunk* chunk) void draw(Chunk::Chunk* chunk, glm::mat4 model) { - // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // wireframe mode + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // wireframe mode if(chunk->getState(Chunk::CHUNK_STATE_MESH_LOADED)) { theShader->use(); @@ -239,7 +266,7 @@ void draw(Chunk::Chunk* chunk, glm::mat4 model) theShader->setMat4("projection", theCamera.getProjection()); glBindVertexArray(chunk->VAO); - glDrawElements(GL_TRIANGLES, chunk->vIndex , GL_UNSIGNED_INT, 0); + glDrawElements(GL_TRIANGLES, chunk->nIndices , GL_UNSIGNED_INT, 0); glBindVertexArray(0); } } @@ -248,86 +275,86 @@ void quad(Chunk::Chunk* chunk, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec glm::vec3 bottomRight, glm::vec3 normal, Block block, bool backFace) { - chunk->vertices.push_back(bottomLeft.x); - chunk->vertices.push_back(bottomLeft.y); - chunk->vertices.push_back(bottomLeft.z); - chunk->vertices.push_back(normal.x); - chunk->vertices.push_back(normal.y); - chunk->vertices.push_back(normal.z); - - chunk->vertices.push_back(bottomRight.x); - chunk->vertices.push_back(bottomRight.y); - chunk->vertices.push_back(bottomRight.z); - chunk->vertices.push_back(normal.x); - chunk->vertices.push_back(normal.y); - chunk->vertices.push_back(normal.z); - - chunk->vertices.push_back(topLeft.x); - chunk->vertices.push_back(topLeft.y); - chunk->vertices.push_back(topLeft.z); - chunk->vertices.push_back(normal.x); - chunk->vertices.push_back(normal.y); - chunk->vertices.push_back(normal.z); - - chunk->vertices.push_back(topRight.x); - chunk->vertices.push_back(topRight.y); - chunk->vertices.push_back(topRight.z); - chunk->vertices.push_back(normal.x); - chunk->vertices.push_back(normal.y); - chunk->vertices.push_back(normal.z); - - - if (backFace) - { - chunk->indices.push_back(chunk->vIndex + 2); - chunk->indices.push_back(chunk->vIndex); - chunk->indices.push_back(chunk->vIndex + 1); - chunk->indices.push_back(chunk->vIndex + 1); - chunk->indices.push_back(chunk->vIndex + 3); - chunk->indices.push_back(chunk->vIndex + 2); - } - else - { - chunk->indices.push_back(chunk->vIndex + 2); - chunk->indices.push_back(chunk->vIndex + 3); - chunk->indices.push_back(chunk->vIndex + 1); - chunk->indices.push_back(chunk->vIndex + 1); - chunk->indices.push_back(chunk->vIndex); - chunk->indices.push_back(chunk->vIndex + 2); - } - chunk->vIndex += 4; - // ugly switch case for colors - GLfloat r, g, b; + glm::vec3 color = glm::vec3(0.0f); switch (block) { case Block::STONE: - r = 0.588f; - g = 0.588f; - b = 0.588f; + color = glm::vec3(0.588f); break; case Block::GRASS: - r = 0.05f; - g = 0.725f; - b = 0.0f; + color = glm::vec3(0.05f, 0.725f, 0.0f); break; case Block::DIRT: - r = 0.152f; - g = 0.056f; - b = 0.056f; - break; - default: - r = 0.0f; - g = 0.0f; - b = 0.0f; + color = glm::vec3(0.152f, 0.056f, 0.056f); break; } - for (int i = 0; i < 4; i++) + int ibottomLeft, ibottomRight, itopLeft, itopRight; + + if(chunk->vertices_map.find(bottomLeft) == chunk->vertices_map.end()){ + chunk->index_to_vertex.push_back(bottomLeft); + ibottomLeft = indexCount++; + chunk->vertices_map[bottomLeft] = std::make_tuple(ibottomLeft, normal, color); + }else{ + auto vm = chunk->vertices_map[bottomLeft]; + ibottomLeft = std::get<0>(vm); + chunk->vertices_map[bottomLeft] = std::make_tuple(std::get<0>(vm), std::get<1>(vm) + normal, + std::get<2>(vm) + color); + } + + if(chunk->vertices_map.find(bottomRight) == chunk->vertices_map.end()){ + chunk->index_to_vertex.push_back(bottomRight); + ibottomRight = indexCount++; + chunk->vertices_map[bottomRight] = std::make_tuple(ibottomRight, normal, color); + }else{ + auto vm = chunk->vertices_map[bottomRight]; + ibottomRight = std::get<0>(vm); + chunk->vertices_map[bottomRight] = std::make_tuple(std::get<0>(vm), std::get<1>(vm) + normal, + std::get<2>(vm) + color); + } + + if(chunk->vertices_map.find(topLeft) == chunk->vertices_map.end()){ + chunk->index_to_vertex.push_back(topLeft); + itopLeft = indexCount++; + chunk->vertices_map[topLeft] = std::make_tuple(itopLeft, normal, color); + }else{ + auto vm = chunk->vertices_map[topLeft]; + itopLeft = std::get<0>(vm); + chunk->vertices_map[topLeft] = std::make_tuple(std::get<0>(vm), std::get<1>(vm) + normal, + std::get<2>(vm) + color); + } + + if(chunk->vertices_map.find(topRight) == chunk->vertices_map.end()){ + chunk->index_to_vertex.push_back(topRight); + itopRight = indexCount++; + chunk->vertices_map[topRight] = std::make_tuple(itopRight, normal, color); + }else{ + auto vm = chunk->vertices_map[topRight]; + itopRight = std::get<0>(vm); + chunk->vertices_map[topRight] = std::make_tuple(std::get<0>(vm), std::get<1>(vm) + normal, + std::get<2>(vm) + color); + } + + // bottomLeft, bottomRight, topLeft, topRight + if (backFace) + { + chunk->indices.push_back(itopLeft); + chunk->indices.push_back(ibottomLeft); + chunk->indices.push_back(ibottomRight); + chunk->indices.push_back(ibottomRight); + chunk->indices.push_back(itopRight); + chunk->indices.push_back(itopLeft); + } + else { - chunk->colors.push_back(r); - chunk->colors.push_back(g); - chunk->colors.push_back(b); + chunk->indices.push_back(itopLeft); + chunk->indices.push_back(itopRight); + chunk->indices.push_back(ibottomRight); + chunk->indices.push_back(ibottomRight); + chunk->indices.push_back(ibottomLeft); + chunk->indices.push_back(itopLeft); } } + };