chunkmesher: external queue of chunk mesh data

instead of every chunk having its own queue

This decreases usage of ram
pull/1/head
EmaMaker 2023-05-20 21:19:44 +02:00
parent 78e3bc11e6
commit e225babb0c
11 changed files with 202 additions and 157 deletions

View File

@ -4,6 +4,7 @@ project(cmake-project-template)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g")
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}) set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR})

View File

@ -112,7 +112,7 @@ public:
private: private:
glm::vec3 cameraPos = glm::vec3(0.0, 80.0f, 0.0f); glm::vec3 cameraPos = glm::vec3(256.0, 80.0f, 256.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 direction = glm::vec3(0.0f); glm::vec3 direction = glm::vec3(0.0f);

View File

@ -56,12 +56,8 @@ namespace Chunk
std::unique_ptr<Block[]> getBlocksArray(int* len) { return (this->blocks.toArray(len)); } std::unique_ptr<Block[]> getBlocksArray(int* len) { return (this->blocks.toArray(len)); }
public: public:
GLuint VAO{0}, VBO{0}, EBO{0}, colorBuffer{0}, vIndex{0}; GLuint VAO{0}, VBO{0}, EBO{0}, colorBuffer{0}, numVertices{0};
std::atomic<float> unload_timer{0}; std::atomic<float> unload_timer{0};
std::vector<GLfloat> vertices;
std::vector<GLfloat> colors;
std::vector<GLuint> indices;
private: private:
glm::vec3 position{}; glm::vec3 position{};

View File

@ -6,6 +6,8 @@
#include <thread> #include <thread>
#include <oneapi/tbb/concurrent_queue.h>
#include "chunk.hpp" #include "chunk.hpp"
#include "globals.hpp" #include "globals.hpp"
@ -17,6 +19,7 @@ namespace chunkmanager
void stop(); void stop();
void destroy(); void destroy();
oneapi::tbb::concurrent_queue<Chunk::Chunk*>& getDeleteVector();
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices(); std::array<std::array<int, 3>, chunks_volume>& getChunksIndices();
void update(); void update();
} }

View File

@ -1,22 +1,29 @@
#ifndef CHUNKMESH_H #ifndef CHUNKMESH_H
#define CHUNKMESH_H #define CHUNKMESH_H
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <oneapi/tbb/concurrent_queue.h>
#include "chunk.hpp" #include "chunk.hpp"
#include "globals.hpp" #include "globals.hpp"
#include "shader.hpp" #include "shader.hpp"
namespace chunkmesher{ namespace chunkmesher{
void mesh(Chunk::Chunk* chunk); struct MeshData{
void sendtogpu(Chunk::Chunk* chunk); Chunk::Chunk* chunk;
void draw(Chunk::Chunk* chunk, glm::mat4 model); std::vector<GLfloat> vertices;
std::vector<GLfloat> colors;
std::vector<GLuint> indices;
};
oneapi::tbb::concurrent_queue<MeshData*>& getMeshDataQueue();
void quad(Chunk::Chunk* chunk, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec3 topRight, void mesh(Chunk::Chunk* chunk);
void sendtogpu(MeshData* mesh_data);
void quad(MeshData* mesh_data, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec3 topRight,
glm::vec3 bottomRight, glm::vec3 normal, Block block, int dim, bool backFace); glm::vec3 bottomRight, glm::vec3 normal, Block block, int dim, bool backFace);
} }

View File

@ -2,16 +2,21 @@
#define RENDERER_H #define RENDERER_H
#include <oneapi/tbb/concurrent_unordered_set.h> #include <oneapi/tbb/concurrent_unordered_set.h>
#include <oneapi/tbb/concurrent_queue.h>
#include "chunk.hpp" #include "chunk.hpp"
#include "chunkmesher.hpp"
#include "shader.hpp" #include "shader.hpp"
namespace renderer{ namespace renderer{
typedef oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*> RenderSet;
void init(); void init();
void render(); void render();
void destroy(); void destroy();
Shader* getRenderShader(); Shader* getRenderShader();
oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*>& getChunksToRender(); RenderSet& getChunksToRender();
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue();
}; };

