Optimize ChunkMesh generation/rendering

This commit is contained in:
2025-06-07 20:38:51 +02:00
parent 56b08e59f7
commit d1b1129ff4
4 changed files with 45 additions and 28 deletions
+7 -5
View File
@@ -1,6 +1,7 @@
#version 100
attribute vec4 position;
attribute vec2 position;
attribute float height;
attribute vec4 material;
varying vec2 f_uv;
@@ -13,9 +14,10 @@ uniform vec3 chunk_position;
void main ()
{
f_uv = position.xz / 4.0;
f_uv = position.xy / 4.0;
f_material = material;
f_height = position.y;
gl_Position = projection * view * (position + vec4(chunk_position, 0.0));
f_height = height;
vec4 pos = vec4 (position.x, height, position.y, 1.0);
gl_Position = projection * view * (pos + vec4(chunk_position, 0.0));
}
-3
View File
@@ -1,8 +1,5 @@
#include "chunkman.h"
/* TODO: Sort chunks by distance to player, and generate them like
that. Will require having a queue or similar structure. */
extern int render_distance;
int n_frame_chunks;
+37 -20
View File
@@ -8,17 +8,18 @@ ChunkMesh *
ChunkMesh_build (Chunk *chunk, Chunk *nr, Chunk *nd, Chunk *nc)
/* nd --- down neighbor; nr --- right neighbor; nc --- corner neighbor */
{
vec3 *positions = malloc (sizeof (vec3) * CHUNKMESH_SIZE);
float *materials = malloc (sizeof (float) * 4 * CHUNKMESH_SIZE);
ivec2 *positions = malloc (sizeof (ivec2) * CHUNKMESH_SIZE);
float *heights = malloc (sizeof (float) * CHUNKMESH_SIZE);
ivec4 *materials = malloc (sizeof (ivec4) * CHUNKMESH_SIZE);
unsigned int *indices = malloc (sizeof (unsigned int) * CHUNK_SIZE * 6);
int m_i = 0, i_i = 0;
int i_i = 0;
for (int z = 0; z < CHUNKMESH_DIM; ++z)
{
for (int x = 0; x < CHUNKMESH_DIM; ++x)
{
float height = chunk->heightmap[INDEX (x, z)];
float material_id = chunk->materialmap[INDEX (x, z)];
char material_id = chunk->materialmap[INDEX (x, z)];
if (x == CHUNK_DIM && z < CHUNK_DIM && nr != NULL)
{
@@ -38,11 +39,14 @@ ChunkMesh_build (Chunk *chunk, Chunk *nr, Chunk *nd, Chunk *nc)
material_id = nc->materialmap[INDEX (0, 0)];
}
glm_vec3_copy ((vec3) { x, height, z }, positions[CMINDEX (x, z)]);
materials[m_i++] = material_id == 1 ? 1 : 0;
materials[m_i++] = material_id == 2 ? 1 : 0;
materials[m_i++] = material_id == 3 ? 1 : 0;
materials[m_i++] = material_id == 4 ? 1 : 0;
positions[CMINDEX (x, z)][0] = x;
heights[CMINDEX (x, z)] = height;
positions[CMINDEX (x, z)][1] = z;
materials[CMINDEX (x, z)][0] = material_id == 1 ? 1 : 0;
materials[CMINDEX (x, z)][1] = material_id == 2 ? 1 : 0;
materials[CMINDEX (x, z)][2] = material_id == 3 ? 1 : 0;
materials[CMINDEX (x, z)][3] = material_id == 4 ? 1 : 0;
if (x < CHUNK_DIM && z < CHUNK_DIM)
{
@@ -70,23 +74,30 @@ ChunkMesh_build (Chunk *chunk, Chunk *nr, Chunk *nd, Chunk *nc)
ChunkMesh *mesh = malloc (sizeof (ChunkMesh));
glGenBuffers (1, &mesh->pbo);
glGenBuffers (1, &mesh->hbo);
glGenBuffers (1, &mesh->mbo);
glGenBuffers (1, &mesh->ebo);
glBindBuffer (GL_ARRAY_BUFFER, mesh->pbo);
glBufferData (GL_ARRAY_BUFFER, sizeof (vec3) * CHUNKMESH_SIZE, positions, GL_STATIC_DRAW);
glBufferData (GL_ARRAY_BUFFER, sizeof (ivec2) * CHUNKMESH_SIZE, positions, GL_STATIC_DRAW);
glEnableVertexAttribArray (0);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof (vec3), 0);
glVertexAttribPointer (0, 2, GL_INT, GL_FALSE, sizeof (ivec2), 0);
glBindBuffer (GL_ARRAY_BUFFER, mesh->mbo);
glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 4 * CHUNKMESH_SIZE, materials, GL_STATIC_DRAW);
glBindBuffer (GL_ARRAY_BUFFER, mesh->hbo);
glBufferData (GL_ARRAY_BUFFER, sizeof (float) * CHUNKMESH_SIZE, heights, GL_STATIC_DRAW);
glEnableVertexAttribArray (1);
glVertexAttribPointer (1, 4, GL_FLOAT, GL_FALSE, sizeof (float) * 4, 0);
glVertexAttribPointer (1, 1, GL_FLOAT, GL_FALSE, sizeof (float), 0);
glBindBuffer (GL_ARRAY_BUFFER, mesh->mbo);
glBufferData (GL_ARRAY_BUFFER, sizeof (ivec4) * CHUNKMESH_SIZE, materials, GL_STATIC_DRAW);
glEnableVertexAttribArray (2);
glVertexAttribPointer (2, 4, GL_INT, GL_FALSE, sizeof (ivec4), 0);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->ebo);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int) * CHUNK_SIZE * 6, indices, GL_STATIC_DRAW);
free (positions);
free (heights);
free (materials);
free (indices);
@@ -96,21 +107,27 @@ ChunkMesh_build (Chunk *chunk, Chunk *nr, Chunk *nd, Chunk *nc)
void
ChunkMesh_bind (ChunkMesh *mesh)
/* The EBO is the same for all chunk meshes, so we can bind it just
once before we render them all. */
once before we render them all. Same for the PBO. The only thing
that changes is the heights and materials. */
{
glBindBuffer (GL_ARRAY_BUFFER, mesh->pbo);
glEnableVertexAttribArray (0);
glVertexAttribPointer (0, 2, GL_INT, GL_FALSE, sizeof (ivec2), 0);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->ebo);
}
void
ChunkMesh_render (ChunkMesh *mesh, bool wireframe)
{
glBindBuffer (GL_ARRAY_BUFFER, mesh->pbo);
glEnableVertexAttribArray (0);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof (vec3), 0);
glBindBuffer (GL_ARRAY_BUFFER, mesh->mbo);
glBindBuffer (GL_ARRAY_BUFFER, mesh->hbo);
glEnableVertexAttribArray (1);
glVertexAttribPointer (1, 4, GL_FLOAT, GL_FALSE, sizeof (float) * 4, 0);
glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, sizeof (float), 0);
glBindBuffer (GL_ARRAY_BUFFER, mesh->mbo);
glEnableVertexAttribArray (2);
glVertexAttribPointer (2, 4, GL_INT, GL_FALSE, sizeof (ivec4), 0);
glDrawElements (wireframe ? GL_LINES : GL_TRIANGLES, CHUNK_SIZE * 6, GL_UNSIGNED_INT, 0);
}
+1
View File
@@ -13,6 +13,7 @@
typedef struct ChunkMesh
{
unsigned int pbo;
unsigned int hbo;
unsigned int mbo;
unsigned int ebo;
} ChunkMesh;