separate rendering in a dedicated file

pull/1/head
EmaMaker 2023-04-09 21:44:17 +02:00
parent b4f3bdad06
commit 2b1991ff2b
9 changed files with 122 additions and 76 deletions

View File

@ -4,7 +4,10 @@
// Second to be passed outside of render distance for a chunk to be destroyed
#define UNLOAD_TIMEOUT 10
#include <unordered_map>
#include <thread>
#include "chunk.hpp"
#include "globals.hpp"
namespace chunkmanager
{
@ -21,6 +24,8 @@ namespace chunkmanager
uint32_t calculateIndex(uint16_t i, uint16_t j, uint16_t k);
void destroy();
std::unordered_map<std::uint32_t, Chunk::Chunk*>& getChunks();
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices();
void update(float deltaTime);
void updateChunk(uint32_t, uint16_t, uint16_t, uint16_t);
}

View File

@ -13,7 +13,7 @@
#define RENDER_DISTANCE 16
extr Camera theCamera;
extr Shader* theShader;
constexpr int chunks_volume = static_cast<int>(1.333333333333*M_PI*(RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE));
extr uint32_t MORTON_XYZ_ENCODE[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE];
extr uint32_t MORTON_XYZ_DECODE[CHUNK_VOLUME][3];

14
include/renderer.hpp Normal file
View File

@ -0,0 +1,14 @@
#ifndef RENDERER_H
#define RENDERER_H
#include "shader.hpp"
namespace renderer{
void init();
void render();
void destroy();
Shader* getRenderShader();
};
#endif

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.2)
project(OpenGLTest)
set(SOURCE_FILES main.cpp chunk.cpp chunkmanager.cpp chunkmesher.cpp chunkgenerator.cpp spacefilling.cpp stb_image.cpp utils.cpp OpenSimplexNoise.cpp)
set(SOURCE_FILES main.cpp chunk.cpp chunkmanager.cpp chunkmesher.cpp chunkgenerator.cpp renderer.cpp spacefilling.cpp stb_image.cpp utils.cpp OpenSimplexNoise.cpp)
add_executable(OpenGLTest ${SOURCE_FILES})

View File

