commit 981f0f9c0b582d41d40809e00d9a4e22322e4b1f
parent 6dad92883cdbc38f8a51c0a4c5d22abff95b0f33
Author: Christian Ermann <christianermann@gmail.com>
Date:   Sun, 29 May 2022 16:11:06 -0700
Prototyped frustum culling system.
Diffstat:
5 files changed, 218 insertions(+), 6 deletions(-)
diff --git a/include/camera.h b/include/camera.h
@@ -5,6 +5,11 @@
 #include "vec.h"
 
 typedef struct {
+    Vec3 n;
+    Vec3 p;
+} Plane;
+
+typedef struct {
     Vec3 position;
     float yaw;
     float pitch;
@@ -22,6 +27,13 @@ typedef struct {
     Vec3 right;
 
     Mat4 matrix;
+
+    float near_h;
+    float near_w;
+    float far_h;
+    float far_w;
+    Plane frustum[6];
+
 } Camera;
 
 Camera *Camera_make(float x, float y, float z, float yaw, float pitch);
@@ -41,4 +53,7 @@ void Camera_updateMatrix(Camera* camera);
 // Process user input to adjust camera's position and orientation
 void Camera_move(Camera *camera, UserInput *input);
 
+void Camera_updateFrustum(Camera *camera);
+int Camera_sphereInFrustum(const Camera *camera, Vec3 p, float r);
+
 #endif
diff --git a/include/chunk_manager.h b/include/chunk_manager.h
@@ -1,6 +1,7 @@
 #ifndef CHUNK_MANAGER_H
 #define CHUNK_MANAGER_H
 
+#include "camera.h"
 #include "chunk.h"
 #include "threadpool.h"
 
@@ -29,6 +30,6 @@ void ChunkManager_free(ChunkManager *cm);
 
 void ChunkManager_recenter(ChunkManager *cm, const Vec3 target);
 
-void ChunkManager_drawChunks(const ChunkManager *cm);
+void ChunkManager_drawChunks(const ChunkManager *cm, const Camera *camera);
 
 #endif
diff --git a/src/camera.c b/src/camera.c
@@ -36,6 +36,12 @@ void Camera_defaultSettings(Camera* camera)
     camera->far = 200.0f;
     camera->speed = 0.1f;
     camera->sensitivity = 0.3f;
+
+    camera->near_h = 2 * tan(camera->fovy / 2) * camera->near;
+    camera->near_w = camera->near_h * camera->aspect;
+
+    camera->far_h = 2 * tan(camera->fovy / 2) * camera->far;
+    camera->far_w = camera->far_h * camera->aspect;
 }
 
 void Camera_updateRotation(Camera* camera, float dx, float dy)
@@ -103,4 +109,176 @@ void Camera_move(Camera *camera, UserInput *input)
     Camera_updatePosition(camera, input->move_dx, input->move_dy, input->move_dz);
     Camera_updateVectors(camera);
     Camera_updateMatrix(camera);