View File

@ -23,10 +23,6 @@ namespace Chunk
Chunk ::~Chunk() Chunk ::~Chunk()
{ {
vertices.clear();
indices.clear();
colors.clear();
this->deleteBuffers();
} }
void Chunk::createBuffers(){ void Chunk::createBuffers(){

View File

@ -14,8 +14,8 @@
#define NOISE_DIRT_MIN 2 #define NOISE_DIRT_MIN 2
#define NOISE_DIRT_X_MULT 0.001f #define NOISE_DIRT_X_MULT 0.001f
#define NOISE_DIRT_Z_MULT 0.001f #define NOISE_DIRT_Z_MULT 0.001f
#define NOISE_GRASS_X_MULT 0.035f #define NOISE_GRASS_X_MULT 0.018f
#define NOISE_GRASS_Z_MULT 0.035f #define NOISE_GRASS_Z_MULT 0.018f
void generatePyramid(Chunk::Chunk *chunk); void generatePyramid(Chunk::Chunk *chunk);
void generateNoise(Chunk::Chunk *chunk); void generateNoise(Chunk::Chunk *chunk);
@ -56,10 +56,12 @@ void generateNoise(Chunk::Chunk *chunk)
int z = HILBERT_XYZ_DECODE[s][2] + CHUNK_SIZE * chunk->getPosition().z; int z = HILBERT_XYZ_DECODE[s][2] + CHUNK_SIZE * chunk->getPosition().z;
int d2 = HILBERT_XYZ_DECODE[s][0] * CHUNK_SIZE + HILBERT_XYZ_DECODE[s][2]; int d2 = HILBERT_XYZ_DECODE[s][0] * CHUNK_SIZE + HILBERT_XYZ_DECODE[s][2];
if (grassNoiseLUT[d2] == -1) if (grassNoiseLUT[d2] == -1){
grassNoiseLUT[d2] = GRASS_OFFSET + (int)((0.5 + noiseGen1.eval(x * NOISE_GRASS_X_MULT, z * NOISE_GRASS_Z_MULT) * NOISE_GRASS_MULT)); grassNoiseLUT[d2] = GRASS_OFFSET + (int)((0.5 + noiseGen1.eval(x * NOISE_GRASS_X_MULT, z * NOISE_GRASS_Z_MULT) * NOISE_GRASS_MULT));
if (dirtNoiseLUT[d2] == -1) }
if (dirtNoiseLUT[d2] == -1){
dirtNoiseLUT[d2] = NOISE_DIRT_MIN + (int)((0.5 + noiseGen2.eval(x * NOISE_DIRT_X_MULT, z * NOISE_DIRT_Z_MULT) * NOISE_DIRT_MULT)); dirtNoiseLUT[d2] = NOISE_DIRT_MIN + (int)((0.5 + noiseGen2.eval(x * NOISE_DIRT_X_MULT, z * NOISE_DIRT_Z_MULT) * NOISE_DIRT_MULT));
}
int grassNoise = grassNoiseLUT[d2]; int grassNoise = grassNoiseLUT[d2];
int dirtNoise = dirtNoiseLUT[d2]; int dirtNoise = dirtNoiseLUT[d2];

View File

@ -2,10 +2,12 @@
#include <atomic> #include <atomic>
#include <math.h> #include <math.h>
#include <vector>
#include <thread> #include <thread>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <oneapi/tbb/concurrent_hash_map.h> #include <oneapi/tbb/concurrent_hash_map.h>
#include "chunk.hpp" #include "chunk.hpp"
@ -23,6 +25,8 @@ namespace chunkmanager
std::array<std::array<int, 3>, chunks_volume> chunks_indices; std::array<std::array<int, 3>, chunks_volume> chunks_indices;
std::atomic_bool should_run; std::atomic_bool should_run;
int chunks_volume_real;
std::thread init(){ std::thread init(){
int index{0}; int index{0};
int rr{RENDER_DISTANCE * RENDER_DISTANCE}; int rr{RENDER_DISTANCE * RENDER_DISTANCE};
@ -62,27 +66,34 @@ namespace chunkmanager
} }
else b = false; else b = false;
} }
chunks_volume_real = index;
// Also init mesh data queue
for(int i = 0; i < 10; i++)
chunkmesher::getMeshDataQueue().push(new chunkmesher::MeshData());
should_run = true; should_run = true;
std::thread update_thread (update); std::thread update_thread (update);
return update_thread; return update_thread;
} }
std::vector<uint32_t> chunks_todelete; oneapi::tbb::concurrent_queue<Chunk::Chunk*> chunks_todelete;
int nUnloaded{0};
void update(){ void update(){
while(should_run) { while(should_run) {
//cameraPos = theCamera.getPos();
int chunkX=static_cast<int>(theCamera.getAtomicPosX() / CHUNK_SIZE); int chunkX=static_cast<int>(theCamera.getAtomicPosX() / CHUNK_SIZE);
int chunkY=static_cast<int>(theCamera.getAtomicPosY() / CHUNK_SIZE); int chunkY=static_cast<int>(theCamera.getAtomicPosY() / CHUNK_SIZE);
int chunkZ=static_cast<int>(theCamera.getAtomicPosZ() / CHUNK_SIZE); int chunkZ=static_cast<int>(theCamera.getAtomicPosZ() / CHUNK_SIZE);
// Update other chunks // Update other chunks
for(int i = 0; i < chunks_volume; i++) { for(int i = 0; i < chunks_volume_real; i++) {
const uint16_t x = chunks_indices[i][0] + chunkX; const uint16_t x = chunks_indices[i][0] + chunkX;
const uint16_t y = chunks_indices[i][1] + chunkY; const uint16_t y = chunks_indices[i][1] + chunkY;
const uint16_t z = chunks_indices[i][2] + chunkZ; const uint16_t z = chunks_indices[i][2] + chunkZ;
const uint32_t index = calculateIndex(x, y, z); const uint32_t index = calculateIndex(x, y, z);
if(x > 1023 || y > 1023 || z > 1023) continue;
ChunkTable::accessor a; ChunkTable::accessor a;
if(!chunks.find(a, index)) chunks.emplace(a, std::make_pair(index, new Chunk::Chunk(glm::vec3(x,y,z)))); if(!chunks.find(a, index)) chunks.emplace(a, std::make_pair(index, new Chunk::Chunk(glm::vec3(x,y,z))));
@ -101,6 +112,7 @@ namespace chunkmanager
return i | (j << 10) | (k << 20); return i | (j << 10) | (k << 20);
} }
oneapi::tbb::concurrent_queue<Chunk::Chunk*>& getDeleteVector(){ return chunks_todelete; }
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices(){ return chunks_indices; } std::array<std::array<int, 3>, chunks_volume>& getChunksIndices(){ return chunks_indices; }
void stop() { should_run=false; } void stop() { should_run=false; }

View File

@ -5,13 +5,20 @@
#include "chunk.hpp" #include "chunk.hpp"
#include "chunkmesher.hpp" #include "chunkmesher.hpp"
#include "globals.hpp" #include "globals.hpp"
#include "renderer.hpp"
#include "spacefilling.hpp" #include "spacefilling.hpp"
#include "utils.hpp" #include "utils.hpp"
namespace chunkmesher{ namespace chunkmesher{
oneapi::tbb::concurrent_queue<MeshData*> MeshDataQueue;
oneapi::tbb::concurrent_queue<MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
void mesh(Chunk::Chunk* chunk) void mesh(Chunk::Chunk* chunk)
{ {
MeshData* mesh_data;
if(!MeshDataQueue.try_pop(mesh_data)) return;
/* /*
* Taking inspiration from 0fps and the jme3 porting at * Taking inspiration from 0fps and the jme3 porting at
@ -29,14 +36,16 @@ void mesh(Chunk::Chunk* chunk)
*/ */
// Cleanup previous data // Cleanup previous data
chunk->vertices.clear(); chunk->numVertices = 0;
chunk->indices.clear(); mesh_data->chunk = chunk;
chunk->colors.clear(); mesh_data->vertices.clear();
chunk->vIndex = 0; mesh_data->indices.clear();
mesh_data->colors.clear();
// Abort if chunk is empty // Abort if chunk is empty
if(chunk->getState(Chunk::CHUNK_STATE_EMPTY)){ if(chunk->getState(Chunk::CHUNK_STATE_EMPTY)){
chunk->setState(Chunk::CHUNK_STATE_MESHED, true); chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
renderer::getMeshDataQueue().push(mesh_data);
return; return;
} }
@ -45,6 +54,7 @@ void mesh(Chunk::Chunk* chunk)
std::unique_ptr<Block[]> blocks = chunk->getBlocksArray(&length); std::unique_ptr<Block[]> blocks = chunk->getBlocksArray(&length);
if(length == 0) { if(length == 0) {
chunk->setState(Chunk::CHUNK_STATE_MESHED, true); chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
renderer::getMeshDataQueue().push(mesh_data);
return; return;
} }
@ -150,7 +160,7 @@ void mesh(Chunk::Chunk* chunk)
dv[2] = 0; dv[2] = 0;
dv[v] = h; dv[v] = h;
quad(chunk, glm::vec3(x[0], x[1], x[2]), quad(mesh_data, glm::vec3(x[0], x[1], x[2]),
glm::vec3(x[0] + du[0], x[1] + du[1], x[2] + du[2]), glm::vec3(x[0] + du[0], x[1] + du[1], x[2] + du[2]),
glm::vec3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], glm::vec3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1],
x[2] + du[2] + dv[2]), x[2] + du[2] + dv[2]),
@ -186,17 +196,21 @@ void mesh(Chunk::Chunk* chunk)
} }
chunk->setState(Chunk::CHUNK_STATE_MESHED, true); chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
renderer::getMeshDataQueue().push(mesh_data);
return;
} }
void sendtogpu(Chunk::Chunk* chunk) void sendtogpu(MeshData* mesh_data)
{ {
if (chunk->vIndex > 0) if (mesh_data->chunk->numVertices > 0)
{ {
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). if(mesh_data->chunk->VAO == 0) mesh_data->chunk->createBuffers();
glBindVertexArray(chunk->VAO);
glBindBuffer(GL_ARRAY_BUFFER, chunk->VBO); // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBufferData(GL_ARRAY_BUFFER, chunk->vertices.size() * sizeof(GLfloat), &(chunk->vertices[0]), GL_STATIC_DRAW); glBindVertexArray(mesh_data->chunk->VAO);
glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->VBO);
glBufferData(GL_ARRAY_BUFFER, mesh_data->vertices.size() * sizeof(GLfloat), &(mesh_data->vertices[0]), GL_STATIC_DRAW);
// position attribute // position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
@ -207,12 +221,12 @@ void sendtogpu(Chunk::Chunk* chunk)
sizeof(float))); sizeof(float)));
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_data->chunk->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, chunk->indices.size() * sizeof(GLuint), &(chunk->indices[0]), GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh_data->indices.size() * sizeof(GLuint), &(mesh_data->indices[0]), GL_STATIC_DRAW);
// texcoords attribute // texcoords attribute
glBindBuffer(GL_ARRAY_BUFFER, chunk->colorBuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->colorBuffer);
glBufferData(GL_ARRAY_BUFFER, chunk->colors.size() * sizeof(GLfloat), &(chunk->colors[0]), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, mesh_data->colors.size() * sizeof(GLfloat), &(mesh_data->colors[0]), GL_STATIC_DRAW);
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
@ -220,119 +234,118 @@ void sendtogpu(Chunk::Chunk* chunk)
glBindVertexArray(0); glBindVertexArray(0);
// save the number of indices of the mesh, it is needed later for drawing // save the number of indices of the mesh, it is needed later for drawing
chunk->vIndex = (GLuint)(chunk->indices.size()); mesh_data->chunk->numVertices = (GLuint)(mesh_data->indices.size());
// once data has been sent to the GPU, it can be cleared from system RAM // once data has been sent to the GPU, it can be cleared from system RAM
chunk->vertices.clear(); mesh_data->vertices.clear();
chunk->indices.clear(); mesh_data->indices.clear();
chunk->colors.clear(); mesh_data->colors.clear();
} }
// mark the chunk mesh has loaded on GPU // mark the chunk mesh has loaded on GPU
chunk->setState(Chunk::CHUNK_STATE_MESH_LOADED, true); mesh_data->chunk->setState(Chunk::CHUNK_STATE_MESH_LOADED, true);
} }
void quad(Chunk::Chunk* chunk, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec3 topRight, void quad(MeshData* mesh_data, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec3 topRight,
glm::vec3 bottomRight, glm::vec3 normal, Block block, int dim, bool backFace) glm::vec3 bottomRight, glm::vec3 normal, Block block, int dim, bool backFace)
{ {
mesh_data->vertices.push_back(bottomLeft.x);
mesh_data->vertices.push_back(bottomLeft.y);
mesh_data->vertices.push_back(bottomLeft.z);
mesh_data->vertices.push_back(normal.x);
mesh_data->vertices.push_back(normal.y);
mesh_data->vertices.push_back(normal.z);
chunk->vertices.push_back(bottomLeft.x); mesh_data->vertices.push_back(bottomRight.x);
chunk->vertices.push_back(bottomLeft.y); mesh_data->vertices.push_back(bottomRight.y);
chunk->vertices.push_back(bottomLeft.z); mesh_data->vertices.push_back(bottomRight.z);
chunk->vertices.push_back(normal.x); mesh_data->vertices.push_back(normal.x);
chunk->vertices.push_back(normal.y); mesh_data->vertices.push_back(normal.y);
chunk->vertices.push_back(normal.z); mesh_data->vertices.push_back(normal.z);
chunk->vertices.push_back(bottomRight.x); mesh_data->vertices.push_back(topLeft.x);
chunk->vertices.push_back(bottomRight.y); mesh_data->vertices.push_back(topLeft.y);
chunk->vertices.push_back(bottomRight.z); mesh_data->vertices.push_back(topLeft.z);
chunk->vertices.push_back(normal.x); mesh_data->vertices.push_back(normal.x);
chunk->vertices.push_back(normal.y); mesh_data->vertices.push_back(normal.y);
chunk->vertices.push_back(normal.z); mesh_data->vertices.push_back(normal.z);
chunk->vertices.push_back(topLeft.x); mesh_data->vertices.push_back(topRight.x);
chunk->vertices.push_back(topLeft.y); mesh_data->vertices.push_back(topRight.y);
chunk->vertices.push_back(topLeft.z); mesh_data->vertices.push_back(topRight.z);
chunk->vertices.push_back(normal.x); mesh_data->vertices.push_back(normal.x);
chunk->vertices.push_back(normal.y); mesh_data->vertices.push_back(normal.y);
chunk->vertices.push_back(normal.z); mesh_data->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);
// texcoords // texcoords
if(dim == 0){ if(dim == 0){
chunk->colors.push_back(0); mesh_data->colors.push_back(0);
chunk->colors.push_back(0); mesh_data->colors.push_back(0);
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(bottomRight.z - bottomLeft.z)); mesh_data->colors.push_back(abs(bottomRight.z - bottomLeft.z));
chunk->colors.push_back(abs(bottomRight.y - bottomLeft.y)); mesh_data->colors.push_back(abs(bottomRight.y - bottomLeft.y));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(topLeft.z - bottomLeft.z)); mesh_data->colors.push_back(abs(topLeft.z - bottomLeft.z));
chunk->colors.push_back(abs(topLeft.y - bottomLeft.y)); mesh_data->colors.push_back(abs(topLeft.y - bottomLeft.y));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(topRight.z - bottomLeft.z)); mesh_data->colors.push_back(abs(topRight.z - bottomLeft.z));
chunk->colors.push_back(abs(topRight.y - bottomLeft.y)); mesh_data->colors.push_back(abs(topRight.y - bottomLeft.y));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
}else if(dim == 1){ }else if(dim == 1){
chunk->colors.push_back(0); mesh_data->colors.push_back(0);
chunk->colors.push_back(0); mesh_data->colors.push_back(0);
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(bottomRight.z - bottomLeft.z)); mesh_data->colors.push_back(abs(bottomRight.z - bottomLeft.z));
chunk->colors.push_back(abs(bottomRight.x - bottomLeft.x)); mesh_data->colors.push_back(abs(bottomRight.x - bottomLeft.x));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(topLeft.z - bottomLeft.z)); mesh_data->colors.push_back(abs(topLeft.z - bottomLeft.z));
chunk->colors.push_back(abs(topLeft.x - bottomLeft.x)); mesh_data->colors.push_back(abs(topLeft.x - bottomLeft.x));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(topRight.z - bottomLeft.z)); mesh_data->colors.push_back(abs(topRight.z - bottomLeft.z));
chunk->colors.push_back(abs(topRight.x - bottomLeft.x)); mesh_data->colors.push_back(abs(topRight.x - bottomLeft.x));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
}else{ }else{
chunk->colors.push_back(0); mesh_data->colors.push_back(0);
chunk->colors.push_back(0); mesh_data->colors.push_back(0);
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(bottomRight.x - bottomLeft.x)); mesh_data->colors.push_back(abs(bottomRight.x - bottomLeft.x));
chunk->colors.push_back(abs(bottomRight.y - bottomLeft.y)); mesh_data->colors.push_back(abs(bottomRight.y - bottomLeft.y));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(topLeft.x - bottomLeft.x)); mesh_data->colors.push_back(abs(topLeft.x - bottomLeft.x));
chunk->colors.push_back(abs(topLeft.y - bottomLeft.y)); mesh_data->colors.push_back(abs(topLeft.y - bottomLeft.y));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
chunk->colors.push_back(abs(topRight.x - bottomLeft.x)); mesh_data->colors.push_back(abs(topRight.x - bottomLeft.x));
chunk->colors.push_back(abs(topRight.y - bottomLeft.y)); mesh_data->colors.push_back(abs(topRight.y - bottomLeft.y));
chunk->colors.push_back(((int)block) - 2); mesh_data->colors.push_back(((int)block) - 2);
} }
if (backFace) if (backFace)
{ {
chunk->indices.push_back(chunk->vIndex + 2); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 2);
chunk->indices.push_back(chunk->vIndex); mesh_data->indices.push_back(mesh_data->chunk->numVertices);
chunk->indices.push_back(chunk->vIndex + 1); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 1);
chunk->indices.push_back(chunk->vIndex + 1); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 1);
chunk->indices.push_back(chunk->vIndex + 3); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 3);
chunk->indices.push_back(chunk->vIndex + 2); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 2);
} }
else else
{ {
chunk->indices.push_back(chunk->vIndex + 2); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 2);
chunk->indices.push_back(chunk->vIndex + 3); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 3);
chunk->indices.push_back(chunk->vIndex + 1); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 1);
chunk->indices.push_back(chunk->vIndex + 1); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 1);
chunk->indices.push_back(chunk->vIndex); mesh_data->indices.push_back(mesh_data->chunk->numVertices);
chunk->indices.push_back(chunk->vIndex + 2); mesh_data->indices.push_back(mesh_data->chunk->numVertices + 2);
} }
chunk->vIndex += 4; mesh_data->chunk->numVertices += 4;
} }
}; };