@ -101,11 +101,11 @@ void generateNoise3D(Chunk::Chunk *chunk) {
double noise = noiseGen1.eval(x * 0.025, y*0.025, z * 0.025);
if (noise < 0)
if (noise < -0.1)
block = Block::STONE;
else if (noise >= 0 && noise < 0.1)
else if (noise >= -0.1 && noise < 0)
block = Block::DIRT;
else if (noise >= 0.1 && noise < 0.2)
else if (noise >= 0 && noise < 0.08)
block = Block::GRASS;
else
block = Block::AIR;

View File

@ -17,13 +17,11 @@
#include <unordered_map>
#include <thread>
std::unordered_map<std::uint32_t, Chunk::Chunk *> chunks;
constexpr int chunks_volume = static_cast<int>(1.333333333333*M_PI*(RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE));
std::array<std::array<int, 3>, chunks_volume> chunks_indices;
namespace chunkmanager
{
std::unordered_map<std::uint32_t, Chunk::Chunk *> chunks;
std::array<std::array<int, 3>, chunks_volume> chunks_indices;
// thread management
std::mutex mutex_queue_generate;
std::mutex mutex_queue_mesh;
@ -35,10 +33,8 @@ namespace chunkmanager
// update variables
uint8_t f = 0;
int rr{RENDER_DISTANCE * RENDER_DISTANCE};
glm::vec4 frustumPlanes[6];
glm::vec3 cameraPos;
int chunkX, chunkY, chunkZ;
int total{0}, toGpu{0};
// disposal
std::unordered_map<uint32_t, float> to_delete;
@ -145,7 +141,6 @@ namespace chunkmanager
f |= mutex_queue_mesh.try_lock() << 1;
cameraPos = theCamera.getPos();
theCamera.getFrustumPlanes(frustumPlanes, true);
chunkX=static_cast<int>(cameraPos.x) / CHUNK_SIZE;
chunkY=static_cast<int>(cameraPos.y) / CHUNK_SIZE;
chunkZ=static_cast<int>(cameraPos.z) / CHUNK_SIZE;
@ -187,12 +182,6 @@ namespace chunkmanager
chunks_indices[i][1] + chunkY,
chunks_indices[i][2] + chunkZ);
//std::cout << "Chunks to mesh: " << to_mesh.size() << "\n";
//std::cout << "Chunks to generate: " << to_generate.size() << "\n";
//std::cout << "Total chunks to draw: " << total << ". Sent to GPU: " << toGpu << "\n";
//total = 0;
//toGpu = 0;
// Unlock mutexes if previously locked. Unlocking a mutex not locked by the current thread
// or already locked is undefined behaviour, so checking has to be done
if ((f & 1))
@ -235,35 +224,6 @@ namespace chunkmanager
else
{
if (!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) chunkmesher::sendtogpu(c);
// Frustum Culling of chunk
total++;
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)
{
toGpu++;
chunkmesher::draw(c, model);
}
}
}
c->mutex_state.unlock();
@ -342,6 +302,9 @@ namespace chunkmanager
return i | (j << 10) | (k << 20);
}
std::unordered_map<std::uint32_t, Chunk::Chunk*>& getChunks(){ return chunks; }
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices(){ return chunks_indices; }
void destroy()
{
for (auto &n : chunks)

View File

@ -227,23 +227,6 @@ void sendtogpu(Chunk::Chunk* chunk)
chunk->setState(Chunk::CHUNK_STATE_MESH_LOADED, true);
}
void draw(Chunk::Chunk* chunk, glm::mat4 model)
{
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // wireframe mode
if(chunk->getState(Chunk::CHUNK_STATE_MESH_LOADED))
{
theShader->use();
theShader->setMat4("model", model);
theShader->setMat4("view", theCamera.getView());
theShader->setMat4("projection", theCamera.getProjection());
glBindVertexArray(chunk->VAO);
glDrawElements(GL_TRIANGLES, chunk->vIndex , GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
}
void quad(Chunk::Chunk* chunk, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec3 topRight,
glm::vec3 bottomRight, glm::vec3 normal, Block block, bool backFace)
{

View File

@ -4,13 +4,15 @@
#include <iostream>
#include <thread>
#include "chunkmanager.hpp"
#include "main.hpp"
#include "spacefilling.hpp"
#include "shader.hpp"
#define GLOBALS_DEFINER
#include "globals.hpp"
#undef GLOBALS_DEFINER
#include "chunkmanager.hpp"
#include "main.hpp"
#include "renderer.hpp"
#include "spacefilling.hpp"
#include "shader.hpp"
float deltaTime = 0.0f; // Time between current frame and last frame
float lastFrame = 0.0f; // Time of last frame
@ -59,12 +61,11 @@ int main()
std::cout << "Using GPU: " << glGetString(GL_VENDOR) << " " << glGetString(GL_RENDERER) << "\n";
SpaceFilling::initLUT();
renderer::init();
chunkmanager::init();
std::thread genThread = chunkmanager::initGenThread();
std::thread meshThread = chunkmanager::initMeshThread();
theShader = new Shader{"shaders/shader.vs", "shaders/shader.fs"};
while (!glfwWindowShouldClose(window))
{
// DeltaTime
@ -88,8 +89,6 @@ int main()
// Camera
theCamera.update(window, deltaTime);
theShader->setFloat("u_time", currentFrame);
theShader->setVec3("viewPos", theCamera.getPos());
// Reset blockping timeout if 200ms have passed
if(glfwGetTime() - lastBlockPick > 0.1) blockpick = false;
@ -97,6 +96,9 @@ int main()
// ChunkManager
chunkmanager::update(deltaTime);
// Render pass
renderer::render();
// Swap buffers to avoid tearing
glfwSwapBuffers(window);
glfwPollEvents();
@ -110,8 +112,7 @@ int main()
// Cleanup allocated memory
chunkmanager::destroy();
delete theShader;
renderer::destroy();
glfwTerminate();
return 0;

80
src/renderer.cpp Normal file
View File

@ -0,0 +1,80 @@
#include "chunkmanager.hpp"
#include "chunkmesher.hpp"
#include "renderer.hpp"
#include "globals.hpp"
namespace renderer{
Shader* theShader;
Shader* getRenderShader() { return theShader; }
void init(){
theShader = new Shader{"shaders/shader.vs", "shaders/shader.fs"};
}
void render(){
int total{0}, toGpu{0};
glm::vec4 frustumPlanes[6];
theCamera.getFrustumPlanes(frustumPlanes, true);
glm::vec3 cameraPos = theCamera.getPos();
int chunkX=static_cast<int>(cameraPos.x) / CHUNK_SIZE;
int chunkY=static_cast<int>(cameraPos.y) / CHUNK_SIZE;
int chunkZ=static_cast<int>(cameraPos.z) / CHUNK_SIZE;
for(int i = 0; i < chunks_volume; i++) {
Chunk::Chunk* c = chunkmanager::getChunks().at(chunkmanager::calculateIndex(chunkmanager::getChunksIndices()[i][0] +
chunkX, chunkmanager::getChunksIndices()[i][1] + chunkY, chunkmanager::getChunksIndices()[i][2] + chunkZ));
// Frustum Culling of chunk
total++;
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)
{
toGpu++;
if(c->getState(Chunk::CHUNK_STATE_MESH_LOADED) && c->vIndex > 0)
{
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // wireframe mode
theShader->use();
theShader->setMat4("model", model);
theShader->setMat4("view", theCamera.getView());
theShader->setMat4("projection", theCamera.getProjection());
glBindVertexArray(c->VAO);
glDrawElements(GL_TRIANGLES, c->vIndex , GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
}
}
//std::cout << "Chunks to mesh: " << to_mesh.size() << "\n";
//std::cout << "Chunks to generate: " << to_generate.size() << "\n";
//std::cout << "Total chunks to draw: " << total << ". Sent to GPU: " << toGpu << "\n";
}
void destroy(){
delete theShader;
}
};