From 5d3b1bc1752e1e684bad8c0a8a1e11be99493e5e Mon Sep 17 00:00:00 2001 From: tylermurphy534 Date: Fri, 30 Sep 2022 00:25:12 -0400 Subject: [PATCH] greedy meshing --- engine/xe_image.cpp | 6 +- src/chunk.cpp | 193 ++++++++++++++++++++++++++++++++-------- src/chunk.hpp | 68 +------------- src/first_app.cpp | 4 +- src/first_app.hpp | 2 +- src/simple_renderer.cpp | 2 +- 6 files changed, 162 insertions(+), 113 deletions(-) diff --git a/engine/xe_image.cpp b/engine/xe_image.cpp index cd53663..9d6bb9b 100644 --- a/engine/xe_image.cpp +++ b/engine/xe_image.cpp @@ -265,9 +265,9 @@ void Image::createTextureSampler(bool anisotropic) { samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.magFilter = VK_FILTER_NEAREST; samplerInfo.minFilter = VK_FILTER_NEAREST; - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.anisotropyEnable = anisotropic ? VK_TRUE : VK_FALSE; samplerInfo.maxAnisotropy = xeDevice.getAnisotropy(); samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; diff --git a/src/chunk.cpp b/src/chunk.cpp index 41f8014..0ff98b0 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -35,11 +35,11 @@ Chunk* Chunk::newChunk(int32_t gridX, int32_t gridZ, uint32_t world_seed) { } Chunk* Chunk::getChunk(int32_t gridX, int32_t gridZ) { - if(chunks.count({gridX, gridZ})) { - return chunks[{gridX, gridZ}]; - } else { - return nullptr; + auto it = chunks.find({gridX, gridZ}); + if(it != chunks.end()) { + return it->second; } + return nullptr; } void Chunk::deleteChunk(int32_t gridX, int32_t gridZ) { @@ -106,6 +106,57 @@ void Chunk::createMeshAsync(Chunk* c) { c->worker = std::thread(createMesh, c); } +struct FMask { + int block; + int normal; +}; + +bool CompareMask(FMask a, FMask b){ + if(a.block == INVALID || b.block == INVALID) return false; + return a.block == b.block && a.normal == b.normal; +} + +void AddVertex(xe::Model::Data& data, glm::vec3 Pos, glm::vec3 Nor, FMask Mask, glm::vec3 AxisMask, float Uv[2]) { + data.write(Pos[0]); + data.write(Pos[1]); + data.write(Pos[2]); + data.write(Nor[0]); + data.write(Nor[1]); + data.write(Nor[2]); + data.write(Uv[0]); + data.write(Uv[1]); + + int i = AxisMask[1]*2+AxisMask[2]*4+(Mask.normal<0?1:0); + data.write(blocks[Mask.block].textures[i]); +} + +void CreateQuad(xe::Model::Data& data, FMask Mask, glm::vec3 AxisMask, glm::vec3 V1, glm::vec3 V2, glm::vec3 V3, glm::vec3 V4, uint32_t width, uint32_t height) { + const auto Normal = glm::vec3(AxisMask) * glm::vec3(Mask.normal); + std::vector verticies = {V1, V2, V3, V4}; + + float uv[4][2]; + + if (AxisMask[0] == 1) { + uv[0][0] = width; uv[0][1] = height; + uv[1][0] = 0; uv[1][1] = height; + uv[2][0] = width; uv[2][1] = 0; + uv[3][0] = 0; uv[3][1] = 0; + } else { + uv[0][0] = height; uv[0][1] = width; + uv[1][0] = height; uv[1][1] = 0; + uv[2][0] = 0; uv[2][1] = width; + uv[3][0] = 0; uv[3][1] = 0; + } + + AddVertex(data, verticies[0], Normal, Mask, AxisMask, uv[0]); + AddVertex(data, verticies[2 + Mask.normal], Normal, Mask, AxisMask, uv[3]); + AddVertex(data, verticies[2 - Mask.normal], Normal, Mask, AxisMask, uv[2]); + AddVertex(data, verticies[3], Normal, Mask, AxisMask, uv[3]); + AddVertex(data, verticies[1 - Mask.normal], Normal, Mask, AxisMask, uv[0]); + AddVertex(data, verticies[1 + Mask.normal], Normal, Mask, AxisMask, uv[1]); + +} + void Chunk::createMesh(Chunk* c) { if(c == nullptr) return; if(!isGenerated(c->gridX-1, c->gridZ) || @@ -116,50 +167,114 @@ void Chunk::createMesh(Chunk* c) { return; } c->vertexData.data.clear(); - for(int32_t x=0;x<16;x++) { - for(int32_t y=0; y<256; y++) { - for(int32_t z=0; z<16; z++) { - uint8_t block = c->getBlock(x,y,z); - if(block == AIR) continue; - if(c->getBlock(x+1,y,z) == AIR) { - c->addVerticies(c, 0, x, y, z, block); + for (int Axis = 0; Axis < 3; ++Axis) { + const int Axis1 = (Axis + 1) % 3; + const int Axis2 = (Axis + 2) % 3; + + const int MainAxisLimit = Axis == 1 ? 256 : 16; + int Axis1Limit = Axis1 == 1 ? 256 : 16; + int Axis2Limit = Axis2 == 1 ? 256 : 16; + + auto DeltaAxis1 = glm::vec3(0.f); + auto DeltaAxis2 = glm::vec3(0.f); + + auto ChunkItr = glm::vec3(0.f); + auto AxisMask = glm::vec3(0.f); + + AxisMask[Axis] = 1; + + std::vector Mask; + Mask.resize(Axis1Limit * Axis2Limit); + + for (ChunkItr[Axis] = -1; ChunkItr[Axis] < MainAxisLimit;) { + int N = 0; + + for (ChunkItr[Axis2] = 0; ChunkItr[Axis2] < Axis2Limit; ++ChunkItr[Axis2]) { + for (ChunkItr[Axis1] = 0; ChunkItr[Axis1] < Axis1Limit; ++ChunkItr[Axis1]) { + const auto CurrentBlock = c->getBlock(ChunkItr[0], ChunkItr[1], ChunkItr[2]); + const auto CompareBlock = c->getBlock(ChunkItr[0] + AxisMask[0], ChunkItr[1] + AxisMask[1] , ChunkItr[2] + AxisMask[2]); + + const bool CurrentBlockOpaque = CurrentBlock != AIR; + const bool CompareBlockOpaque = CompareBlock != AIR; + + if (CurrentBlockOpaque == CompareBlockOpaque) { + Mask[N++] = FMask { INVALID, 0 }; + } else if (CurrentBlockOpaque) { + Mask[N++] = FMask { CurrentBlock, 1}; + } else { + Mask[N++] = FMask { CompareBlock, -1}; + } } - if(c->getBlock(x-1,y,z) == AIR) { - c->addVerticies(c, 1, x, y, z, block); - } - if(c->getBlock(x,y+1,z) == AIR) { - c->addVerticies(c, 2, x, y, z, block); - } - if(c->getBlock(x,y-1,z) == AIR) { - c->addVerticies(c, 3, x, y, z, block); - } - if(c->getBlock(x,y,z+1) == AIR) { - c->addVerticies(c, 4, x, y, z, block); - } - if(c->getBlock(x,y,z-1) == AIR) { - c->addVerticies(c, 5, x, y, z, block); + } + + ++ChunkItr[Axis]; + N = 0; + + for (int j = 0; j < Axis2Limit; ++j) { + for (int i = 0; i < Axis1Limit;) { + if(Mask[N].normal != 0) { + const auto CurrentMask = Mask[N]; + ChunkItr[Axis1] = i; + ChunkItr[Axis2] = j; + + int width; + + for(width = 1; i + width < Axis1Limit && CompareMask(Mask[N + width], CurrentMask); ++width) {} + + int height; + bool done = false; + + for (height = 1; j + height < Axis2Limit; ++height) { + for(int k = 0; k < width; ++k) { + if(CompareMask(Mask[N + k + height * Axis1Limit], CurrentMask)) continue; + + done = true; + break; + } + + if(done) break; + } + + DeltaAxis1[Axis1] = width; + DeltaAxis2[Axis2] = height; + + CreateQuad(c->vertexData, CurrentMask, AxisMask, + ChunkItr, + ChunkItr + DeltaAxis1, + ChunkItr + DeltaAxis2, + ChunkItr + DeltaAxis1 + DeltaAxis2, + height, + width + ); + + DeltaAxis1 = glm::vec3(0.f); + DeltaAxis2 = glm::vec3(0.f); + + for (int l = 0; l < height; ++l) { + for(int k = 0; k < width; ++k) { + Mask[N + k + l * Axis1Limit] = FMask { INVALID, 0 }; + } + } + + i += width; + N += width; + + } else { + + i++; + N++; + + } + } } } + } c->reload = true; c->working = false; } -void Chunk::addVerticies(Chunk* c, uint8_t side, int32_t x, int32_t y, int32_t z, uint8_t block) { - for(int i = 0; i < 6; i ++) { - c->vertexData.write(px[side * 6 + i][0] + x); - c->vertexData.write(px[side * 6 + i][1] + y); - c->vertexData.write(px[side * 6 + i][2] + z); - c->vertexData.write(nm[side][0]); - c->vertexData.write(nm[side][1]); - c->vertexData.write(nm[side][2]); - c->vertexData.write(uv[i][0]); - c->vertexData.write(uv[i][1]); - c->vertexData.write(static_cast(blocks[block].textures[side])); - } -} - // // CHUNK GENERATION FOR BOTH SYNC AND ASYNC // diff --git a/src/chunk.hpp b/src/chunk.hpp index 18230c8..59df514 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -77,81 +77,15 @@ class Chunk { Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed); ~Chunk(); - static void addVerticies(Chunk* c, uint8_t side, int32_t x, int32_t y, int32_t z, uint8_t block); - bool generated{false}; bool reload{false}; bool working{false}; xe::Model* chunkMesh; xe::Model::Data vertexData; - std::vector cubes; + std::vector cubes{}; std::thread worker; }; -const float px[36][3] = { - // POS X - {0.5f,0.5f,0.5f}, - {0.5f,-0.5f,0.5f}, - {0.5f,-0.5f,-0.5f}, - {0.5f,-0.5f,-0.5f}, - {0.5f,0.5f,-0.5f}, - {0.5f,0.5f,0.5f}, - // NEG X - {-0.5f,0.5f,-0.5f}, - {-0.5f,-0.5f,-0.5f}, - {-0.5f,-0.5f,0.5f}, - {-0.5f,-0.5f,0.5f}, - {-0.5f,0.5f,0.5f}, - {-0.5f,0.5f,-0.5f}, - // POS Y - {0.5f,0.5f,-0.5f}, - {-0.5f,0.5f,-0.5f}, - {-0.5f,0.5f,0.5f}, - {-0.5f,0.5f,0.5f}, - {0.5f,0.5f,0.5f}, - {0.5f,0.5f,-0.5f}, - // NEG Y - {-0.5f,-0.5f,0.5f}, - {-0.5f,-0.5f,-0.5f}, - {0.5f,-0.5f,-0.5f}, - {0.5f,-0.5f,-0.5f}, - {0.5f,-0.5f,0.5f}, - {-0.5f,-0.5f,0.5f}, - // POS Z - {-0.5f,0.5f,0.5f}, - {-0.5f,-0.5f,0.5f}, - {0.5f,-0.5f,0.5f}, - {0.5f,-0.5f,0.5f}, - {0.5f,0.5f,0.5f}, - {-0.5f,0.5f,0.5f}, - // NEG Z - {0.5f,0.5f,-0.5f}, - {0.5f,-0.5f,-0.5f}, - {-0.5f,-0.5f,-0.5f}, - {-0.5f,-0.5f,-0.5f}, - {-0.5f,0.5f,-0.5f}, - {0.5f,0.5f,-0.5f} -}; - -const float nm[6][3] = { - {1.f,0.f,0.f}, - {-1.f,0.f,0.f}, - {0.f,1.f,0.f}, - {0.f,-1.f,0.f}, - {0.f,0.f,1.f}, - {0.f,0.f,-1.f} -}; - - -const float uv[6][2] = { - {1.f,0.f}, - {1.f,1.f}, - {0.f,1.f}, - {0.f,1.f}, - {0.f,0.f}, - {1.f,0.f} -}; - } \ No newline at end of file diff --git a/src/first_app.cpp b/src/first_app.cpp index e677d06..619a810 100755 --- a/src/first_app.cpp +++ b/src/first_app.cpp @@ -11,7 +11,7 @@ void FirstApp::run() { Chunk::load(); auto viewerObject = xe::GameObject::createGameObject(); - viewerObject.transform.translation = {0.f, 10.f, 0.f}; + viewerObject.transform.translation = {0.f, 40.f, 0.f}; viewerObject.transform.rotation.y = glm::radians(45.f); createGameObjects(viewerObject); @@ -78,7 +78,7 @@ void FirstApp::reloadLoadedChunks(xe::GameObject& viewer) { Chunk* chunk = Chunk::getChunk(newGridX, newGridZ); if(chunk == nullptr) { chunk = Chunk::newChunk(newGridX, newGridZ, 12345); - Chunk::generateAsync(chunk); + Chunk::generate(chunk); } if(chunk->getMesh() == nullptr){ Chunk::createMeshAsync(chunk); diff --git a/src/first_app.hpp b/src/first_app.hpp index 3d97bad..59cf3df 100755 --- a/src/first_app.hpp +++ b/src/first_app.hpp @@ -32,7 +32,7 @@ class FirstApp { static constexpr int WIDTH = 800; static constexpr int HEIGHT = 600; - static constexpr int RENDER_DISTANCE = 25; + static constexpr int RENDER_DISTANCE = 45; void createGameObjects(xe::GameObject& viewer); void reloadLoadedChunks(xe::GameObject& viewer); diff --git a/src/simple_renderer.cpp b/src/simple_renderer.cpp index d13e7ac..95acdad 100644 --- a/src/simple_renderer.cpp +++ b/src/simple_renderer.cpp @@ -13,7 +13,7 @@ SimpleRenderer::SimpleRenderer(xe::Engine &xeEngine, std::vector &im .addPushConstant(sizeof(PushConstant)) .addUniformBinding(0, sizeof(UniformBuffer)) .addTextureArrayBinding(1, images) - .setCulling(true) + .setCulling(false) .build(); }