From 965ff9cc09401ae61c15aca0232d59fac17bfce3 Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Tue, 27 Sep 2022 13:35:49 -0400 Subject: [PATCH] async chunk meshing --- engine/xe_engine.cpp | 6 +- engine/xe_engine.hpp | 5 +- engine/xe_game_object.hpp | 3 +- engine/xe_model.cpp | 4 +- engine/xe_model.hpp | 2 +- engine/xe_render_system.cpp | 2 + src/chunk.cpp | 223 +++++++++++++++++++++--------------- src/chunk.hpp | 25 ++-- src/first_app.cpp | 32 ++---- src/first_app.hpp | 2 - src/simple_renderer.cpp | 7 +- 11 files changed, 168 insertions(+), 143 deletions(-) diff --git a/engine/xe_engine.cpp b/engine/xe_engine.cpp index 44e5a4e..6392d78 100644 --- a/engine/xe_engine.cpp +++ b/engine/xe_engine.cpp @@ -32,18 +32,18 @@ void Engine::loadDescriptorPool() { .build(); } -std::shared_ptr Engine::loadModelFromFile(const std::string &filename) { +Model* Engine::loadModelFromFile(const std::string &filename) { return Model::createModelFromFile(xeDevice, filename); } -std::shared_ptr Engine::loadModelFromData(std::vector vertexData, uint32_t vertexSize, std::vector indices) { +Model* Engine::loadModelFromData(std::vector vertexData, uint32_t vertexSize, std::vector indices) { Model::Builder builder{}; builder.vertexData.data = vertexData; builder.vertexSize = vertexSize; if(indices.size() > 0) { builder.indices = indices; } - return std::make_shared(xeDevice, builder); + return new Model(xeDevice, builder); } Image* Engine::loadImageFromFile(const std::string &filename, bool anisotropic) { diff --git a/engine/xe_engine.hpp b/engine/xe_engine.hpp index 1a208d6..eff2d13 100644 --- a/engine/xe_engine.hpp +++ b/engine/xe_engine.hpp @@ -7,6 +7,7 @@ #include "xe_image.hpp" #include "xe_input.hpp" #include "xe_sound.hpp" +#include "xe_model.hpp" #include #include @@ -31,8 +32,8 @@ class Engine { Camera& getCamera() {return xeCamera;} Device& getDevice() {return xeDevice;} - std::shared_ptr loadModelFromFile(const std::string &filename); - std::shared_ptr loadModelFromData(std::vector vertexData, uint32_t vertexSize, std::vector indices); + Model* loadModelFromFile(const std::string &filename); + Model* loadModelFromData(std::vector vertexData, uint32_t vertexSize, std::vector indices); Image* loadImageFromFile(const std::string &filename, bool anisotropic = true); bool beginFrame() { return xeRenderer.beginFrame(); } diff --git a/engine/xe_game_object.hpp b/engine/xe_game_object.hpp index 7c4149e..7d7e698 100644 --- a/engine/xe_game_object.hpp +++ b/engine/xe_game_object.hpp @@ -37,8 +37,7 @@ class GameObject { id_t getId() { return id; } - std::shared_ptr model{}; - // glm::vec3 color{}; + Model* model{}; TransformComponent transform; private: diff --git a/engine/xe_model.cpp b/engine/xe_model.cpp index fd97f44..ff0d630 100644 --- a/engine/xe_model.cpp +++ b/engine/xe_model.cpp @@ -20,10 +20,10 @@ Model::Model(Device &device, const Model::Builder &builder) : xeDevice{device} { Model::~Model() {} -std::unique_ptr Model::createModelFromFile(Device &device, const std::string &filepath) { +Model* Model::createModelFromFile(Device &device, const std::string &filepath) { Builder builder{}; builder.loadModel(filepath); - return std::make_unique(device, builder); + return new Model(device, builder); } void Model::createVertexBuffers(const std::vector &vertexData, uint32_t vertexSize) { diff --git a/engine/xe_model.hpp b/engine/xe_model.hpp index 41dccd5..1886657 100644 --- a/engine/xe_model.hpp +++ b/engine/xe_model.hpp @@ -40,7 +40,7 @@ class Model { Model(const Model &) = delete; Model operator=(const Model &) = delete; - static std::unique_ptr createModelFromFile(Device &device, const std::string &filepath); + static Model* createModelFromFile(Device &device, const std::string &filepath); void bind(VkCommandBuffer commandBuffer); void draw(VkCommandBuffer commandBuffer); diff --git a/engine/xe_render_system.cpp b/engine/xe_render_system.cpp index f2f0e43..1ceff78 100644 --- a/engine/xe_render_system.cpp +++ b/engine/xe_render_system.cpp @@ -208,6 +208,8 @@ void RenderSystem::loadTextureArray(uint32_t binding, std::vector& image void RenderSystem::render(GameObject &gameObject) { + if(gameObject.model == nullptr) return; + gameObject.model->bind(xeRenderer.getCurrentCommandBuffer()); gameObject.model->draw(xeRenderer.getCurrentCommandBuffer()); diff --git a/src/chunk.cpp b/src/chunk.cpp index 1c15fa7..f9ddb54 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -1,16 +1,33 @@ #include "chunk.hpp" + namespace app { -static std::map, Chunk*> chunks{}; +// +// CHUNK CONSTRUCTORS AND DECONSTUCTORS +// Chunk::Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed) : world_seed{world_seed}, chunk_seed{(world_seed * gridX) + (world_seed * gridZ) / 2}, gridX{gridX}, gridZ{gridZ} { + chunkMesh = nullptr; generate(); } +Chunk::~Chunk() { + if(chunkMesh != nullptr) + delete chunkMesh; + if(worker.joinable()) + worker.join(); +} + +// +// CHUNK CREATION AND DELETION +// + +static std::map, Chunk*> chunks{}; + Chunk* Chunk::newChunk(int32_t gridX, int32_t gridZ, uint32_t world_seed) { Chunk* chunk = new Chunk(gridX, gridZ, world_seed); chunks[{gridX, gridZ}] = std::move(chunk); @@ -25,36 +42,9 @@ Chunk* Chunk::getChunk(int32_t gridX, int32_t gridZ) { } } -uint8_t Chunk::getBlock(int32_t x, int32_t y, int32_t z) { - if(y > 256) return AIR; - if(y < 0) return INVALID; - int chunkX = gridX; - int chunkZ = gridZ; - if(x < 0) { - chunkX--; - } else if(x > 15) { - chunkX++; - } - if(z < 0) { - chunkZ--; - } else if(z > 15) { - chunkZ++; - } - x = (x+16)%16; - z = (z+16)%16; - if(chunkX == gridX && chunkZ == gridZ) { - int index = x + (z * 16) + (y * 256); - return cubes[index]; - } else { - Chunk* chunk = getChunk(chunkX, chunkZ); - if(chunk == NULL) { - return INVALID; - } else { - int index = x + (z * 16) + (y * 256); - return chunk->cubes[index]; - } - } -} +// +// CHUNK TEXTURE AND BLOCK LOADING +// static std::map blocks{}; static std::map texturesIds{}; @@ -93,73 +83,120 @@ void Chunk::unload() { textures.clear(); } +// +// CHUNK MESH CREATION FOR BOTH SYNC AND ASYNC +// + +void Chunk::createMeshAsync(Chunk* c) { + if(c->working) return; + c->worker = std::thread(createMesh, c); +} + +void Chunk::createMesh(Chunk* c) { + c->working = true; + 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); + } + 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); + } + } + } + } + c->working = false; + c->reloadRequired = true; +} + +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 GETTERS AND SETTORS +// + +xe::Model* Chunk::getMesh() { + if(reloadRequired) { + if(chunkMesh != nullptr) + delete chunkMesh; + if(worker.joinable()) + worker.join(); + xe::Model::Builder builder{}; + builder.vertexData = vertexData; + builder.vertexSize = 36; + chunkMesh = new xe::Model(xe::Engine::getInstance()->getDevice(), builder); + reloadRequired = false; + } + return chunkMesh; +} + +uint8_t Chunk::getBlock(int32_t x, int32_t y, int32_t z) { + if(y > 256) return AIR; + if(y < 0) return INVALID; + int chunkX = gridX; + int chunkZ = gridZ; + if(x < 0) { + chunkX--; + } else if(x > 15) { + chunkX++; + } + if(z < 0) { + chunkZ--; + } else if(z > 15) { + chunkZ++; + } + x = (x+16)%16; + z = (z+16)%16; + if(chunkX == gridX && chunkZ == gridZ) { + int index = x + (z * 16) + (y * 256); + return cubes[index]; + } else { + Chunk* chunk = getChunk(chunkX, chunkZ); + if(chunk == NULL) { + return INVALID; + } else { + int index = x + (z * 16) + (y * 256); + return chunk->cubes[index]; + } + } +} + void Chunk::setBlock(int32_t x, int32_t y, int32_t z, uint8_t block) { int index = x + (z * 16) + (y * 256); cubes[index] = block; } -std::shared_ptr Chunk::getMesh() { - if(reloadRequired) { - delete chunkMesh.get(); - xe::Model::Builder builder{}; - builder.vertexData = vertexData; - builder.vertexSize = 36; - chunkMesh = std::make_shared(xe::Engine::getInstance()->getDevice(), builder); - } - return chunkMesh; -} - -void Chunk::createMeshAsync() { - if(working) return; - // worker = std::thread(createMesh); -} - -void Chunk::createMesh() { - working = true; - 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 = getBlock(x,y,z); - if(block == AIR) continue; - if(getBlock(x+1,y,z) == AIR) { - addVerticies(0, x, y, z, block); - } - if(getBlock(x-1,y,z) == AIR) { - addVerticies(1, x, y, z, block); - } - if(getBlock(x,y+1,z) == AIR) { - addVerticies(2, x, y, z, block); - } - if(getBlock(x,y-1,z) == AIR) { - addVerticies(3, x, y, z, block); - } - if(getBlock(x,y,z+1) == AIR) { - addVerticies(4, x, y, z, block); - } - if(getBlock(x,y,z-1) == AIR) { - addVerticies(5, x, y, z, block); - } - } - } - } - working = false; - reloadRequired = true; -} - -void Chunk::addVerticies(uint8_t side, int32_t x, int32_t y, int32_t z, uint8_t block) { - for(int i = 0; i < 6; i ++) { - vertexData.write(px[side * 6 + i][0] + x); - vertexData.write(px[side * 6 + i][1] + y); - vertexData.write(px[side * 6 + i][2] + z); - vertexData.write(nm[side][0]); - vertexData.write(nm[side][1]); - vertexData.write(nm[side][2]); - vertexData.write(uv[i][0]); - vertexData.write(uv[i][1]); - vertexData.write(static_cast(blocks[block].textures[side])); - } -} +// +// CHUNK GENERATION +// void Chunk::generate() { cubes.resize(16*16*256); diff --git a/src/chunk.hpp b/src/chunk.hpp index e2cfab5..c506ca0 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -38,31 +38,30 @@ class Chunk { static std::vector& getTextures(); static Chunk* newChunk(int32_t gridX, int32_t gridZ, uint32_t world_seed); + static Chunk* getChunk(int32_t gridX, int32_t gridZ); - Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed); - ~Chunk() {}; + static void createMesh(Chunk* c); + static void createMeshAsync(Chunk* c); + + xe::Model* getMesh(); + uint8_t getBlock(int32_t x, int32_t y, int32_t z); + void setBlock(int32_t x, int32_t y, int32_t z, uint8_t block); const int32_t gridX, gridZ; const uint32_t world_seed, chunk_seed; - void createMesh(); - void createMeshAsync(); - std::shared_ptr getMesh(); - - uint8_t getBlock(int32_t x, int32_t y, int32_t z); - void setBlock(int32_t x, int32_t y, int32_t z, uint8_t block); - - static Chunk* getChunk(int32_t x, int32_t z); - private: + Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed); + ~Chunk(); + void generate(); - void addVerticies(uint8_t side, int32_t x, int32_t y, int32_t z, uint8_t block); + static void addVerticies(Chunk* c, uint8_t side, int32_t x, int32_t y, int32_t z, uint8_t block); bool reloadRequired{false}; bool working{false}; - std::shared_ptr chunkMesh; + xe::Model* chunkMesh; xe::Model::Data vertexData; std::vector cubes; std::thread worker; diff --git a/src/first_app.cpp b/src/first_app.cpp index 968f7f8..08f6f0c 100755 --- a/src/first_app.cpp +++ b/src/first_app.cpp @@ -11,7 +11,15 @@ void FirstApp::run() { Chunk::load(); - loadGameObjects(); + for(int32_t x = 0; x < 10; x++) { + for(int32_t z = 0; z < 10; z++) { + Chunk* chunk = Chunk::newChunk(x, z, 53463); + Chunk::createMeshAsync(chunk); + auto chunkObject = xe::GameObject::createGameObject(); + chunkObject.transform.translation = {16.f*x, 0.f, 16.f*z}; + gameObjects.push_back(std::move(chunkObject)); + } + } SimpleRenderer renderer{xeEngine, Chunk::getTextures()}; @@ -44,26 +52,4 @@ void FirstApp::run() { } -void FirstApp::loadGameObjects() { - - for(int32_t x = 0; x < 10; x++) { - for(int32_t z = 0; z < 10; z++) { - Chunk* chunk = Chunk::newChunk(x, z, 53463); - } - } - - for(int32_t x = 0; x < 10; x++) { - for(int32_t z = 0; z < 10; z++) { - Chunk* chunk = Chunk::getChunk(x,z); - chunk->createMesh(); - - auto chunkObject = xe::GameObject::createGameObject(); - chunkObject.model = chunk->getMesh(); - chunkObject.transform.translation = {16.f*x, 0.f, 16.f*z}; - gameObjects.push_back(std::move(chunkObject)); - } - } - -} - } \ No newline at end of file diff --git a/src/first_app.hpp b/src/first_app.hpp index 87cedba..3339b04 100755 --- a/src/first_app.hpp +++ b/src/first_app.hpp @@ -32,8 +32,6 @@ class FirstApp { static constexpr int WIDTH = 800; static constexpr int HEIGHT = 600; - void loadGameObjects(); - xe::Engine xeEngine; std::vector gameObjects; diff --git a/src/simple_renderer.cpp b/src/simple_renderer.cpp index 17f7b57..22046be 100644 --- a/src/simple_renderer.cpp +++ b/src/simple_renderer.cpp @@ -1,4 +1,5 @@ #include "simple_renderer.hpp" +#include "chunk.hpp" namespace app { @@ -18,8 +19,6 @@ SimpleRenderer::SimpleRenderer(xe::Engine &xeEngine, std::vector &im void SimpleRenderer::render(std::vector &gameObjects, xe::Camera &xeCamera) { - // xeRenderSystem->loadTexture(1, xeImage); - xeRenderSystem->start(); UniformBuffer ubo{}; @@ -30,6 +29,10 @@ void SimpleRenderer::render(std::vector &gameObjects, xe::Camera PushConstant pc{}; pc.modelMatrix = obj.transform.mat4(); pc.normalMatrix = obj.transform.normalMatrix(); + + Chunk* chunk = Chunk::getChunk(obj.transform.translation.x/16.f, obj.transform.translation.z/16.f); + obj.model = chunk->getMesh(); + xeRenderSystem->loadPushConstant(&pc); xeRenderSystem->render(obj); }