commit 4f5cb4dc20278fa511955ad253adb2eb0252a40e
parent 85c7eca6038d4186603dd73b6fe136ec827a7cf9
Author: Christian Ermann <christianermann@gmail.com>
Date:   Sat, 28 May 2022 20:15:12 -0700
Render terrain surface and caves.
Diffstat:
7 files changed, 134 insertions(+), 19 deletions(-)
diff --git a/include/marching_cubes.h b/include/marching_cubes.h
@@ -1,13 +1,18 @@
 #ifndef MC_H
 #define MC_H
 
-#include "vec.h"
+#include "mesh.h"
 #include "sdf.h"
 
 int MC_index(const Vec3 corners[8], SDF f, float isolevel);
 
-int MC_vertices(const Vec3 corners[8], SDF f, float isolevel, int mc_index,
-        Vec3 vertices[3]);
+int MC_vertices(
+        const Vec3 corners[8],
+        SDF f,
+        float isolevel,
+        int mc_index,
+        Vertex vertices[3]
+);
 
 int MC_indices(int mc_index, unsigned int vertex_offset,
         const unsigned int edge_offsets[12], unsigned int indices[15]);
diff --git a/include/mesh.h b/include/mesh.h
@@ -6,9 +6,14 @@
 #include "glad/glad.h"
 
 typedef struct {
+    Vec3 position;
+    Vec3 normal;
+} Vertex;
+
+typedef struct {
     unsigned int vertex_capacity;
     unsigned int vertex_count;
-    Vec3 *vertices;
+    Vertex *vertices;
 
     unsigned int index_capacity;
     unsigned int index_count;
diff --git a/shaders/basic.fs b/shaders/basic.fs
@@ -1,6 +1,7 @@
 #version 330 core
 
 in vec3 frag_pos;
+in vec3 frag_norm;
 
 out vec4 frag_color;
 
@@ -16,7 +17,9 @@ void main()
     vec3 normal = normalize(cross(dy, dx));
 
     float slope = (normal.y + 1.0) * 0.5;
-    vec3 object_color = mix(vec3(1.0, 0.8, 0.6), vec3(0.7, 0.7, 0.7), slope);
+
+    normal = mix(normal, -frag_norm, 1 - slope);
+    vec3 object_color = mix(vec3(0.6, 0.7, 0.5), vec3(0.5, 0.6, 0.7), slope);
 
     float d = length(pointlight_pos - frag_pos);
     float attenuation = 1.0 / (1.0 + 0.022 * d + 0.0019 * d * d);
diff --git a/shaders/basic.vs b/shaders/basic.vs
@@ -1,13 +1,16 @@
 #version 330 core
 
 layout(location = 0) in vec3 in_position;
+layout(location = 1) in vec3 in_normal;
 
 out vec3 frag_pos;
+out vec3 frag_norm;
 
 uniform mat4 camera;
 
 void main()
 {
     frag_pos = in_position;
-    gl_Position = camera * vec4(in_position, 1.0);
+    frag_norm = in_normal;
+    gl_Position = camera * vec4(frag_pos, 1.0);
 }
diff --git a/src/main.c b/src/main.c
@@ -18,6 +18,39 @@ float perlinSDF(const Vec3 p)
         + 0.1f * perlin(p[0] * 0.1f, p[1] * 0.1f, p[2] * 0.1f);
 }
 
+float caveSDF(const Vec3 p)
+{
+    float o1 = perlin(p[0] * 0.01f, p[1] * 0.01f, p[2] * 0.01f);
+
+    return o1;
+}
+
+float terrainSDF(const Vec3 p)
+{
+    float o1 = 50.0f * perlin(p[0] * 0.005f, 0.0f, p[2] * 0.005f);
+    float o2 =  2.0f * perlin(p[0] * 0.050f, 0.0f, p[2] * 0.050f);
+    float o3 =  1.0f * perlin(p[0] * 0.100f, 0.0f, p[2] * 0.100f);
+
+    float surface = p[1] - o1 - o2 - o3;
+    float cave = perlinSDF(p);
+
+    float k  = 32.0f;
+    float h = 0.5f - 0.5f * (cave - surface) / k;
+    if (h < 0.0f)
+    {
+        h = 0.0f;
+    }
+    if (h > 1.0f)
+    {
+        h = 1.0f;
+    }
+
+    float a = cave * (1.0f - h) + surface * h;
+    float b = k * h * (1.0f - h);
+
+    return a + b;
+}
+
 float sphereSDF(const float p[3])
 {
     return sqrtf(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]) - 25.0f;
