separate rendering in a dedicated file
parent
b4f3bdad06
commit
2b1991ff2b
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef RENDERER_H
|
||||
#define RENDERER_H
|
||||
|
||||
#include "shader.hpp"
|
||||
|
||||
namespace renderer{
|
||||
void init();
|
||||
void render();
|
||||
void destroy();
|
||||
Shader* getRenderShader();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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})
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
23
src/main.cpp
23
src/main.cpp
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
};
|
Loading…
Reference in New Issue