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);