@@ -46,7 +79,7 @@ int main(int argc, char** argv)
     ChunkManager chunk_manager = ChunkManager_create(
             camera->position,
             3,
-            perlinSDF,
+            terrainSDF,
             0.0f
     );
     ChunkManager_drawChunks(&chunk_manager);
@@ -59,7 +92,6 @@ int main(int argc, char** argv)
         if (glfwGetKey(app->window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
         {
             glfwSetInputMode(app->window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
-            //glfwSetWindowShouldClose(app->window, true);
         }
         if (glfwGetKey(app->window, GLFW_KEY_ENTER) == GLFW_PRESS)
         {
diff --git a/src/marching_cubes.c b/src/marching_cubes.c
@@ -330,23 +330,70 @@ static void MC_interpolateVertexPosition(const Vec3 a, const Vec3 b, SDF f,
     return;
 }
 
+// Inigo Quilez trapezoidal algorithm                                       
+// These normals could be computed in vertex shader if it had access to the SDF
+static void MC_normal(const Vec3 p, SDF f, Vec3 dst)
+{
+    const float h = 0.01f;
+
+    Vec3 x1 = {  h, -h, -h };
+    Vec3 x2 = { -h, -h,  h };
+    Vec3 x3 = { -h,  h, -h };
+    Vec3 x4 = {  h,  h,  h };
+
+    Vec3 x5, x6, x7, x8;
+    Vec3_add(p, x1, x5);
+    Vec3_add(p, x2, x6);
+    Vec3_add(p, x3, x7);
+    Vec3_add(p, x4, x8);
+
+    Vec3_scale(x1, f(x5), x1);
+    Vec3_scale(x2, f(x6), x2);
+    Vec3_scale(x3, f(x7), x3);
+    Vec3_scale(x4, f(x8), x4);
+
+    Vec3_add(x1, x2, x1);
+    Vec3_add(x3, x4, x3);
+    Vec3_add(x1, x3, x1);
+
+    Vec3_normalize(x1, dst);
+}
+
 int MC_vertices(const Vec3 corners[8], SDF f, float isolevel, int mc_index,
-        Vec3 vertices[3])
+        Vertex vertices[3])
 {
     if (EDGE_TABLE[mc_index] & 1)
     {
-        MC_interpolateVertexPosition(corners[0], corners[1], f, isolevel,
-                vertices[0]);
+        MC_interpolateVertexPosition(
+                corners[0],
+                corners[1],
+                f,
+                isolevel,
+                vertices[0].position
+        );
+        MC_normal(vertices[0].position, f, vertices[0].normal);
     }
     if (EDGE_TABLE[mc_index] & 8)
     {
-        MC_interpolateVertexPosition(corners[3], corners[0], f, isolevel,
-                vertices[1]);
+        MC_interpolateVertexPosition(
+                corners[3],
+                corners[0],
+                f,
+                isolevel,
+                vertices[1].position
+        );
+        MC_normal(vertices[1].position, f, vertices[1].normal);
     }
     if (EDGE_TABLE[mc_index] & 256)
     {
-        MC_interpolateVertexPosition(corners[0], corners[4], f, isolevel,
-                vertices[2]);
+        MC_interpolateVertexPosition(
+                corners[0],
+                corners[4],
+                f,
+                isolevel,
+                vertices[2].position
+        );
+        MC_normal(vertices[2].position, f, vertices[2].normal);
     }
     return 3;
 }
diff --git a/src/mesh.c b/src/mesh.c
@@ -17,12 +17,32 @@ void Mesh_init(Mesh *m, unsigned int vertex_count, unsigned int index_count)
 
     glGenBuffers(1, &m->vbo);
     glBindBuffer(GL_ARRAY_BUFFER, m->vbo);
-    glBufferData(GL_ARRAY_BUFFER, sizeof *m->vertices * vertex_count, NULL,
-            GL_STATIC_DRAW);
-
-    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vec3), (GLvoid*)0);
+    glBufferData(
+            GL_ARRAY_BUFFER,
+            sizeof *m->vertices * vertex_count,
+            NULL,
+            GL_STATIC_DRAW
+    );
+
+    glVertexAttribPointer(
+            0,
+            3,
+            GL_FLOAT,
+            GL_FALSE,
+            sizeof(Vertex),
+            (GLvoid*)0
+    );
     glEnableVertexAttribArray(0);
 
+    glVertexAttribPointer(
+            1,
+            3,
+            GL_FLOAT,
+            GL_FALSE,
+            sizeof(Vertex),
+            (GLvoid*)sizeof(Vec3)
+    );
+    glEnableVertexAttribArray(1);
 
     glGenBuffers(1, &m->ebo);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ebo);