+    Camera_updateFrustum(camera);
+}
+
+void Camera_updateFrustum(Camera *camera)
+{
+    // Near plane
+    camera->frustum[0].n[0] = camera->front[0];
+    camera->frustum[0].n[1] = camera->front[1];
+    camera->frustum[0].n[2] = camera->front[2];
+    Vec3_scale(
+            camera->front,
+            camera->near,
+            camera->frustum[0].p
+    );
+    Vec3_add(
+            camera->position,
+            camera->frustum[0].p,
+            camera->frustum[0].p
+    );
+
+    // Far plane
+    camera->frustum[1].n[0] = -camera->front[0];
+    camera->frustum[1].n[1] = -camera->front[1];
+    camera->frustum[1].n[2] = -camera->front[2];
+    Vec3_scale(
+            camera->front,
+            camera->far,
+            camera->frustum[1].p
+    );
+    Vec3_add(
+            camera->position,
+            camera->frustum[1].p,
+            camera->frustum[1].p
+    );
+
+    // Used to store vector in plane
+    Vec3 a;
+
+    // Top plane
+    Vec3_scale(
+            camera->up,
+            camera->near_h / 2,
+            camera->frustum[2].p
+    );
+    Vec3_add(
+            camera->frustum[0].p,
+            camera->frustum[2].p,
+            camera->frustum[2].p
+    );
+
+    Vec3_sub(
+            camera->frustum[2].p,
+            camera->position,
+            a
+    );
+
+    Vec3_mul(
+            a,
+            camera->right,
+            camera->frustum[2].n
+    );
+    Vec3_normalize(
+            camera->frustum[2].n,
+            camera->frustum[2].n
+    );
+
+    // Bottom plane
+    Vec3_scale(
+            camera->up,
+            camera->near_h / 2,
+            camera->frustum[3].p
+    );
+    Vec3_sub(
+            camera->frustum[0].p,
+            camera->frustum[3].p,
+            camera->frustum[3].p
+    );
+
+    Vec3_sub(
+            camera->frustum[3].p,
+            camera->position,
+            a
+    );
+
+    Vec3_mul(
+            camera->right,
+            a,
+            camera->frustum[3].n
+    );
+    Vec3_normalize(
+            camera->frustum[3].n,
+            camera->frustum[3].n
+    );
+
+    // Left plane
+    Vec3_scale(
+            camera->right,
+            camera->near_w / 2,
+            camera->frustum[4].p
+    );
+    Vec3_sub(
+            camera->frustum[0].p,
+            camera->frustum[4].p,
+            camera->frustum[4].p
+    );
+
+    Vec3_sub(
+            camera->frustum[4].p,
+            camera->position,
+            a
+    );
+
+    Vec3_mul(
+            a,
+            camera->up,
+            camera->frustum[4].n
+    );
+    Vec3_normalize(
+            camera->frustum[4].n,
+            camera->frustum[4].n
+    );
+
+    // Right plane
+    Vec3_scale(
+            camera->right,
+            camera->near_w / 2,
+            camera->frustum[5].p
+    );
+    Vec3_add(
+            camera->frustum[0].p,
+            camera->frustum[5].p,
+            camera->frustum[5].p
+    );
+
+    Vec3_sub(
+            camera->frustum[5].p,
+            camera->position,
+            a
+    );
+
+    Vec3_mul(
+            camera->up,
+            a,
+            camera->frustum[5].n
+    );
+    Vec3_normalize(
+            camera->frustum[5].n,
+            camera->frustum[5].n
+    );
+
+}
+
+static float planeSDF(const Plane *p, const Vec3 r)
+{
+    return Vec3_dot(p->n, r) - Vec3_dot(p->n, p->p);
+}
+
+int Camera_sphereInFrustum(const Camera *camera, Vec3 p, float r)
+{
+    for (int i = 0; i < 6; i++)
+    {
+        float distance = planeSDF(&camera->frustum[i], p);
+        if (distance < -r)
+        {
+            return 0;
+        }
+        else if (distance < r)
+        {
+            return 1;
+        }
+    }
+    return 1;
 }
diff --git a/src/chunk_manager.c b/src/chunk_manager.c
@@ -124,6 +124,13 @@ static void ChunkManager_worldToChunk(const Vec3 src, IVec3 dst)
     dst[2] = (int)floorf(src[2] / CHUNK_WIDTH);
 }
 
+static void ChunkManager_chunkToWorld(const IVec3 src, Vec3 dst)
+{
+    dst[0] = src[0] * CHUNK_WIDTH;
+    dst[1] = src[1] * CHUNK_WIDTH;
+    dst[2] = src[2] * CHUNK_WIDTH;
+}
+
 ChunkManager ChunkManager_create(const Vec3 target, int radius, SDF f,
         float isolevel)
 {
@@ -178,10 +185,21 @@ void ChunkManager_recenter(ChunkManager *cm, const Vec3 target)
     }
 }
 
-void ChunkManager_drawChunks(const ChunkManager *cm)
+void ChunkManager_drawChunks(const ChunkManager *cm, const Camera *camera)
 {
     for (int i = 0; i < cm->chunk_count; i++)
     {
-        Chunk_drawMesh(&cm->chunks[i]);
+        Vec3 chunk_center;
+        ChunkManager_chunkToWorld(cm->chunks[i].origin, chunk_center);
+        chunk_center[0] += CHUNK_WIDTH / 2;
+        chunk_center[1] += CHUNK_WIDTH / 2;
+        chunk_center[2] += CHUNK_WIDTH / 2;
+
+        float chunk_radius = CHUNK_WIDTH * 0.866025f;
+
+        if (Camera_sphereInFrustum(camera, chunk_center, chunk_radius))
+        {
+            Chunk_drawMesh(&cm->chunks[i]);
+        }
     }
 }
diff --git a/src/main.c b/src/main.c
@@ -78,11 +78,11 @@ int main(int argc, char** argv)
 
     ChunkManager chunk_manager = ChunkManager_create(
             camera->position,
-            3,
+            5,
             terrainSDF,
             0.0f
     );
-    ChunkManager_drawChunks(&chunk_manager);
+    ChunkManager_drawChunks(&chunk_manager, camera);
 
     Shader *shader = Shader_make("shaders/basic.vs", "shaders/basic.fs");
     Shader_use(shader);
@@ -114,7 +114,7 @@ int main(int argc, char** argv)
         Shader_setVec3(shader, "pointlight_pos", camera->position);
 
         ChunkManager_recenter(&chunk_manager, camera->position);
-        ChunkManager_drawChunks(&chunk_manager);
+        ChunkManager_drawChunks(&chunk_manager, camera);
         
         glfwSwapBuffers(app->window);
         glfwPollEvents();