View File

@ -1,19 +1,24 @@
#include "renderer.hpp" #include "renderer.hpp"
#include <oneapi/tbb/concurrent_vector.h>
#include <oneapi/tbb/concurrent_queue.h>
#include "chunkmanager.hpp" #include "chunkmanager.hpp"
#include "chunkmesher.hpp" #include "chunkmesher.hpp"
#include "globals.hpp" #include "globals.hpp"
#include "stb_image.h" #include "stb_image.h"
namespace renderer{ namespace renderer{
oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*> chunks_torender; RenderSet chunks_torender;
oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*> render_todelete; oneapi::tbb::concurrent_vector<Chunk::Chunk*> render_todelete;
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*> MeshDataQueue;
Shader* theShader; Shader* theShader;
GLuint chunkTexture; GLuint chunkTexture;
Shader* getRenderShader() { return theShader; } Shader* getRenderShader() { return theShader; }
oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*>& getChunksToRender(){ return chunks_torender; } RenderSet& getChunksToRender(){ return chunks_torender; }
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
void init(){ void init(){
@ -50,18 +55,45 @@ namespace renderer{
theShader->use(); theShader->use();
theShader->setVec3("viewPos", cameraPos); theShader->setVec3("viewPos", cameraPos);
for(Chunk::Chunk* c : chunks_torender){ for(auto& n : render_todelete){
// we can get away with unsafe erase as access to the container is only done by this
// thread
n->deleteBuffers();
chunks_torender.unsafe_erase(n);
}
render_todelete.clear();
chunkmesher::MeshData* m;
while(MeshDataQueue.try_pop(m)){
chunkmesher::sendtogpu(m);
chunkmesher::getMeshDataQueue().push(m);
}
for(auto& c : chunks_torender){
if(! (c->getState(Chunk::CHUNK_STATE_MESHED))) continue; if(! (c->getState(Chunk::CHUNK_STATE_MESHED))) continue;
float dist = glm::distance(c->getPosition(), cameraChunkPos);
if(dist >= static_cast<float>(RENDER_DISTANCE)*1.75f){
// When the chunk is outside render distance
// If the mesh is ready send it to the gpu if(c->getState(Chunk::CHUNK_STATE_OUTOFVISION)){
if(! (c->getState(Chunk::CHUNK_STATE_MESH_LOADED))){ if(glfwGetTime() - c->unload_timer > UNLOAD_TIMEOUT){
if(c->VAO == 0) c->createBuffers(); // If chunk was already out and enough time has passed
chunkmesher::sendtogpu(c); // Mark the chunk to be unloaded
c->setState(Chunk::CHUNK_STATE_MESH_LOADED, true); // And mark is to be removed from the render set
} render_todelete.push_back(c);
chunkmanager::getDeleteVector().push(c);
}
} else{
// Mark has out of vision and annotate when it started
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, true);
c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
c->unload_timer = glfwGetTime();
}
}else if(dist <= static_cast<float>(RENDER_DISTANCE)){
if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) continue;
if(glm::distance(c->getPosition(), cameraChunkPos) < static_cast<float>(RENDER_DISTANCE)){
// if chunk can be seen
// reset out-of-vision and unload flags // reset out-of-vision and unload flags
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, false); c->setState(Chunk::CHUNK_STATE_OUTOFVISION, false);
c->setState(Chunk::CHUNK_STATE_UNLOADED, false); c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
@ -89,7 +121,7 @@ namespace renderer{
if (!out) if (!out)
{ {
if(c->vIndex > 0) if(c->numVertices > 0)
{ {
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // wireframe mode // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // wireframe mode
theShader->setMat4("model", model); theShader->setMat4("model", model);
@ -97,36 +129,14 @@ namespace renderer{
theShader->setMat4("projection", theCamera.getProjection()); theShader->setMat4("projection", theCamera.getProjection());
glBindVertexArray(c->VAO); glBindVertexArray(c->VAO);
glDrawElements(GL_TRIANGLES, c->vIndex , GL_UNSIGNED_INT, 0); glDrawElements(GL_TRIANGLES, c->numVertices , GL_UNSIGNED_INT, 0);
glBindVertexArray(0); glBindVertexArray(0);
} }
} }
}else{
// When the chunk is outside render distance
if(c->getState(Chunk::CHUNK_STATE_OUTOFVISION) && glfwGetTime() -
c->unload_timer > UNLOAD_TIMEOUT){
// If chunk was already out and enough time has passed
// Mark the chunk to be unloaded
c->setState(Chunk::CHUNK_STATE_UNLOADED, true);
// And delete it from the render set
render_todelete.insert(c);
} else{
// Mark has out of vision and annotate when it started
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, true);
c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
c->unload_timer = glfwGetTime();
}
} }
} }
for(Chunk::Chunk* i : render_todelete){
chunks_torender.unsafe_erase(i);
}
render_todelete.clear();
} }
void destroy(){ void destroy(){
delete theShader; delete theShader;
} }