per-instance frustum culling

main
Dominik Madarász 2024-09-03 12:31:42 +02:00
parent aec753e2c4
commit 9bfb5b47fd
6 changed files with 133 additions and 51 deletions

View File

@ -1493,6 +1493,7 @@ typedef struct model_t {
vec3 *meshcenters; vec3 *meshcenters;
aabb *meshbounds; aabb *meshbounds;
float *meshradii; float *meshradii;
bool *mesh_visible;
int num_tris; int num_tris;
handle vao, ibo, vbo, vao_instanced; handle vao, ibo, vbo, vao_instanced;
int* lod_collapse_map; int* lod_collapse_map;

View File

@ -17783,6 +17783,7 @@ typedef struct model_t {
vec3 *meshcenters; vec3 *meshcenters;
aabb *meshbounds; aabb *meshbounds;
float *meshradii; float *meshradii;
bool *mesh_visible;
int num_tris; int num_tris;
handle vao, ibo, vbo, vao_instanced; handle vao, ibo, vbo, vao_instanced;
@ -386398,6 +386399,7 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3)); m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb)); m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb));
m->meshradii = CALLOC(hdr->num_meshes, sizeof(float)); m->meshradii = CALLOC(hdr->num_meshes, sizeof(float));
m->mesh_visible = CALLOC(hdr->num_meshes, sizeof(bool));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
@ -387195,7 +387197,7 @@ bool model_is_visible(model_t m, int mesh, mat44 model_mat, mat44 proj, mat44 vi
mat44 proj_modified; mat44 proj_modified;
copy44(proj_modified, proj); copy44(proj_modified, proj);
// Increase FOV by 1.5 // Increase FOV by GLOBAL_FRUSTUM_FOV_MULTIPLIER
float fov_scale = 1.0f / GLOBAL_FRUSTUM_FOV_MULTIPLIER; float fov_scale = 1.0f / GLOBAL_FRUSTUM_FOV_MULTIPLIER;
proj_modified[0] *= fov_scale; proj_modified[0] *= fov_scale;
proj_modified[5] *= fov_scale; proj_modified[5] *= fov_scale;
@ -387265,13 +387267,13 @@ 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, proj, view)) continue; if (!m.mesh_visible[i]) 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, proj, view)) continue; if (!m.mesh_visible[i]) continue;
// collect opaque drawcalls // collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) { if (required_rs[i] == RENDER_PASS_OPAQUE) {
@ -387288,7 +387290,7 @@ 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, proj, view)) continue; if (!m.mesh_visible[i]) continue;
// collect transparent drawcalls // collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) { if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
@ -387364,28 +387366,52 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
shader_bind(old_shader); shader_bind(old_shader);
} }
void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) { static mat44 *pass_model_matrices = NULL;
if(!m.iqm) return;
iqm_t *q = m.iqm; void model_render_instanced_pass(model_t mdl, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) {
if(!mdl.iqm) return;
iqm_t *q = mdl.iqm;
if (active_shadowmap && active_shadowmap->skip_render) { if (active_shadowmap && active_shadowmap->skip_render) {
return; return;
} }
mat44 mv; multiply44x2(mv, view, models[0]); pass_model_matrices = array_resize(pass_model_matrices, count); //@leak
memcpy(pass_model_matrices, models, count * sizeof(mat44));
memset(mdl.mesh_visible, 0, q->nummeshes * sizeof(bool));
if( count != m.num_instances ) { for (int i = 0; i < count; i++) {
m.num_instances = count; bool any_visible = false;
m.instanced_matrices = (float*)models; for (int m = 0; m < q->nummeshes; m++) {
model_set_state(m); bool visible = model_is_visible(mdl, m, pass_model_matrices[i], proj, view);
mdl.mesh_visible[m] |= visible;
any_visible |= visible;
}
if (!any_visible) {
array_erase_fast(pass_model_matrices, i);
i--;
count--;
}
}
if (count == 0) {
return;
}
mat44 mv; multiply44x2(mv, view, pass_model_matrices[0]);
if( count != mdl.num_instances ) {
mdl.num_instances = count;
mdl.instanced_matrices = (float*)pass_model_matrices;
model_set_state(mdl);
} }
if (model_getpass() > RENDER_PASS_SHADOW_BEGIN && model_getpass() < RENDER_PASS_SHADOW_END) { if (model_getpass() > RENDER_PASS_SHADOW_BEGIN && model_getpass() < RENDER_PASS_SHADOW_END) {
shader = m.shadow_program; shader = mdl.shadow_program;
} }
model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_set_uniforms(mdl, shader > 0 ? shader : mdl.program, mv, proj, view, pass_model_matrices[0]);
model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0], proj, view); model_draw_call(mdl, shader > 0 ? shader : mdl.program, pass, pos44(view), pass_model_matrices[0], proj, view);
} }
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) { void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) {
@ -387796,6 +387822,7 @@ void model_destroy(model_t m) {
FREE(m.meshcenters); FREE(m.meshcenters);
FREE(m.meshbounds); FREE(m.meshbounds);
FREE(m.meshradii); FREE(m.meshradii);
FREE(m.mesh_visible);
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);

View File

@ -4575,6 +4575,7 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3)); m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb)); m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb));
m->meshradii = CALLOC(hdr->num_meshes, sizeof(float)); m->meshradii = CALLOC(hdr->num_meshes, sizeof(float));
m->mesh_visible = CALLOC(hdr->num_meshes, sizeof(bool));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
@ -5372,7 +5373,7 @@ bool model_is_visible(model_t m, int mesh, mat44 model_mat, mat44 proj, mat44 vi
mat44 proj_modified; mat44 proj_modified;
copy44(proj_modified, proj); copy44(proj_modified, proj);
// Increase FOV by 1.5 // Increase FOV by GLOBAL_FRUSTUM_FOV_MULTIPLIER
float fov_scale = 1.0f / GLOBAL_FRUSTUM_FOV_MULTIPLIER; float fov_scale = 1.0f / GLOBAL_FRUSTUM_FOV_MULTIPLIER;
proj_modified[0] *= fov_scale; proj_modified[0] *= fov_scale;
proj_modified[5] *= fov_scale; proj_modified[5] *= fov_scale;
@ -5442,13 +5443,13 @@ 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, proj, view)) continue; if (!m.mesh_visible[i]) 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, proj, view)) continue; if (!m.mesh_visible[i]) continue;
// collect opaque drawcalls // collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) { if (required_rs[i] == RENDER_PASS_OPAQUE) {
@ -5465,7 +5466,7 @@ 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, proj, view)) continue; if (!m.mesh_visible[i]) continue;
// collect transparent drawcalls // collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) { if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
@ -5541,28 +5542,52 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
shader_bind(old_shader); shader_bind(old_shader);
} }
void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) { static mat44 *pass_model_matrices = NULL;
if(!m.iqm) return;
iqm_t *q = m.iqm; void model_render_instanced_pass(model_t mdl, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) {
if(!mdl.iqm) return;
iqm_t *q = mdl.iqm;
if (active_shadowmap && active_shadowmap->skip_render) { if (active_shadowmap && active_shadowmap->skip_render) {
return; return;
} }
mat44 mv; multiply44x2(mv, view, models[0]); pass_model_matrices = array_resize(pass_model_matrices, count); //@leak
memcpy(pass_model_matrices, models, count * sizeof(mat44));
memset(mdl.mesh_visible, 0, q->nummeshes * sizeof(bool));
if( count != m.num_instances ) { for (int i = 0; i < count; i++) {
m.num_instances = count; bool any_visible = false;
m.instanced_matrices = (float*)models; for (int m = 0; m < q->nummeshes; m++) {
model_set_state(m); bool visible = model_is_visible(mdl, m, pass_model_matrices[i], proj, view);
mdl.mesh_visible[m] |= visible;
any_visible |= visible;
}
if (!any_visible) {
array_erase_fast(pass_model_matrices, i);
i--;
count--;
}
}
if (count == 0) {
return;
}
mat44 mv; multiply44x2(mv, view, pass_model_matrices[0]);
if( count != mdl.num_instances ) {
mdl.num_instances = count;
mdl.instanced_matrices = (float*)pass_model_matrices;
model_set_state(mdl);
} }
if (model_getpass() > RENDER_PASS_SHADOW_BEGIN && model_getpass() < RENDER_PASS_SHADOW_END) { if (model_getpass() > RENDER_PASS_SHADOW_BEGIN && model_getpass() < RENDER_PASS_SHADOW_END) {
shader = m.shadow_program; shader = mdl.shadow_program;
} }
model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_set_uniforms(mdl, shader > 0 ? shader : mdl.program, mv, proj, view, pass_model_matrices[0]);
model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0], proj, view); model_draw_call(mdl, shader > 0 ? shader : mdl.program, pass, pos44(view), pass_model_matrices[0], proj, view);
} }
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) { void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) {
@ -5973,6 +5998,7 @@ void model_destroy(model_t m) {
FREE(m.meshcenters); FREE(m.meshcenters);
FREE(m.meshbounds); FREE(m.meshbounds);
FREE(m.meshradii); FREE(m.meshradii);
FREE(m.mesh_visible);
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);

View File

@ -815,6 +815,7 @@ typedef struct model_t {
vec3 *meshcenters; vec3 *meshcenters;
aabb *meshbounds; aabb *meshbounds;
float *meshradii; float *meshradii;
bool *mesh_visible;
int num_tris; int num_tris;
handle vao, ibo, vbo, vao_instanced; handle vao, ibo, vbo, vao_instanced;

View File

@ -21429,6 +21429,7 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3)); m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb)); m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb));
m->meshradii = CALLOC(hdr->num_meshes, sizeof(float)); m->meshradii = CALLOC(hdr->num_meshes, sizeof(float));
m->mesh_visible = CALLOC(hdr->num_meshes, sizeof(bool));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
@ -22226,7 +22227,7 @@ bool model_is_visible(model_t m, int mesh, mat44 model_mat, mat44 proj, mat44 vi
mat44 proj_modified; mat44 proj_modified;
copy44(proj_modified, proj); copy44(proj_modified, proj);
// Increase FOV by 1.5 // Increase FOV by GLOBAL_FRUSTUM_FOV_MULTIPLIER
float fov_scale = 1.0f / GLOBAL_FRUSTUM_FOV_MULTIPLIER; float fov_scale = 1.0f / GLOBAL_FRUSTUM_FOV_MULTIPLIER;
proj_modified[0] *= fov_scale; proj_modified[0] *= fov_scale;
proj_modified[5] *= fov_scale; proj_modified[5] *= fov_scale;
@ -22296,13 +22297,13 @@ 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, proj, view)) continue; if (!m.mesh_visible[i]) 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, proj, view)) continue; if (!m.mesh_visible[i]) continue;
// collect opaque drawcalls // collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) { if (required_rs[i] == RENDER_PASS_OPAQUE) {
@ -22319,7 +22320,7 @@ 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, proj, view)) continue; if (!m.mesh_visible[i]) continue;
// collect transparent drawcalls // collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) { if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
@ -22395,28 +22396,52 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
shader_bind(old_shader); shader_bind(old_shader);
} }
void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) { static mat44 *pass_model_matrices = NULL;
if(!m.iqm) return;
iqm_t *q = m.iqm; void model_render_instanced_pass(model_t mdl, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) {
if(!mdl.iqm) return;
iqm_t *q = mdl.iqm;
if (active_shadowmap && active_shadowmap->skip_render) { if (active_shadowmap && active_shadowmap->skip_render) {
return; return;
} }
mat44 mv; multiply44x2(mv, view, models[0]); pass_model_matrices = array_resize(pass_model_matrices, count); //@leak
memcpy(pass_model_matrices, models, count * sizeof(mat44));
memset(mdl.mesh_visible, 0, q->nummeshes * sizeof(bool));
if( count != m.num_instances ) { for (int i = 0; i < count; i++) {
m.num_instances = count; bool any_visible = false;
m.instanced_matrices = (float*)models; for (int m = 0; m < q->nummeshes; m++) {
model_set_state(m); bool visible = model_is_visible(mdl, m, pass_model_matrices[i], proj, view);
mdl.mesh_visible[m] |= visible;
any_visible |= visible;
}
if (!any_visible) {
array_erase_fast(pass_model_matrices, i);
i--;
count--;
}
}
if (count == 0) {
return;
}
mat44 mv; multiply44x2(mv, view, pass_model_matrices[0]);
if( count != mdl.num_instances ) {
mdl.num_instances = count;
mdl.instanced_matrices = (float*)pass_model_matrices;
model_set_state(mdl);
} }
if (model_getpass() > RENDER_PASS_SHADOW_BEGIN && model_getpass() < RENDER_PASS_SHADOW_END) { if (model_getpass() > RENDER_PASS_SHADOW_BEGIN && model_getpass() < RENDER_PASS_SHADOW_END) {
shader = m.shadow_program; shader = mdl.shadow_program;
} }
model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_set_uniforms(mdl, shader > 0 ? shader : mdl.program, mv, proj, view, pass_model_matrices[0]);
model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0], proj, view); model_draw_call(mdl, shader > 0 ? shader : mdl.program, pass, pos44(view), pass_model_matrices[0], proj, view);
} }
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) { void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) {
@ -22827,6 +22852,7 @@ void model_destroy(model_t m) {
FREE(m.meshcenters); FREE(m.meshcenters);
FREE(m.meshbounds); FREE(m.meshbounds);
FREE(m.meshradii); FREE(m.meshradii);
FREE(m.mesh_visible);
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);

View File

@ -3850,6 +3850,7 @@ typedef struct model_t {
vec3 *meshcenters; vec3 *meshcenters;
aabb *meshbounds; aabb *meshbounds;
float *meshradii; float *meshradii;
bool *mesh_visible;
int num_tris; int num_tris;
handle vao, ibo, vbo, vao_instanced; handle vao, ibo, vbo, vao_instanced;