terrain

Real-time terrain generation using marching cubes
git clone git://git.christianermann.dev/terrain
Log | Files | Refs | README | LICENSE

commit 981f0f9c0b582d41d40809e00d9a4e22322e4b1f
parent 6dad92883cdbc38f8a51c0a4c5d22abff95b0f33
Author: Christian Ermann <christianermann@gmail.com>
Date:   Sun, 29 May 2022 16:11:06 -0700

Prototyped frustum culling system.

Diffstat:
Minclude/camera.h | 15+++++++++++++++
Minclude/chunk_manager.h | 3++-
Msrc/camera.c | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/chunk_manager.c | 22++++++++++++++++++++--
Msrc/main.c | 6+++---
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();