diff --git a/bind/v4k.lua b/bind/v4k.lua index 007497c..e1c4570 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -1493,6 +1493,7 @@ typedef struct model_t { vec3 *meshcenters; aabb *meshbounds; float *meshradii; + bool *mesh_visible; int num_tris; handle vao, ibo, vbo, vao_instanced; int* lod_collapse_map; diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index ffe7998..bfef5b7 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -17783,6 +17783,7 @@ typedef struct model_t { vec3 *meshcenters; aabb *meshbounds; float *meshradii; + bool *mesh_visible; int num_tris; 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->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb)); 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++) { 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; 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; proj_modified[0] *= fov_scale; proj_modified[5] *= fov_scale; @@ -387265,14 +387267,14 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) { 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}); } } else { if(pass == -1 || pass == RENDER_PASS_OPAQUE) { 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 if (required_rs[i] == RENDER_PASS_OPAQUE) { drawcall_t call; @@ -387288,8 +387290,8 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) { 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 if (required_rs[i] == RENDER_PASS_TRANSPARENT) { drawcall_t call; @@ -387364,28 +387366,52 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ shader_bind(old_shader); } -void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) { - if(!m.iqm) return; - iqm_t *q = m.iqm; +static mat44 *pass_model_matrices = NULL; + +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) { 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 ) { - m.num_instances = count; - m.instanced_matrices = (float*)models; - model_set_state(m); + for (int i = 0; i < count; i++) { + bool any_visible = false; + for (int m = 0; m < q->nummeshes; 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) { - shader = m.shadow_program; + shader = mdl.shadow_program; } - model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); - model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0], proj, view); + model_set_uniforms(mdl, shader > 0 ? shader : mdl.program, mv, proj, view, pass_model_matrices[0]); + 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) { @@ -387796,6 +387822,7 @@ void model_destroy(model_t m) { FREE(m.meshcenters); FREE(m.meshbounds); FREE(m.meshradii); + FREE(m.mesh_visible); iqm_t *q = m.iqm; // if(m.mesh) mesh_destroy(m.mesh); diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index 91575e0..310fbaa 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -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->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb)); 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++) { 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; 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; proj_modified[0] *= fov_scale; proj_modified[5] *= fov_scale; @@ -5442,14 +5443,14 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) { 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}); } } else { if(pass == -1 || pass == RENDER_PASS_OPAQUE) { 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 if (required_rs[i] == RENDER_PASS_OPAQUE) { drawcall_t call; @@ -5465,8 +5466,8 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) { 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 if (required_rs[i] == RENDER_PASS_TRANSPARENT) { drawcall_t call; @@ -5541,28 +5542,52 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ shader_bind(old_shader); } -void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) { - if(!m.iqm) return; - iqm_t *q = m.iqm; +static mat44 *pass_model_matrices = NULL; + +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) { 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 ) { - m.num_instances = count; - m.instanced_matrices = (float*)models; - model_set_state(m); + for (int i = 0; i < count; i++) { + bool any_visible = false; + for (int m = 0; m < q->nummeshes; 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) { - shader = m.shadow_program; + shader = mdl.shadow_program; } - model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); - model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0], proj, view); + model_set_uniforms(mdl, shader > 0 ? shader : mdl.program, mv, proj, view, pass_model_matrices[0]); + 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) { @@ -5973,6 +5998,7 @@ void model_destroy(model_t m) { FREE(m.meshcenters); FREE(m.meshbounds); FREE(m.meshradii); + FREE(m.mesh_visible); iqm_t *q = m.iqm; // if(m.mesh) mesh_destroy(m.mesh); diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index e1bcfb2..e252f7f 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -815,6 +815,7 @@ typedef struct model_t { vec3 *meshcenters; aabb *meshbounds; float *meshradii; + bool *mesh_visible; int num_tris; handle vao, ibo, vbo, vao_instanced; diff --git a/engine/v4k.c b/engine/v4k.c index e613bb7..f91c176 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -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->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb)); 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++) { 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; 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; proj_modified[0] *= fov_scale; proj_modified[5] *= fov_scale; @@ -22296,14 +22297,14 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) { 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}); } } else { if(pass == -1 || pass == RENDER_PASS_OPAQUE) { 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 if (required_rs[i] == RENDER_PASS_OPAQUE) { drawcall_t call; @@ -22319,8 +22320,8 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) { 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 if (required_rs[i] == RENDER_PASS_TRANSPARENT) { drawcall_t call; @@ -22395,28 +22396,52 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ shader_bind(old_shader); } -void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) { - if(!m.iqm) return; - iqm_t *q = m.iqm; +static mat44 *pass_model_matrices = NULL; + +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) { 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 ) { - m.num_instances = count; - m.instanced_matrices = (float*)models; - model_set_state(m); + for (int i = 0; i < count; i++) { + bool any_visible = false; + for (int m = 0; m < q->nummeshes; 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) { - shader = m.shadow_program; + shader = mdl.shadow_program; } - model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); - model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0], proj, view); + model_set_uniforms(mdl, shader > 0 ? shader : mdl.program, mv, proj, view, pass_model_matrices[0]); + 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) { @@ -22827,6 +22852,7 @@ void model_destroy(model_t m) { FREE(m.meshcenters); FREE(m.meshbounds); FREE(m.meshradii); + FREE(m.mesh_visible); iqm_t *q = m.iqm; // if(m.mesh) mesh_destroy(m.mesh); diff --git a/engine/v4k.h b/engine/v4k.h index 1a033c4..c5dd782 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -3850,6 +3850,7 @@ typedef struct model_t { vec3 *meshcenters; aabb *meshbounds; float *meshradii; + bool *mesh_visible; int num_tris; handle vao, ibo, vbo, vao_instanced;