proper frustum culling

vertex-deduplication
EmaMaker 2023-03-09 17:30:40 +01:00
parent e69c58abd3
commit 383fb60686
2 changed files with 58 additions and 40 deletions

View File

@ -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<float>(CHUNK_SIZE)*24, 40.0f, static_cast<float>(CHUNK_SIZE)*24);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);

View File

@ -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<int>(cameraPos.x)) / CHUNK_SIZE}, chunkY{(static_cast<int>(cameraPos.y)) / CHUNK_SIZE}, chunkZ{(static_cast<int>(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<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);
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();
}
}