procedural chunk loading

This commit is contained in:
Tyler Murphy 2022-09-27 17:03:43 -04:00
parent 965ff9cc09
commit 9b60b862e5
12 changed files with 89 additions and 60 deletions

View file

@ -32,24 +32,6 @@ void Engine::loadDescriptorPool() {
.build();
}
Model* Engine::loadModelFromFile(const std::string &filename) {
return Model::createModelFromFile(xeDevice, filename);
}
Model* Engine::loadModelFromData(std::vector<unsigned char> vertexData, uint32_t vertexSize, std::vector<uint32_t> indices) {
Model::Builder builder{};
builder.vertexData.data = vertexData;
builder.vertexSize = vertexSize;
if(indices.size() > 0) {
builder.indices = indices;
}
return new Model(xeDevice, builder);
}
Image* Engine::loadImageFromFile(const std::string &filename, bool anisotropic) {
return new Image(xeDevice, filename, anisotropic);
}
bool Engine::poll() {
glfwPollEvents();
auto newTime = std::chrono::high_resolution_clock::now();

View file

@ -1,13 +1,12 @@
#pragma once
#include "xe_buffer.hpp"
#include "xe_device.hpp"
#include "xe_renderer.hpp"
#include "xe_camera.hpp"
#include "xe_descriptors.hpp"
#include "xe_image.hpp"
#include "xe_input.hpp"
#include "xe_sound.hpp"
#include "xe_model.hpp"
#include <chrono>
#include <string>
@ -30,11 +29,6 @@ class Engine {
Input& getInput() {return xeInput;}
Camera& getCamera() {return xeCamera;}
Device& getDevice() {return xeDevice;}
Model* loadModelFromFile(const std::string &filename);
Model* loadModelFromData(std::vector<unsigned char> vertexData, uint32_t vertexSize, std::vector<uint32_t> indices);
Image* loadImageFromFile(const std::string &filename, bool anisotropic = true);
bool beginFrame() { return xeRenderer.beginFrame(); }
void endFrame() { xeRenderer.endFrame(); }
@ -63,6 +57,8 @@ class Engine {
std::unique_ptr<DescriptorPool> xeDescriptorPool;
friend class RenderSystem;
friend class Image;
friend class Model;
};
}

View file

@ -1,4 +1,5 @@
#include "xe_image.hpp"
#include "xe_engine.hpp"
#include <vulkan/vulkan.h>
#include <stdexcept>
@ -10,7 +11,7 @@
namespace xe {
Image::Image(Device &xeDevice, const std::string &filename, bool anisotropic) : xeDevice{xeDevice} {
Image::Image(const std::string &filename, bool anisotropic) : xeDevice{Engine::getInstance()->xeDevice} {
createTextureImage(filename);
createTextureImageView();
createTextureSampler(anisotropic);

View file

@ -10,7 +10,7 @@ class Image {
public:
Image(Device &xeDevice, const std::string &filename, bool anisotropic);
Image(const std::string &filename, bool anisotropic);
~Image();
Image(const Image&) = delete;

View file

@ -1,4 +1,5 @@
#include "xe_model.hpp"
#include "xe_engine.hpp"
#define TINYOBJLOADER_IMPLEMENTATION
#include "xe_obj_loader.hpp"
@ -13,17 +14,17 @@
namespace xe {
Model::Model(Device &device, const Model::Builder &builder) : xeDevice{device} {
Model::Model(const Model::Builder &builder) : xeDevice{Engine::getInstance()->xeDevice} {
createVertexBuffers(builder.vertexData.data, builder.vertexSize);
createIndexBuffers(builder.indices);
}
Model::~Model() {}
Model* Model::createModelFromFile(Device &device, const std::string &filepath) {
Model* Model::createModelFromFile(const std::string &filepath) {
Builder builder{};
builder.loadModel(filepath);
return new Model(device, builder);
return new Model(builder);
}
void Model::createVertexBuffers(const std::vector<unsigned char> &vertexData, uint32_t vertexSize) {

View file

@ -34,13 +34,13 @@ class Model {
void loadModel(const std::string &filepath);
};
Model(Device &device, const Model::Builder &builder);
Model(const Model::Builder &builder);
~Model();
Model(const Model &) = delete;
Model operator=(const Model &) = delete;
static Model* createModelFromFile(Device &device, const std::string &filepath);
static Model* createModelFromFile(const std::string &filepath);
void bind(VkCommandBuffer commandBuffer);
void draw(VkCommandBuffer commandBuffer);

View file

@ -1,7 +1,6 @@
#pragma once
#include "xe_device.hpp"
#include "xe_game_object.hpp"
#include "xe_swap_chain.hpp"
#include "xe_descriptors.hpp"
#include "xe_window.hpp"

View file

@ -16,14 +16,14 @@ Chunk::Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed)
}
Chunk::~Chunk() {
if(chunkMesh != nullptr)
delete chunkMesh;
if(worker.joinable())
worker.join();
if(chunkMesh != nullptr)
delete chunkMesh;
}
//
// CHUNK CREATION AND DELETION
// CHUNK CREATION, DELETION, AND RETREVAL
//
static std::map<std::pair<int32_t, int32_t>, Chunk*> chunks{};
@ -38,10 +38,17 @@ Chunk* Chunk::getChunk(int32_t gridX, int32_t gridZ) {
if(chunks.count({gridX, gridZ})) {
return chunks[{gridX, gridZ}];
} else {
return NULL;
return nullptr;
}
}
void Chunk::deleteChunk(int32_t gridX, int32_t gridZ) {
Chunk* chunk = getChunk(gridX, gridZ);
if(chunk == nullptr) return; // Chunk does not exist or is already deleted
delete chunk;
chunks.erase({gridX, gridZ});
}
//
// CHUNK TEXTURE AND BLOCK LOADING
//
@ -51,7 +58,7 @@ static std::map<std::string, uint32_t> texturesIds{};
static std::vector<xe::Image*> textures{};
void loadTexture(const std::string& filePath) {
xe::Image* image = xe::Engine::getInstance()->loadImageFromFile(filePath, false);
xe::Image* image = new xe::Image(filePath, false);
texturesIds[filePath] = static_cast<uint32_t>(textures.size());
textures.push_back(image);
}
@ -88,12 +95,15 @@ void Chunk::unload() {
//
void Chunk::createMeshAsync(Chunk* c) {
if(c == nullptr) return;
if(c->working) return;
if(c->worker.joinable())
c->worker.join();
c->worker = std::thread(createMesh, c);
}
void Chunk::createMesh(Chunk* c) {
c->working = true;
if(c == nullptr) return;
c->vertexData.data.clear();
for(int32_t x=0;x<16;x++) {
for(int32_t y=0; y<256; y++) {
@ -152,7 +162,7 @@ xe::Model* Chunk::getMesh() {
xe::Model::Builder builder{};
builder.vertexData = vertexData;
builder.vertexSize = 36;
chunkMesh = new xe::Model(xe::Engine::getInstance()->getDevice(), builder);
chunkMesh = new xe::Model(builder);
reloadRequired = false;
}
return chunkMesh;

View file

@ -39,6 +39,7 @@ class Chunk {
static Chunk* newChunk(int32_t gridX, int32_t gridZ, uint32_t world_seed);
static Chunk* getChunk(int32_t gridX, int32_t gridZ);
static void deleteChunk(int32_t gridX, int32_t gridZ);
static void createMesh(Chunk* c);
static void createMeshAsync(Chunk* c);

View file

@ -1,5 +1,4 @@
#include "first_app.hpp"
#include "chunk.hpp"
namespace app {
@ -11,15 +10,11 @@ void FirstApp::run() {
Chunk::load();
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));
}
}
auto viewerObject = xe::GameObject::createGameObject();
viewerObject.transform.translation = {0.f, 10.f, 0.f};
viewerObject.transform.rotation.y = glm::radians(45.f);
createGameObjects(viewerObject);
SimpleRenderer renderer{xeEngine, Chunk::getTextures()};
@ -27,9 +22,6 @@ void FirstApp::run() {
sound.setLooping(true);
sound.play();
auto viewerObject = xe::GameObject::createGameObject();
viewerObject.transform.translation = {0.f, 10.f, 0.f};
viewerObject.transform.rotation.y = glm::radians(45.f);
KeyboardMovementController cameraController{xeEngine.getInput(), viewerObject};
while (xeEngine.poll()) {
@ -40,10 +32,12 @@ void FirstApp::run() {
xeEngine.getCamera().setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);
if(xeEngine.beginFrame()) {
renderer.render(gameObjects, xeEngine.getCamera());
renderer.render(loadedChunks, xeEngine.getCamera());
xeEngine.endFrame();
}
reloadLoadedChunks(viewerObject);
}
xeEngine.close();
@ -52,4 +46,46 @@ void FirstApp::run() {
}
void FirstApp::createGameObjects(xe::GameObject& viewer) {
int width = 2*RENDER_DISTANCE+1;
loadedChunks.clear();
for(int32_t x = 0; x < width; x++) {
for(int32_t z = 0; z < width; z++) {
auto gameObject = xe::GameObject::createGameObject();
gameObject.transform.translation = glm::vec3(0.f);
loadedChunks.push_back(std::move(gameObject));
}
}
}
void FirstApp::reloadLoadedChunks(xe::GameObject& viewer) {
viewX = static_cast<int>(floor(viewer.transform.translation.x / 16.f));
viewZ = static_cast<int>(floor(viewer.transform.translation.z / 16.f));
int width = 2*RENDER_DISTANCE+1;
int minX = viewX - RENDER_DISTANCE;
int minZ = viewZ - RENDER_DISTANCE;
int maxX = viewX + RENDER_DISTANCE;
int maxZ = viewZ + RENDER_DISTANCE;
for(int32_t x = 0; x < width; x++) {
for(int32_t z = 0; z < width; z++) {
auto& gameObject = loadedChunks[x + z * width];
int gridX = static_cast<int>(floor(gameObject.transform.translation.x / 16.f));
int gridZ = static_cast<int>(floor(gameObject.transform.translation.z / 16.f));
int newGridX = minX + x;
int newGridZ = minZ + z;
if(gridX < minX || gridZ < minZ || gridX > maxX || gridZ > maxZ)
Chunk::deleteChunk(gridX, gridZ);
Chunk* chunk = Chunk::getChunk(newGridX, newGridZ);
if(chunk == nullptr) {
chunk = Chunk::newChunk(newGridX, newGridZ, 12345);
Chunk::createMeshAsync(chunk);
Chunk::createMeshAsync(Chunk::getChunk(newGridX-1, newGridZ));
Chunk::createMeshAsync(Chunk::getChunk(newGridX, newGridZ+1));
}
gameObject.model = chunk->getMesh();
gameObject.transform.translation = glm::vec3(newGridX * 16.f, 0, newGridZ * 16.f);
}
}
}
}

View file

@ -4,6 +4,7 @@
#include "keyboard_movement_controller.hpp"
#include "simple_renderer.hpp"
#include "chunk.hpp"
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
@ -31,9 +32,15 @@ class FirstApp {
static constexpr int WIDTH = 800;
static constexpr int HEIGHT = 600;
static constexpr int RENDER_DISTANCE = 10;
void createGameObjects(xe::GameObject& viewer);
void reloadLoadedChunks(xe::GameObject& viewer);
int viewX, viewZ;
xe::Engine xeEngine;
std::vector<xe::GameObject> gameObjects;
std::vector<xe::GameObject> loadedChunks;
};
}

View file

@ -29,10 +29,6 @@ void SimpleRenderer::render(std::vector<xe::GameObject> &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);
}