From 383fb60686e966a4e26218f192eaa15240b48586 Mon Sep 17 00:00:00 2001 From: EmaMaker Date: Thu, 9 Mar 2023 17:30:40 +0100 Subject: [PATCH] proper frustum culling --- include/camera.hpp | 32 +++++++++++++++++++-- src/chunkmanager.cpp | 66 +++++++++++++++++++------------------------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/include/camera.hpp b/include/camera.hpp index 17f16c2..93eea63 100644 --- a/include/camera.hpp +++ b/include/camera.hpp @@ -18,7 +18,7 @@ public: { view = glm::mat4(1.0f); // note that we're translating the scene in the reverse direction of where we want to move - projection = glm::perspective(glm::radians(90.0f), 800.0f / 600.0f, 0.1f, 200.0f); + projection = glm::perspective(glm::radians(90.0f), 800.0f / 600.0f, 1.0f, 200.0f); } void update(GLFWwindow *window, float deltaTime) @@ -49,7 +49,7 @@ public: void viewPortCallBack(GLFWwindow *window, int width, int height) { - projection = glm::perspective(glm::radians(70.0f), (float)width / (float)height, 0.1f, 350.0f); + projection = glm::perspective(glm::radians(80.0f), (float)width / (float)height, 1.0f, 350.0f); } void mouseCallback(GLFWwindow *window, double xpos, double ypos) @@ -97,6 +97,32 @@ public: return projection; } + // Plane extraction as per Gribb&Hartmann + // 6 planes, each with 4 components (a,b,c,d) + void getFrustumPlanes(glm::vec4 planes[6], bool normalize){ + glm::mat4 mat = transpose(projection*view); + + // This just compressed the code below + float ap = mat[3][0], bp = mat[3][1], cp = mat[3][2], dp = mat[3][3]; + + planes[0] = glm::vec4(ap + mat[0][0], bp + mat[0][1], cp + mat[0][2], dp + mat[0][3]); + planes[1] = glm::vec4(ap - mat[0][0], bp - mat[0][1], cp - mat[0][2], dp - mat[0][3]); + planes[2] = glm::vec4(ap + mat[1][0], bp + mat[1][1], cp + mat[1][2], dp + mat[1][3]); + planes[3] = glm::vec4(ap - mat[1][0], bp - mat[1][1], cp - mat[1][2], dp - mat[1][3]); + planes[4] = glm::vec4(ap + mat[2][0], bp + mat[2][1], cp + mat[2][2], dp + mat[2][3]); + planes[5] = glm::vec4(ap - mat[2][0], bp - mat[2][1], cp - mat[2][2], dp - mat[2][3]); + + if(normalize) + for(int i = 0; i < 6; i++){ + float mag = sqrt(planes[i].x + planes[i].x + planes[i].y * planes[i].y + + planes[i].z*planes[i].z); + + planes[i] /= mag; + } + } + + + private: glm::vec3 cameraPos = glm::vec3(static_cast(CHUNK_SIZE)*24, 40.0f, static_cast(CHUNK_SIZE)*24); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); @@ -109,4 +135,4 @@ private: float yaw, pitch; }; -#endif \ No newline at end of file +#endif diff --git a/src/chunkmanager.cpp b/src/chunkmanager.cpp index c15ff95..6b43f28 100644 --- a/src/chunkmanager.cpp +++ b/src/chunkmanager.cpp @@ -93,6 +93,7 @@ namespace chunkmanager int total{0}, toGpu{0}; int rr{RENDER_DISTANCE * RENDER_DISTANCE}; uint8_t f = 0; + glm::vec4 frustumPlanes[6]; void update(float deltaTime) { @@ -103,6 +104,7 @@ namespace chunkmanager // Iterate over all chunks, in concentric spheres starting fron the player and going outwards // Eq. of the sphere (x - a)² + (y - b)² + (z - c)² = r² glm::vec3 cameraPos = theCamera.getPos(); + theCamera.getFrustumPlanes(frustumPlanes, true); int chunkX{(static_cast(cameraPos.x)) / CHUNK_SIZE}, chunkY{(static_cast(cameraPos.y)) / CHUNK_SIZE}, chunkZ{(static_cast(cameraPos.z)) / CHUNK_SIZE}; @@ -175,9 +177,9 @@ namespace chunkmanager b = false; } } - // std::cout << "Total chunks to draw: " << total << ". Sent to GPU: " << toGpu << "\n"; - // total = 0; - // toGpu = 0; + std::cout << "Total chunks to draw: " << total << ". Sent to GPU: " << toGpu << "\n"; + total = 0; + toGpu = 0; if ((f & 1)) mutex_queue_generate.unlock(); @@ -188,7 +190,6 @@ namespace chunkmanager // Generation and meshing happen in two separate threads from the main one // Chunk states are used to decide which actions need to be done on the chunk and queues+mutexes to pass the chunks between the threads // Uploading data to GPU still needs to be done in the main thread, or another OpenGL context needs to be opened, which further complicates stuff - // For now using frustum culling decreases performance (somehow) void updateChunk(uint32_t index, uint16_t i, uint16_t j, uint16_t k) { if (chunks.find(index) == chunks.end()) @@ -253,48 +254,39 @@ namespace chunkmanager c->setState(Chunk::CHUNK_STATE_MESH_LOADED, true); } - glm::vec3 chunk = c->getPosition(); - glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk); - // chunkmesher::draw(c, model); + // Frustum Culling of chunk total++; - int a{0}; - for (int i = 0; i < 8; i++) - { - glm::vec4 vertex = glm::vec4(chunk.x + (float)(i & 1), chunk.y + (float)((i & 2) >> 1), chunk.z + (float)((i & 4) >> 2), 500.0f) * (theCamera.getProjection() * theCamera.getView() * model); - vertex = glm::normalize(vertex); + glm::vec3 chunk = c->getPosition(); + glm::vec4 chunkW = glm::vec4(chunk.x*static_cast(CHUNK_SIZE), chunk.y*static_cast(CHUNK_SIZE), chunk.z*static_cast(CHUNK_SIZE),1.0); + glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk); - a += (-vertex.w <= vertex.x && vertex.x <= vertex.w && -vertex.w <= vertex.y && vertex.y <= vertex.w /*&& -vertex.w < vertex.z && vertex.z < vertex.w*/); - } - if (a) + bool out=false; + // First test, check if all the corners of the chunk are outside any of the + // planes + for(int p = 0; p < 6; p++){ + + int 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); } } } - - // if ((f & 4) == 4) - // { - // glm::vec3 chunk = c->getPosition(); - // glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk); - // // chunkmesher::draw(c, model); - // // total++; - - // // int a{0}; - // // for (int i = 0; i < 8; i++) - // // { - // // glm::vec4 vertex = glm::vec4(chunk.x + (float)(i & 1), chunk.y + (float)((i & 2) >> 1), chunk.z + (float)((i & 4) >> 2), 500.0f) * (theCamera.getProjection() * theCamera.getView() * model); - // // vertex = glm::normalize(vertex); - - // // a += (-vertex.w <= vertex.x && vertex.x <= vertex.w && -vertex.w <= vertex.y && vertex.y <= vertex.w /*&& -vertex.w < vertex.z && vertex.z < vertex.w*/); - // // } - // // if (a) - // // { - // // toGpu++; - // chunkmesher::draw(c, model); - // // } - // } c->mutex_state.unlock(); } }