frustum culling

main
Dominik Madarász 2024-08-24 13:33:05 +02:00
parent 708629c80f
commit d3cbd939c7
4 changed files with 294 additions and 6 deletions

View File

@ -385267,11 +385267,66 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
q->textures[i] = invalid; q->textures[i] = invalid;
struct iqmmesh *mesh = &q->meshes[i]; struct iqmmesh *mesh = &q->meshes[i];
#if 1 #if 0
GLfloat *pos = verts[q->meshes[i].first_vertex].position; GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]); m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
#else #else
// for (int j = 0; j < ) int first_triangle = mesh->first_triangle;
int num_triangles = mesh->num_triangles;
int vertex_count = 0;
vec3 center = {0};
aabb box = {
.min = {FLT_MAX, FLT_MAX, FLT_MAX},
.max = {-FLT_MAX, -FLT_MAX, -FLT_MAX}
};
float max_distance_squared = 0.0f;
for (int j = first_triangle; j < num_triangles+first_triangle; ++j) {
struct iqmtriangle *tri = &tris[j];
// calculate mesh center
for (int k = 0; k < 3; ++k) {
iqm_vertex *v = &verts[tri->vertex[k]];
GLfloat *pos = v->position;
center.x += pos[0];
center.y += pos[1];
center.z += pos[2];
vertex_count++;
// Update AABB
box.min.x = fminf(box.min.x, pos[0]);
box.min.y = fminf(box.min.y, pos[1]);
box.min.z = fminf(box.min.z, pos[2]);
box.max.x = fmaxf(box.max.x, pos[0]);
box.max.y = fmaxf(box.max.y, pos[1]);
box.max.z = fmaxf(box.max.z, pos[2]);
}
}
if (vertex_count) {
center.x /= vertex_count;
center.y /= vertex_count;
center.z /= vertex_count;
}
// Compute bounding sphere radius
for (int j = first_triangle; j < num_triangles + first_triangle; ++j) {
struct iqmtriangle *tri = &tris[j];
for (int k = 0; k < 3; ++k) {
int vertex_index = tri->vertex[k];
GLfloat *pos = verts[vertex_index].position;
float dx = pos[0] - center.x;
float dy = pos[1] - center.y;
float dz = pos[2] - center.z;
float distance_squared = dx*dx + dy*dy + dz*dz;
max_distance_squared = fmaxf(max_distance_squared, distance_squared);
}
}
m->meshcenters[i] = center;
m->meshbounds[i] = box;
m->meshradii[i] = sqrtf(max_distance_squared);
#endif #endif
} }
@ -385939,6 +385994,28 @@ void model_clear_frustum(model_t *m) {
m->frustum_enabled = 0; m->frustum_enabled = 0;
} }
static inline
bool model_is_visible(model_t m, int mesh, mat44 model_mat) {
if(!m.iqm) return false;
if(!m.frustum_enabled) return true;
sphere s; s.c = transform344(model_mat, m.meshcenters[mesh]); s.r = m.meshradii[mesh];
if (!frustum_test_sphere(m.frustum_state, s)) {
return false;
}
aabb box = m.meshbounds[mesh];
box.min = transform344(model_mat, box.min);
box.max = transform344(model_mat, box.max);
if (!frustum_test_aabb(m.frustum_state, box)) {
return false;
}
return true;
}
static static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) { void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return; if(!m.iqm) return;
@ -385971,11 +386048,14 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) { if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
array_push(drawcalls, (drawcall_t){i, -1}); array_push(drawcalls, (drawcall_t){i, -1});
} }
} else { } else {
if(pass == -1 || pass == RENDER_PASS_OPAQUE) { if(pass == -1 || pass == RENDER_PASS_OPAQUE) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
// collect opaque drawcalls // collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) { if (required_rs[i] == RENDER_PASS_OPAQUE) {
drawcall_t call; drawcall_t call;
@ -385991,6 +386071,8 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) { if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
// collect transparent drawcalls // collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) { if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
drawcall_t call; drawcall_t call;
@ -388087,8 +388169,22 @@ int scene_obj_distance_compare(const void *a, const void *b) {
void scene_render(int flags) { void scene_render(int flags) {
camera_t *cam = camera_get_active(); camera_t *cam = camera_get_active();
#if 1
mat44 projview; multiply44x2(projview, cam->proj, cam->view); mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum frustum_state = frustum_build(projview); frustum frustum_state = frustum_build(projview);
#else
static frustum frustum_state;
do_once {
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum_state = frustum_build(projview);
}
if (input_down(KEY_T)) {
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum_state = frustum_build(projview);
}
#endif
if(flags & SCENE_BACKGROUND) { if(flags & SCENE_BACKGROUND) {
if(last_scene->skybox.program) { if(last_scene->skybox.program) {

View File

@ -3611,11 +3611,66 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
q->textures[i] = invalid; q->textures[i] = invalid;
struct iqmmesh *mesh = &q->meshes[i]; struct iqmmesh *mesh = &q->meshes[i];
#if 1 #if 0
GLfloat *pos = verts[q->meshes[i].first_vertex].position; GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]); m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
#else #else
// for (int j = 0; j < ) int first_triangle = mesh->first_triangle;
int num_triangles = mesh->num_triangles;
int vertex_count = 0;
vec3 center = {0};
aabb box = {
.min = {FLT_MAX, FLT_MAX, FLT_MAX},
.max = {-FLT_MAX, -FLT_MAX, -FLT_MAX}
};
float max_distance_squared = 0.0f;
for (int j = first_triangle; j < num_triangles+first_triangle; ++j) {
struct iqmtriangle *tri = &tris[j];
// calculate mesh center
for (int k = 0; k < 3; ++k) {
iqm_vertex *v = &verts[tri->vertex[k]];
GLfloat *pos = v->position;
center.x += pos[0];
center.y += pos[1];
center.z += pos[2];
vertex_count++;
// Update AABB
box.min.x = fminf(box.min.x, pos[0]);
box.min.y = fminf(box.min.y, pos[1]);
box.min.z = fminf(box.min.z, pos[2]);
box.max.x = fmaxf(box.max.x, pos[0]);
box.max.y = fmaxf(box.max.y, pos[1]);
box.max.z = fmaxf(box.max.z, pos[2]);
}
}
if (vertex_count) {
center.x /= vertex_count;
center.y /= vertex_count;
center.z /= vertex_count;
}
// Compute bounding sphere radius
for (int j = first_triangle; j < num_triangles + first_triangle; ++j) {
struct iqmtriangle *tri = &tris[j];
for (int k = 0; k < 3; ++k) {
int vertex_index = tri->vertex[k];
GLfloat *pos = verts[vertex_index].position;
float dx = pos[0] - center.x;
float dy = pos[1] - center.y;
float dz = pos[2] - center.z;
float distance_squared = dx*dx + dy*dy + dz*dz;
max_distance_squared = fmaxf(max_distance_squared, distance_squared);
}
}
m->meshcenters[i] = center;
m->meshbounds[i] = box;
m->meshradii[i] = sqrtf(max_distance_squared);
#endif #endif
} }
@ -4283,6 +4338,28 @@ void model_clear_frustum(model_t *m) {
m->frustum_enabled = 0; m->frustum_enabled = 0;
} }
static inline
bool model_is_visible(model_t m, int mesh, mat44 model_mat) {
if(!m.iqm) return false;
if(!m.frustum_enabled) return true;
sphere s; s.c = transform344(model_mat, m.meshcenters[mesh]); s.r = m.meshradii[mesh];
if (!frustum_test_sphere(m.frustum_state, s)) {
return false;
}
aabb box = m.meshbounds[mesh];
box.min = transform344(model_mat, box.min);
box.max = transform344(model_mat, box.max);
if (!frustum_test_aabb(m.frustum_state, box)) {
return false;
}
return true;
}
static static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) { void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return; if(!m.iqm) return;
@ -4315,11 +4392,14 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) { if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
array_push(drawcalls, (drawcall_t){i, -1}); array_push(drawcalls, (drawcall_t){i, -1});
} }
} else { } else {
if(pass == -1 || pass == RENDER_PASS_OPAQUE) { if(pass == -1 || pass == RENDER_PASS_OPAQUE) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
// collect opaque drawcalls // collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) { if (required_rs[i] == RENDER_PASS_OPAQUE) {
drawcall_t call; drawcall_t call;
@ -4335,6 +4415,8 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) { if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
// collect transparent drawcalls // collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) { if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
drawcall_t call; drawcall_t call;

View File

@ -513,8 +513,22 @@ int scene_obj_distance_compare(const void *a, const void *b) {
void scene_render(int flags) { void scene_render(int flags) {
camera_t *cam = camera_get_active(); camera_t *cam = camera_get_active();
#if 1
mat44 projview; multiply44x2(projview, cam->proj, cam->view); mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum frustum_state = frustum_build(projview); frustum frustum_state = frustum_build(projview);
#else
static frustum frustum_state;
do_once {
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum_state = frustum_build(projview);
}
if (input_down(KEY_T)) {
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum_state = frustum_build(projview);
}
#endif
if(flags & SCENE_BACKGROUND) { if(flags & SCENE_BACKGROUND) {
if(last_scene->skybox.program) { if(last_scene->skybox.program) {

View File

@ -20410,11 +20410,66 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
q->textures[i] = invalid; q->textures[i] = invalid;
struct iqmmesh *mesh = &q->meshes[i]; struct iqmmesh *mesh = &q->meshes[i];
#if 1 #if 0
GLfloat *pos = verts[q->meshes[i].first_vertex].position; GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]); m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
#else #else
// for (int j = 0; j < ) int first_triangle = mesh->first_triangle;
int num_triangles = mesh->num_triangles;
int vertex_count = 0;
vec3 center = {0};
aabb box = {
.min = {FLT_MAX, FLT_MAX, FLT_MAX},
.max = {-FLT_MAX, -FLT_MAX, -FLT_MAX}
};
float max_distance_squared = 0.0f;
for (int j = first_triangle; j < num_triangles+first_triangle; ++j) {
struct iqmtriangle *tri = &tris[j];
// calculate mesh center
for (int k = 0; k < 3; ++k) {
iqm_vertex *v = &verts[tri->vertex[k]];
GLfloat *pos = v->position;
center.x += pos[0];
center.y += pos[1];
center.z += pos[2];
vertex_count++;
// Update AABB
box.min.x = fminf(box.min.x, pos[0]);
box.min.y = fminf(box.min.y, pos[1]);
box.min.z = fminf(box.min.z, pos[2]);
box.max.x = fmaxf(box.max.x, pos[0]);
box.max.y = fmaxf(box.max.y, pos[1]);
box.max.z = fmaxf(box.max.z, pos[2]);
}
}
if (vertex_count) {
center.x /= vertex_count;
center.y /= vertex_count;
center.z /= vertex_count;
}
// Compute bounding sphere radius
for (int j = first_triangle; j < num_triangles + first_triangle; ++j) {
struct iqmtriangle *tri = &tris[j];
for (int k = 0; k < 3; ++k) {
int vertex_index = tri->vertex[k];
GLfloat *pos = verts[vertex_index].position;
float dx = pos[0] - center.x;
float dy = pos[1] - center.y;
float dz = pos[2] - center.z;
float distance_squared = dx*dx + dy*dy + dz*dz;
max_distance_squared = fmaxf(max_distance_squared, distance_squared);
}
}
m->meshcenters[i] = center;
m->meshbounds[i] = box;
m->meshradii[i] = sqrtf(max_distance_squared);
#endif #endif
} }
@ -21082,6 +21137,28 @@ void model_clear_frustum(model_t *m) {
m->frustum_enabled = 0; m->frustum_enabled = 0;
} }
static inline
bool model_is_visible(model_t m, int mesh, mat44 model_mat) {
if(!m.iqm) return false;
if(!m.frustum_enabled) return true;
sphere s; s.c = transform344(model_mat, m.meshcenters[mesh]); s.r = m.meshradii[mesh];
if (!frustum_test_sphere(m.frustum_state, s)) {
return false;
}
aabb box = m.meshbounds[mesh];
box.min = transform344(model_mat, box.min);
box.max = transform344(model_mat, box.max);
if (!frustum_test_aabb(m.frustum_state, box)) {
return false;
}
return true;
}
static static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) { void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return; if(!m.iqm) return;
@ -21114,11 +21191,14 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) { if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
array_push(drawcalls, (drawcall_t){i, -1}); array_push(drawcalls, (drawcall_t){i, -1});
} }
} else { } else {
if(pass == -1 || pass == RENDER_PASS_OPAQUE) { if(pass == -1 || pass == RENDER_PASS_OPAQUE) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
// collect opaque drawcalls // collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) { if (required_rs[i] == RENDER_PASS_OPAQUE) {
drawcall_t call; drawcall_t call;
@ -21134,6 +21214,8 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) { if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) {
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
if (!model_is_visible(m, i, model_mat)) continue;
// collect transparent drawcalls // collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) { if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
drawcall_t call; drawcall_t call;
@ -23230,8 +23312,22 @@ int scene_obj_distance_compare(const void *a, const void *b) {
void scene_render(int flags) { void scene_render(int flags) {
camera_t *cam = camera_get_active(); camera_t *cam = camera_get_active();
#if 1
mat44 projview; multiply44x2(projview, cam->proj, cam->view); mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum frustum_state = frustum_build(projview); frustum frustum_state = frustum_build(projview);
#else
static frustum frustum_state;
do_once {
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum_state = frustum_build(projview);
}
if (input_down(KEY_T)) {
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum_state = frustum_build(projview);
}
#endif
if(flags & SCENE_BACKGROUND) { if(flags & SCENE_BACKGROUND) {
if(last_scene->skybox.program) { if(last_scene->skybox.program) {