Refactor Meshing/Rendering communication #13
|
@ -52,9 +52,6 @@ namespace Chunk
|
|||
~Chunk();
|
||||
|
||||
public:
|
||||
void createBuffers();
|
||||
void deleteBuffers();
|
||||
|
||||
glm::vec3 getPosition() { return this->position; }
|
||||
void setState(chunk_state_t nstate, bool value);
|
||||
bool getState(chunk_state_t n) { return (this->state & n) == n; }
|
||||
|
@ -72,7 +69,6 @@ namespace Chunk
|
|||
std::unique_ptr<Block[]> getBlocksArray(int* len) { return (this->blocks.toArray(len)); }
|
||||
|
||||
public:
|
||||
GLuint VAO{0}, VBO{0}, extentsBuffer{0}, texinfoBuffer{0}, numVertices{0};
|
||||
std::atomic<float> unload_timer{0};
|
||||
chunk_index_t getIndex(){ return this->index; }
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef CHUNK_MESH_DATA_H
|
||||
#define CHUNK_MESH_DATA_H
|
||||
|
||||
#include <oneapi/tbb/concurrent_queue.h>
|
||||
#include "chunk.hpp"
|
||||
|
||||
enum class ChunkMeshDataType{
|
||||
MESH_UPDATE
|
||||
};
|
||||
|
||||
typedef struct ChunkMeshData{
|
||||
chunk_index_t index;
|
||||
glm::vec3 position;
|
||||
int num_vertices = 0;
|
||||
|
||||
std::vector<GLfloat> vertices;
|
||||
std::vector<GLfloat> extents;
|
||||
std::vector<GLfloat> texinfo;
|
||||
|
||||
ChunkMeshDataType message_type;
|
||||
|
||||
void clear(){
|
||||
vertices.clear();
|
||||
texinfo.clear();
|
||||
extents.clear();
|
||||
index = 0;
|
||||
position = glm::vec3(0);
|
||||
num_vertices = 0;
|
||||
}
|
||||
|
||||
}ChunkMeshData;
|
||||
typedef oneapi::tbb::concurrent_queue<ChunkMeshData*> ChunkMeshDataQueue;
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -5,10 +5,12 @@
|
|||
#include <vector>
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <oneapi/tbb/concurrent_queue.h>
|
||||
|
||||
#include "chunk.hpp"
|
||||
#include "chunkmeshdata.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "shader.hpp"
|
||||
|
||||
|
@ -21,13 +23,12 @@ namespace chunkmesher{
|
|||
std::vector<GLfloat> extents;
|
||||
std::vector<GLfloat> texinfo;
|
||||
};
|
||||
oneapi::tbb::concurrent_queue<MeshData*>& getMeshDataQueue();
|
||||
|
||||
ChunkMeshDataQueue& getMeshDataQueue();
|
||||
void init();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -6,12 +6,43 @@
|
|||
|
||||
#include "chunk.hpp"
|
||||
#include "chunkmesher.hpp"
|
||||
#include "chunkmeshdata.hpp"
|
||||
#include "shader.hpp"
|
||||
|
||||
namespace renderer{
|
||||
typedef oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*> RenderSet;
|
||||
typedef struct RenderInfo {
|
||||
chunk_index_t index;
|
||||
int num_vertices;
|
||||
glm::vec3 position;
|
||||
bool buffers_allocated=false;
|
||||
|
||||
GLuint VAO, VBO, extentsBuffer, texinfoBuffer;
|
||||
|
||||
void allocateBuffers(){
|
||||
// Allocate buffers
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
glGenBuffers(1, &extentsBuffer);
|
||||
glGenBuffers(1, &texinfoBuffer);
|
||||
|
||||
buffers_allocated=true;
|
||||
}
|
||||
|
||||
void deallocateBuffers(){
|
||||
// Allocate buffers
|
||||
glDeleteBuffers(1, &VBO);
|
||||
glDeleteBuffers(1, &extentsBuffer);
|
||||
glDeleteBuffers(1, &texinfoBuffer);
|
||||
glDeleteVertexArrays(1, &VAO);
|
||||
|
||||
buffers_allocated=false;
|
||||
}
|
||||
} RenderInfo;
|
||||
|
||||
typedef oneapi::tbb::concurrent_queue<int32_t> IndexQueue;
|
||||
|
||||
void init(GLFWwindow* window);
|
||||
void send_chunk_to_gpu(ChunkMeshData* mesh_data, RenderInfo* render_info);
|
||||
void render();
|
||||
void resize_framebuffer(int width, int height);
|
||||
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
|
||||
|
@ -20,9 +51,11 @@ namespace renderer{
|
|||
void saveScreenshot(bool forceFullHD=false);
|
||||
|
||||
Shader* getRenderShader();
|
||||
RenderSet& getChunksToRender();
|
||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue();
|
||||
ChunkMeshDataQueue& getMeshDataQueue();
|
||||
IndexQueue& getDeleteIndexQueue();
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -36,21 +36,6 @@ namespace Chunk
|
|||
{
|
||||
}
|
||||
|
||||
void Chunk::createBuffers(){
|
||||
glGenVertexArrays(1, &(this->VAO));
|
||||
glGenBuffers(1, &(this->VBO));
|
||||
glGenBuffers(1, &(this->extentsBuffer));
|
||||
glGenBuffers(1, &(this->texinfoBuffer));
|
||||
|
||||
}
|
||||
|
||||
void Chunk::deleteBuffers(){
|
||||
glDeleteBuffers(1, &(this->VBO));
|
||||
glDeleteBuffers(1, &(this->extentsBuffer));
|
||||
glDeleteBuffers(1, &(this->texinfoBuffer));
|
||||
glDeleteVertexArrays(1, &(this->VAO));
|
||||
}
|
||||
|
||||
Block Chunk::getBlock(int x, int y, int z)
|
||||
{
|
||||
if(x < 0 || y < 0 || z < 0 || x > CHUNK_SIZE -1 || y > CHUNK_SIZE -1 || z > CHUNK_SIZE-1 ||
|
||||
|
|
|
@ -53,10 +53,6 @@ namespace chunkmanager
|
|||
index++;
|
||||
}
|
||||
|
||||
// Also init mesh data queue
|
||||
for(int i = 0; i < 10; i++)
|
||||
chunkmesher::getMeshDataQueue().push(new chunkmesher::MeshData());
|
||||
|
||||
should_run = true;
|
||||
update_thread = std::thread(update);
|
||||
gen_thread = std::thread(generate);
|
||||
|
@ -85,7 +81,6 @@ namespace chunkmanager
|
|||
if(chunks_to_mesh_queue.try_pop(entry)){
|
||||
Chunk::Chunk* chunk = entry.first;
|
||||
chunkmesher::mesh(chunk);
|
||||
renderer::getChunksToRender().insert(chunk);
|
||||
chunk->setState(Chunk::CHUNK_STATE_IN_MESHING_QUEUE, false);
|
||||
}
|
||||
}
|
||||
|
@ -117,6 +112,7 @@ namespace chunkmanager
|
|||
// Using the key doesn't work
|
||||
if(chunks.erase(a)){
|
||||
nUnloaded++;
|
||||
renderer::getDeleteIndexQueue().push(index);
|
||||
delete c;
|
||||
} else {
|
||||
c->setState(Chunk::CHUNK_STATE_IN_DELETING_QUEUE, false);
|
||||
|
|
|
@ -11,15 +11,24 @@
|
|||
#include "spacefilling.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#define CHUNK_MESH_DATA_QUANTITY 100
|
||||
#define CHUNK_MESH_WORLD_LIMIT_BORDERS 0
|
||||
|
||||
namespace chunkmesher{
|
||||
|
||||
oneapi::tbb::concurrent_queue<MeshData*> MeshDataQueue;
|
||||
ChunkMeshDataQueue MeshDataQueue;
|
||||
|
||||
oneapi::tbb::concurrent_queue<MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
|
||||
ChunkMeshDataQueue& getMeshDataQueue(){ return MeshDataQueue; }
|
||||
|
||||
void init()
|
||||
{
|
||||
for(int i = 0; i < CHUNK_MESH_DATA_QUANTITY; i++)
|
||||
MeshDataQueue.push(new ChunkMeshData{});
|
||||
}
|
||||
|
||||
void mesh(Chunk::Chunk* chunk)
|
||||
{
|
||||
MeshData* mesh_data;
|
||||
ChunkMeshData* mesh_data;
|
||||
if(!MeshDataQueue.try_pop(mesh_data)) return;
|
||||
|
||||
/*
|
||||
|
@ -38,27 +47,14 @@ void mesh(Chunk::Chunk* chunk)
|
|||
*/
|
||||
|
||||
// Cleanup previous data
|
||||
mesh_data->numVertices = 0;
|
||||
mesh_data->chunk = chunk;
|
||||
mesh_data->vertices.clear();
|
||||
mesh_data->extents.clear();
|
||||
mesh_data->texinfo.clear();
|
||||
|
||||
// Abort if chunk is empty
|
||||
if(chunk->getState(Chunk::CHUNK_STATE_EMPTY)){
|
||||
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
||||
renderer::getMeshDataQueue().push(mesh_data);
|
||||
return;
|
||||
}
|
||||
mesh_data->clear();
|
||||
mesh_data->message_type = ChunkMeshDataType::MESH_UPDATE;
|
||||
mesh_data->index = chunk->getIndex();
|
||||
mesh_data->position = chunk->getPosition();
|
||||
|
||||
// convert tree to array since it is easier to work with it
|
||||
int length{0};
|
||||
std::unique_ptr<Block[]> blocks = chunk->getBlocksArray(&length);
|
||||
if(length == 0) {
|
||||
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
||||
renderer::getMeshDataQueue().push(mesh_data);
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<Block[]> blocks;
|
||||
|
||||
int k, l, u, v, w, h, n, j, i;
|
||||
int x[]{0, 0, 0};
|
||||
|
@ -66,6 +62,12 @@ void mesh(Chunk::Chunk* chunk)
|
|||
int du[]{0, 0, 0};
|
||||
int dv[]{0, 0, 0};
|
||||
|
||||
// Abort if chunk is empty
|
||||
if(chunk->getState(Chunk::CHUNK_STATE_EMPTY)) goto end;
|
||||
|
||||
blocks = chunk->getBlocksArray(&length);
|
||||
if(length == 0) goto end;
|
||||
|
||||
std::array<Block, CHUNK_SIZE * CHUNK_SIZE> mask;
|
||||
for (bool backFace = true, b = false; b != backFace; backFace = backFace && b, b = !b)
|
||||
{
|
||||
|
@ -128,9 +130,15 @@ void mesh(Chunk::Chunk* chunk)
|
|||
// The else case provides face culling for adjacent solid faces
|
||||
// Checking for NULLBLK avoids creating empty faces if nearby chunk was not
|
||||
// yet generated
|
||||
#if CHUNK_MESH_WORLD_LIMIT_BORDERS == 1
|
||||
mask[n++] = b1 == b2 ? Block::NULLBLK
|
||||
: backFace ? b1 == Block::NULLBLK || b1 == Block::AIR ? b2 : Block::NULLBLK
|
||||
: b2 == Block::NULLBLK || b2 == Block::AIR ? b1 : Block::NULLBLK;
|
||||
#else
|
||||
mask[n++] = b1 == b2 ? Block::NULLBLK
|
||||
: backFace ? b1 == Block::AIR ? b2 : Block::NULLBLK
|
||||
: b2 == Block::AIR ? b1 : Block::NULLBLK;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +199,7 @@ void mesh(Chunk::Chunk* chunk)
|
|||
|
||||
mesh_data->texinfo.push_back(backFace ? 0.0 : 1.0);
|
||||
mesh_data->texinfo.push_back((int)(mask[n]) - 2);
|
||||
mesh_data->numVertices++;
|
||||
mesh_data->num_vertices++;
|
||||
}
|
||||
|
||||
for (l = 0; l < h; ++l)
|
||||
|
@ -220,49 +228,8 @@ void mesh(Chunk::Chunk* chunk)
|
|||
}
|
||||
}
|
||||
|
||||
end:
|
||||
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
||||
renderer::getMeshDataQueue().push(mesh_data);
|
||||
}
|
||||
|
||||
void sendtogpu(MeshData* mesh_data)
|
||||
{
|
||||
if (mesh_data->numVertices > 0)
|
||||
{
|
||||
if(mesh_data->chunk->VAO == 0) mesh_data->chunk->createBuffers();
|
||||
|
||||
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
|
||||
glBindVertexArray(mesh_data->chunk->VAO);
|
||||
|
||||
// position attribute
|
||||
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);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
// normal attribute
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->extentsBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh_data->extents.size() * sizeof(GLfloat), &(mesh_data->extents[0]), GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)(0));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
// texcoords attribute
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->texinfoBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh_data->texinfo.size() * sizeof(GLfloat), &(mesh_data->texinfo[0]), GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
// save the number of indices of the mesh, it is needed later for drawing
|
||||
mesh_data->chunk->numVertices = (GLuint)(mesh_data->numVertices);
|
||||
|
||||
// once data has been sent to the GPU, it can be cleared from system RAM
|
||||
mesh_data->vertices.clear();
|
||||
mesh_data->extents.clear();
|
||||
mesh_data->texinfo.clear();
|
||||
}
|
||||
|
||||
// mark the chunk mesh has loaded on GPU
|
||||
mesh_data->chunk->setState(Chunk::CHUNK_STATE_MESH_LOADED, true);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -95,18 +95,15 @@ namespace debug{
|
|||
}
|
||||
|
||||
if(ImGui::CollapsingHeader("Mesh")){
|
||||
ImGui::Text("Total chunks updated: %d",
|
||||
ImGui::Text("Total chunk meshed: %d",
|
||||
std::any_cast<int>(parameters.at("render_chunks_total")));
|
||||
ImGui::Text("Of which renderable (not empty): %d",
|
||||
std::any_cast<int>(parameters.at("render_chunks_renderable")));
|
||||
ImGui::Text("Chunks rendered: %d",
|
||||
std::any_cast<int>(parameters.at("render_chunks_rendered")));
|
||||
ImGui::Text("Frustum culled: %d",
|
||||
std::any_cast<int>(parameters.at("render_chunks_culled")));
|
||||
ImGui::Text("Chunks out of view: %d",
|
||||
std::any_cast<int>(parameters.at("render_chunks_oof")));
|
||||
if(parameters.find("render_chunks_deleted") != parameters.end())
|
||||
ImGui::Text("Chunks deleted: %d",
|
||||
std::any_cast<int>(parameters.at("render_chunks_deleted")));
|
||||
ImGui::Text("Vertices in the scene: %d",
|
||||
ImGui::Text("Total vertices in the scene: %d",
|
||||
std::any_cast<int>(parameters.at("render_chunks_vertices")));
|
||||
ImGui::Checkbox("Wireframe",
|
||||
std::any_cast<bool*>(parameters.at("wireframe_return")));
|
||||
|
|
|
@ -69,6 +69,7 @@ int main()
|
|||
SpaceFilling::initLUT();
|
||||
controls::init();
|
||||
chunkmanager::init();
|
||||
chunkmesher::init();
|
||||
debug::window::init(window);
|
||||
renderer::init(window);
|
||||
|
||||
|
|
212
src/renderer.cpp
212
src/renderer.cpp
|
@ -1,7 +1,8 @@
|
|||
#include "renderer.hpp"
|
||||
|
||||
#include <oneapi/tbb/concurrent_vector.h>
|
||||
#include <oneapi/tbb/concurrent_queue.h>
|
||||
#include <glm/ext.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include <oneapi/tbb/concurrent_hash_map.h>
|
||||
|
||||
#include "chunkmanager.hpp"
|
||||
#include "chunkmesher.hpp"
|
||||
|
@ -12,16 +13,18 @@
|
|||
#include "stb_image_write.h"
|
||||
|
||||
namespace renderer{
|
||||
RenderSet chunks_torender;
|
||||
oneapi::tbb::concurrent_vector<Chunk::Chunk*> render_todelete;
|
||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*> MeshDataQueue;
|
||||
typedef oneapi::tbb::concurrent_hash_map<chunk_index_t, RenderInfo*> RenderTable;
|
||||
|
||||
RenderTable ChunksToRender;
|
||||
ChunkMeshDataQueue MeshDataQueue;
|
||||
IndexQueue MeshDataToDelete;
|
||||
|
||||
Shader* theShader, *quadShader;
|
||||
GLuint chunkTexture;
|
||||
|
||||
Shader* getRenderShader() { return theShader; }
|
||||
RenderSet& getChunksToRender(){ return chunks_torender; }
|
||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
|
||||
ChunkMeshDataQueue& getMeshDataQueue(){ return MeshDataQueue; }
|
||||
IndexQueue& getDeleteIndexQueue(){ return MeshDataToDelete; }
|
||||
|
||||
GLuint renderTexFrameBuffer, renderTex, renderTexDepthBuffer, quadVAO, quadVBO;
|
||||
int screenWidth, screenHeight;
|
||||
|
@ -138,98 +141,95 @@ namespace renderer{
|
|||
theShader->use();
|
||||
theShader->setVec3("viewPos", cameraPos);
|
||||
|
||||
chunkmesher::MeshData* m;
|
||||
/* Process incoming mesh data */
|
||||
ChunkMeshData* m;
|
||||
while(MeshDataQueue.try_pop(m)){
|
||||
//chunkmesher::sendtogpu(m);
|
||||
RenderTable::accessor a;
|
||||
RenderInfo* render_info;
|
||||
|
||||
if(ChunksToRender.find(a, m->index)){
|
||||
render_info = a->second;
|
||||
render_info->position = m->position;
|
||||
render_info->num_vertices = m->num_vertices;
|
||||
}else{
|
||||
render_info = new RenderInfo();
|
||||
render_info->index = m->index;
|
||||
render_info->position = m->position;
|
||||
render_info->num_vertices = m->num_vertices;
|
||||
|
||||
ChunksToRender.emplace(a, std::make_pair(render_info->index, render_info));
|
||||
}
|
||||
|
||||
send_chunk_to_gpu(m, render_info);
|
||||
chunkmesher::getMeshDataQueue().push(m);
|
||||
}
|
||||
|
||||
/*
|
||||
for(auto& c : chunks_torender){
|
||||
float dist = glm::distance(c->getPosition(), cameraChunkPos);
|
||||
if(dist <= static_cast<float>(RENDER_DISTANCE)){
|
||||
if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) continue;
|
||||
|
||||
if(c->numVertices > 0){
|
||||
// Increase total vertex count
|
||||
vertices += c->numVertices;
|
||||
|
||||
// reset out-of-vision and unload flags
|
||||
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, false);
|
||||
c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
|
||||
|
||||
// Perform frustum culling and eventually render
|
||||
glm::vec3 chunk = c->getPosition();
|
||||
glm::vec4 chunkW = glm::vec4(chunk.x*static_cast<float>(CHUNK_SIZE), chunk.y*static_cast<float>(CHUNK_SIZE), chunk.z*static_cast<float>(CHUNK_SIZE),1.0);
|
||||
glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk);
|
||||
|
||||
// Check if all the corners of the chunk are outside any of the planes
|
||||
// TODO (?) implement frustum culling as per (Inigo Quilez)[https://iquilezles.org/articles/frustumcorrect/], and check each
|
||||
// plane against each corner of the chunk
|
||||
bool out=false;
|
||||
int a{0};
|
||||
for(int p = 0; p < 6; p++){
|
||||
a = 0;
|
||||
for(int i = 0; i < 8; i++) a += glm::dot(frustumPlanes[p], glm::vec4(chunkW.x + ((float)(i & 1))*CHUNK_SIZE, chunkW.y
|
||||
+ ((float)((i & 2) >> 1))*CHUNK_SIZE, chunkW.z + ((float)((i & 4) >> 2))*CHUNK_SIZE, 1.0)) < 0.0;
|
||||
|
||||
if(a==8){
|
||||
out=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!out)
|
||||
{
|
||||
theShader->setMat4("model", model);
|
||||
theShader->setMat4("view", theCamera.getView());
|
||||
theShader->setMat4("projection", theCamera.getProjection());
|
||||
|
||||
glBindVertexArray(c->VAO);
|
||||
glDrawArrays(GL_POINTS, 0, c->numVertices);
|
||||
glBindVertexArray(0);
|
||||
|
||||
toGpu++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// When the chunk is outside render distance
|
||||
|
||||
if(c->getState(Chunk::CHUNK_STATE_OUTOFVISION)){
|
||||
oof++;
|
||||
if(glfwGetTime() - c->unload_timer > UNLOAD_TIMEOUT){
|
||||
// If chunk was already out and enough time has passed
|
||||
// Mark the chunk to be unloaded
|
||||
// And mark is to be removed from the render set
|
||||
render_todelete.push_back(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();
|
||||
}
|
||||
/* Process chunks to be removed */
|
||||
chunk_index_t queue_index;
|
||||
while(MeshDataToDelete.try_pop(queue_index)){
|
||||
RenderTable::accessor a;
|
||||
|
||||
if(ChunksToRender.find(a, queue_index)){
|
||||
RenderInfo* render_info = a->second;
|
||||
render_info->deallocateBuffers();
|
||||
delete render_info;
|
||||
ChunksToRender.erase(a);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
total = chunks_torender.size();
|
||||
debug::window::set_parameter("render_chunks_total", total);
|
||||
debug::window::set_parameter("render_chunks_rendered", toGpu);
|
||||
debug::window::set_parameter("render_chunks_culled", total-toGpu);
|
||||
debug::window::set_parameter("render_chunks_oof", oof);
|
||||
debug::window::set_parameter("render_chunks_deleted", (int) (render_todelete.size()));
|
||||
debug::window::set_parameter("render_chunks_vertices", vertices);
|
||||
/* Render the chunks */
|
||||
// parallel_for cannot be used since all the rendering needs to happen in a single thread
|
||||
for(RenderTable::iterator i = ChunksToRender.begin(); i != ChunksToRender.end(); i++){
|
||||
RenderInfo* render_info = i->second;
|
||||
|
||||
/*for(auto& c : render_todelete){
|
||||
// we can get away with unsafe erase as access to the container is only done by this
|
||||
// thread
|
||||
c->deleteBuffers();
|
||||
chunks_torender.unsafe_erase(c);
|
||||
chunkmanager::getDeleteVector().push(c);
|
||||
if(render_info->num_vertices > 0)
|
||||
{
|
||||
total++;
|
||||
|
||||
// Increase total vertex count
|
||||
vertices += render_info->num_vertices;
|
||||
|
||||
// Perform frustum culling and eventually render
|
||||
glm::vec3 chunk = render_info->position;
|
||||
glm::vec4 chunkW = glm::vec4(chunk.x*static_cast<float>(CHUNK_SIZE), chunk.y*static_cast<float>(CHUNK_SIZE), chunk.z*static_cast<float>(CHUNK_SIZE),1.0);
|
||||
glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk);
|
||||
|
||||
// Check if all the corners of the chunk are outside any of the planes
|
||||
// TODO (?) implement frustum culling as per (Inigo Quilez)[https://iquilezles.org/articles/frustumcorrect/], and check each
|
||||
// plane against each corner of the chunk
|
||||
bool out=false;
|
||||
int a{0};
|
||||
for(int p = 0; p < 6; p++){
|
||||
a = 0;
|
||||
for(int i = 0; i < 8; i++) a += glm::dot(frustumPlanes[p], glm::vec4(chunkW.x + ((float)(i & 1))*CHUNK_SIZE, chunkW.y
|
||||
+ ((float)((i & 2) >> 1))*CHUNK_SIZE, chunkW.z + ((float)((i & 4) >> 2))*CHUNK_SIZE, 1.0)) < 0.0;
|
||||
|
||||
if(a==8){
|
||||
out=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!out)
|
||||
{
|
||||
theShader->setMat4("model", model);
|
||||
theShader->setMat4("view", theCamera.getView());
|
||||
theShader->setMat4("projection", theCamera.getProjection());
|
||||
|
||||
glBindVertexArray(render_info->VAO);
|
||||
glDrawArrays(GL_POINTS, 0, render_info->num_vertices);
|
||||
glBindVertexArray(0);
|
||||
|
||||
toGpu++;
|
||||
}
|
||||
}
|
||||
}
|
||||
render_todelete.clear();*/
|
||||
|
||||
debug::window::set_parameter("render_chunks_total", (int)(ChunksToRender.size()));
|
||||
debug::window::set_parameter("render_chunks_rendered", toGpu);
|
||||
debug::window::set_parameter("render_chunks_renderable", total);
|
||||
debug::window::set_parameter("render_chunks_culled", total-toGpu);
|
||||
debug::window::set_parameter("render_chunks_vertices", vertices);
|
||||
|
||||
/* DISPLAY TEXTURE ON A QUAD THAT FILLS THE SCREEN */
|
||||
// Now to render the quad, with the texture on top
|
||||
|
@ -252,6 +252,40 @@ namespace renderer{
|
|||
debug::window::render();
|
||||
}
|
||||
|
||||
void send_chunk_to_gpu(ChunkMeshData* mesh_data, RenderInfo* render_info)
|
||||
{
|
||||
if (render_info->num_vertices > 0)
|
||||
{
|
||||
if(!render_info->buffers_allocated) render_info->allocateBuffers();
|
||||
|
||||
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
|
||||
glBindVertexArray(render_info->VAO);
|
||||
|
||||
// TODO: change GL_STATIC_DRAW to the one that means "few redraws and further in between"
|
||||
|
||||
// position attribute
|
||||
glBindBuffer(GL_ARRAY_BUFFER, render_info->VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh_data->vertices.size() * sizeof(GLfloat), &(mesh_data->vertices[0]), GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
// normal attribute
|
||||
glBindBuffer(GL_ARRAY_BUFFER, render_info->extentsBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh_data->extents.size() * sizeof(GLfloat), &(mesh_data->extents[0]), GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)(0));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
// texcoords attribute
|
||||
glBindBuffer(GL_ARRAY_BUFFER, render_info->texinfoBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh_data->texinfo.size() * sizeof(GLfloat), &(mesh_data->texinfo[0]), GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void framebuffer_size_callback(GLFWwindow *window, int width, int height){
|
||||
resize_framebuffer(width, height);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue