wip: frustum culling (per-model for now)

main
Dominik Madarász 2024-08-24 13:02:36 +02:00
parent d1cc36207f
commit 708629c80f
12 changed files with 612 additions and 87 deletions

View File

@ -1387,6 +1387,8 @@ typedef struct model_t {
int num_verts;
void *tris;
vec3 *meshcenters;
aabb *meshbounds;
float *meshradii;
int num_tris;
handle vao, ibo, vbo, vao_instanced;
int* lod_collapse_map;
@ -1400,6 +1402,8 @@ typedef struct model_t {
unsigned num_instances;
int stored_flags;
renderstate_t rs[NUM_RENDER_PASSES];
bool frustum_enabled;
frustum frustum_state;
} model_t;
enum BILLBOARD_MODE {
BILLBOARD_X = 0x1,
@ -1423,6 +1427,10 @@ enum BILLBOARD_MODE {
void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass);
void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass);
void model_set_texture(model_t*, texture_t t);
bool model_has_transparency_mesh(model_t m, int mesh);
bool model_has_transparency(model_t m);
void model_set_frustum(model_t *m, frustum f);
void model_clear_frustum(model_t *m);
bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out);
void model_destroy(model_t);
unsigned model_getpass();
@ -1555,6 +1563,11 @@ typedef struct object_t {
float anim_speed;
aabb bounds;
unsigned billboard;
bool disable_frustum_check;
handle* old_texture_ids;
texture_t* old_textures;
float distance;
bool skip_draw;
bool light_cached;
} object_t;
object_t object();

View File

@ -0,0 +1,58 @@
// render map
#include "v4k.h"
int main() {
window_create(80, WINDOW_MSAA8);
window_title(__FILE__);
window_fps_unlock();
// load skybox
skybox_t sky = skybox("bridge3", 0);
// load static scene
model_t map, prop;
map = model(option("--model","sorting_test.obj"), 0); // MODEL_NO_TEXTURES);
prop = model(option("--model","sorting_test2.obj"), 0); // MODEL_NO_TEXTURES);
shader_bind(map.program);
skybox_sh_shader(&sky);
prop.program = map.program;
// define scene
object_t *prop_obj = scene_spawn();
object_model(prop_obj, prop);
object_t *map_obj = scene_spawn();
object_model(map_obj, map);
// camera
camera_t cam = camera();
cam.speed *= 0.05f;
// demo loop
while (window_swap())
{
// input
if( input_down(KEY_ESC) ) break;
if( input_down(KEY_F5) ) window_reload();
if( input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen() ^ 1 );
if( input_down(KEY_X) ) window_screenshot(__FILE__ ".png");
if( input_down(KEY_Z) ) window_record(__FILE__ ".mp4");
// fps camera
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
camera_moveby(&cam, wasdecq);
camera_fps(&cam, mouse.x,mouse.y);
window_cursor( !active );
// draw skybox
profile("Skybox") {
skybox_render(&sky, cam.proj, cam.view);
}
scene_render(SCENE_FOREGROUND);
}
}

View File

@ -7,21 +7,14 @@ int main() {
window_title(__FILE__);
window_fps_unlock();
// load all fx files
fx_load("fx**.fs");
// load skybox
// skybox_t sky = skybox(flag("--mie") ? 0 : "hdr/Tokyo_BigSight_1k.hdr", 0); // --mie for rayleigh/mie scattering
skybox_t sky = skybox("bridge3", 0); // --mie for rayleigh/mie scattering
skybox_t sky = skybox("bridge3", 0);
// load static scene
model_t map;
map = model(option("--model","sorting_test.obj"), 0); // MODEL_NO_TEXTURES);
shader_bind(map.program);
skybox_sh_shader(&sky);
// translation44(map.pivot, 0,-1,0);
// rotate44(map.pivot, -90,1,0,0);
// scale44(map.pivot, 10,10,10);
// camera
camera_t cam = camera();
@ -53,12 +46,6 @@ int main() {
mat44 M; copy44(M, map.pivot);// translate44(M, 0,0,0); scale44(M, scale,scale,scale);
// apply post-fxs from here
fx_begin();
model_render_pass(map, cam.proj, cam.view, M, 0, -1);
// post-fxs end here
fx_end(0);
model_render(map, cam.proj, cam.view, M, 0);
}
}

View File

@ -0,0 +1,52 @@
# Blender 4.2.1 LTS MTL File: 'None'
# www.blender.org
newmtl Material.006
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd E:/v4games/v4k/demos/art/matcaps/material3.jpg
newmtl Material.007
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd E:/v4games/v4k/demos/art/matcaps/test_steel.jpg
newmtl Material.008
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.059941 0.801453 0.027650
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.228070
illum 9
newmtl Material.009
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.015818 0.013069 0.801024
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.294737
illum 9
newmtl Material.010
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800063 0.776954 0.209224
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.480702
illum 9

View File

@ -0,0 +1,70 @@
# Blender 4.2.1 LTS
# www.blender.org
mtllib sorting_test2.mtl
o Cube.001
v 6.691334 -10.979122 -7.520660
v 6.691334 -10.979120 -11.912354
v -6.691334 -10.979122 -7.520660
v -6.691334 -10.979120 -11.912354
v 6.691333 -15.370816 -7.520660
v 6.691333 -15.370816 -11.912354
v -6.691335 -15.370814 -7.520660
v -6.691335 -15.370814 -11.912354
v 6.691334 -1.734141 -7.520659
v 6.691334 -1.734141 -11.912354
v -6.691334 -1.734140 -7.520659
v -6.691334 -1.734140 -11.912354
v 6.691334 -6.125834 -7.520660
v 6.691334 -6.125834 -11.912353
v -6.691333 -6.125834 -7.520660
v -6.691333 -6.125834 -11.912353
v 6.691335 6.836245 -7.520658
v 6.691335 6.836244 -11.912353
v -6.691332 6.836244 -7.520658
v -6.691332 6.836243 -11.912353
v 6.691335 2.444547 -7.520658
v 6.691335 2.444549 -11.912353
v -6.691333 2.444548 -7.520658
v -6.691333 2.444550 -11.912353
vn -0.0000 1.0000 -0.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -0.0000 -1.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.008
f 1/1/1 2/2/1 4/3/1 3/4/1
f 3/4/2 4/3/2 8/5/2 7/6/2
f 7/6/3 8/5/3 6/7/3 5/8/3
f 5/8/4 6/7/4 2/9/4 1/10/4
f 3/11/5 7/6/5 5/8/5 1/12/5
f 8/5/6 4/13/6 2/14/6 6/7/6
usemtl Material.009
f 9/1/1 10/2/1 12/3/1 11/4/1
f 11/4/2 12/3/2 16/5/2 15/6/2
f 15/6/3 16/5/3 14/7/3 13/8/3
f 13/8/4 14/7/4 10/9/4 9/10/4
f 11/11/5 15/6/5 13/8/5 9/12/5
f 16/5/6 12/13/6 10/14/6 14/7/6
usemtl Material.010
f 17/1/1 18/2/1 20/3/1 19/4/1
f 19/4/2 20/3/2 24/5/2 23/6/2
f 23/6/3 24/5/3 22/7/3 21/8/3
f 21/8/4 22/7/4 18/9/4 17/10/4
f 19/11/5 23/6/5 21/8/5 17/12/5
f 24/5/6 20/13/6 18/14/6 22/7/6

View File

@ -17645,6 +17645,8 @@ typedef struct model_t {
int num_verts;
void *tris;
vec3 *meshcenters;
aabb *meshbounds;
float *meshradii;
int num_tris;
handle vao, ibo, vbo, vao_instanced;
@ -17662,6 +17664,9 @@ typedef struct model_t {
int stored_flags;
renderstate_t rs[NUM_RENDER_PASSES];
bool frustum_enabled;
frustum frustum_state;
} model_t;
enum BILLBOARD_MODE {
@ -17688,6 +17693,10 @@ API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *mode
API void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass);
API void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass);
API void model_set_texture(model_t*, texture_t t);
API bool model_has_transparency_mesh(model_t m, int mesh);
API bool model_has_transparency(model_t m);
API void model_set_frustum(model_t *m, frustum f);
API void model_clear_frustum(model_t *m);
API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out);
API void model_destroy(model_t);
@ -17884,6 +17893,13 @@ typedef struct object_t {
float anim_speed;
aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool disable_frustum_check;
// internal states
array(handle) old_texture_ids;
array(texture_t) old_textures;
float distance;
bool skip_draw;
bool light_cached; //< used by scene to update light data
} object_t;
@ -385244,12 +385260,19 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb));
m->meshradii = CALLOC(hdr->num_meshes, sizeof(float));
for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id;
q->textures[i] = invalid;
struct iqmmesh *mesh = &q->meshes[i];
#if 1
GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
#else
// for (int j = 0; j < )
#endif
}
const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
@ -385876,6 +385899,46 @@ int drawcall_compare(const void *a, const void *b) {
return da->order < db->order ? 1 : da->order > db->order ? -1 : 0;
}
bool model_has_transparency_mesh(model_t m, int mesh) {
if(!m.iqm) return false;
iqm_t *q = m.iqm;
if (m.flags & MODEL_TRANSPARENT) {
return true;
}
if (m.materials[mesh].layer[0].map.color.a < 1 || (m.materials[mesh].layer[0].map.texture && m.materials[mesh].layer[0].map.texture->transparent)) {
return true;
}
if (m.shading == SHADING_PBR && (m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
return true;
}
return false;
}
bool model_has_transparency(model_t m) {
if(!m.iqm) return false;
iqm_t *q = m.iqm;
for (int i = 0; i < q->nummeshes; i++) {
if (model_has_transparency_mesh(m, i)) {
return true;
}
}
return false;
}
void model_set_frustum(model_t *m, frustum f) {
m->frustum_enabled = 1;
m->frustum_state = f;
}
void model_clear_frustum(model_t *m) {
m->frustum_enabled = 0;
}
static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return;
@ -385897,13 +385960,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
required_rs[i] = rs_idx;
if (required_rs[i] < RENDER_PASS_OVERRIDES_BEGIN) {
if (m.flags & MODEL_TRANSPARENT) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.materials[i].layer[0].map.color.a < 1 || (m.materials[i].layer[0].map.texture && m.materials[i].layer[0].map.texture->transparent)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.shading == SHADING_PBR && (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
if (model_has_transparency_mesh(m, i)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
}
@ -385943,7 +386000,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
// calculate distance from camera
// @todo: improve me, uses first mesh triangle
{
call.distance = len3(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
call.distance = len3sq(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
}
if (m.shading == SHADING_PBR)
@ -386372,6 +386429,8 @@ void model_destroy(model_t m) {
}
array_free(m.texture_names);
FREE(m.meshcenters);
FREE(m.meshbounds);
FREE(m.meshradii);
iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh);
@ -388020,8 +388079,16 @@ light_t* scene_index_light(unsigned light_index) {
return &last_scene->lights[light_index];
}
static
int scene_obj_distance_compare(const void *a, const void *b) {
const object_t *da = a, *db = b;
return da->distance < db->distance ? 1 : da->distance > db->distance ? -1 : 0;
}
void scene_render(int flags) {
camera_t *cam = camera_get_active();
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum frustum_state = frustum_build(projview);
if(flags & SCENE_BACKGROUND) {
if(last_scene->skybox.program) {
@ -388047,18 +388114,18 @@ void scene_render(int flags) {
model_t *model = &obj->model;
anim_t *anim = &obj->anim;
mat44 *views = (mat44*)(&cam->view);
obj->skip_draw = !obj->disable_frustum_check && !frustum_test_aabb(frustum_state, model_aabb(*model, obj->transform));
// @todo: avoid heap allocs here?
static array(handle) old_texture_ids = 0;
static array(texture_t) old_textures = 0;
if (obj->skip_draw) continue;
int do_retexturing = model->iqm && model->shading != SHADING_PBR && array_count(obj->textures) > 0;
if( do_retexturing ) {
for(int i = 0; i < model->iqm->nummeshes; ++i) {
array_push(old_texture_ids, model->iqm->textures[i]);
array_push(obj->old_texture_ids, model->iqm->textures[i]);
model->iqm->textures[i] = (*array_back(obj->textures)).id;
if (model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture) {
array_push(old_textures, *model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture);
array_push(obj->old_textures, *model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture);
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = (*array_back(obj->textures));
}
}
@ -388072,32 +388139,80 @@ void scene_render(int flags) {
if ( flags&SCENE_UPDATE_SH_COEF ) {
shader_bind(model->program);
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
skybox_sh_shader(&last_scene->skybox);
}
model_skybox(model, last_scene->skybox, 0);
if (!obj->disable_frustum_check)
model_set_frustum(model, frustum_state);
else
model_clear_frustum(model);
if (anim) {
float delta = window_delta() * obj->anim_speed;
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
}
model->billboard = obj->billboard;
model->rs[RENDER_PASS_OPAQUE].cull_face_enabled = flags&SCENE_CULLFACE ? 1 : 0;
model->rs[RENDER_PASS_OPAQUE].polygon_mode_draw = flags&SCENE_WIREFRAME ? GL_LINE : GL_FILL;
model_render(*model, cam->proj, cam->view, obj->transform, model->program);
for (int p = 0; p < RENDER_PASS_OVERRIDES_BEGIN; ++p) {
model->rs[p].cull_face_enabled = flags&SCENE_CULLFACE ? 1 : 0;
model->rs[p].polygon_mode_draw = flags&SCENE_WIREFRAME ? GL_LINE : GL_FILL;
}
}
/* Collect all transparency enabled models and sort them by distance */
static array(object_t*) transparent_objects = 0;
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
if (model_has_transparency(*model)) {
obj->distance = len3sq(sub3(cam->position, transform344(model->pivot, add3(obj->pos, model->meshcenters[0]))));
array_push(transparent_objects, obj);
}
}
array_sort(transparent_objects, scene_obj_distance_compare);
/* Opaque pass */
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
model_render_pass(*model, cam->proj, cam->view, obj->transform, model->program, RENDER_PASS_OPAQUE);
}
/* Transparency pass */
for (unsigned j = 0; j < array_count(transparent_objects); ++j) {
object_t *obj = transparent_objects[j];
model_t *model = &obj->model;
if (obj->skip_draw) continue;
model_render_pass(*model, cam->proj, cam->view, obj->transform, model->program, RENDER_PASS_TRANSPARENT);
}
array_resize(transparent_objects, 0);
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
int do_retexturing = model->iqm && model->shading != SHADING_PBR && array_count(obj->textures) > 0;
if( do_retexturing ) {
for(int i = 0; i < model->iqm->nummeshes; ++i) {
model->iqm->textures[i] = old_texture_ids[i];
if (i < array_count(old_textures)) {
model->iqm->textures[i] = obj->old_texture_ids[i];
if (i < array_count(obj->old_textures)) {
if (model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture)
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = old_textures[i];
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = obj->old_textures[i];
}
}
array_resize(old_texture_ids, 0);
array_resize(old_textures, 0);
array_resize(obj->old_texture_ids, 0);
array_resize(obj->old_textures, 0);
}
}
glBindVertexArray(0);

View File

@ -3604,12 +3604,19 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb));
m->meshradii = CALLOC(hdr->num_meshes, sizeof(float));
for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id;
q->textures[i] = invalid;
struct iqmmesh *mesh = &q->meshes[i];
#if 1
GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
#else
// for (int j = 0; j < )
#endif
}
const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
@ -4236,6 +4243,46 @@ int drawcall_compare(const void *a, const void *b) {
return da->order < db->order ? 1 : da->order > db->order ? -1 : 0;
}
bool model_has_transparency_mesh(model_t m, int mesh) {
if(!m.iqm) return false;
iqm_t *q = m.iqm;
if (m.flags & MODEL_TRANSPARENT) {
return true;
}
if (m.materials[mesh].layer[0].map.color.a < 1 || (m.materials[mesh].layer[0].map.texture && m.materials[mesh].layer[0].map.texture->transparent)) {
return true;
}
if (m.shading == SHADING_PBR && (m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
return true;
}
return false;
}
bool model_has_transparency(model_t m) {
if(!m.iqm) return false;
iqm_t *q = m.iqm;
for (int i = 0; i < q->nummeshes; i++) {
if (model_has_transparency_mesh(m, i)) {
return true;
}
}
return false;
}
void model_set_frustum(model_t *m, frustum f) {
m->frustum_enabled = 1;
m->frustum_state = f;
}
void model_clear_frustum(model_t *m) {
m->frustum_enabled = 0;
}
static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return;
@ -4257,13 +4304,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
required_rs[i] = rs_idx;
if (required_rs[i] < RENDER_PASS_OVERRIDES_BEGIN) {
if (m.flags & MODEL_TRANSPARENT) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.materials[i].layer[0].map.color.a < 1 || (m.materials[i].layer[0].map.texture && m.materials[i].layer[0].map.texture->transparent)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.shading == SHADING_PBR && (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
if (model_has_transparency_mesh(m, i)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
}
@ -4303,7 +4344,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
// calculate distance from camera
// @todo: improve me, uses first mesh triangle
{
call.distance = len3(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
call.distance = len3sq(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
}
if (m.shading == SHADING_PBR)
@ -4732,6 +4773,8 @@ void model_destroy(model_t m) {
}
array_free(m.texture_names);
FREE(m.meshcenters);
FREE(m.meshbounds);
FREE(m.meshradii);
iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh);

View File

@ -677,6 +677,8 @@ typedef struct model_t {
int num_verts;
void *tris;
vec3 *meshcenters;
aabb *meshbounds;
float *meshradii;
int num_tris;
handle vao, ibo, vbo, vao_instanced;
@ -694,6 +696,9 @@ typedef struct model_t {
int stored_flags;
renderstate_t rs[NUM_RENDER_PASSES];
bool frustum_enabled;
frustum frustum_state;
} model_t;
enum BILLBOARD_MODE {
@ -720,6 +725,10 @@ API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *mode
API void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass);
API void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass);
API void model_set_texture(model_t*, texture_t t);
API bool model_has_transparency_mesh(model_t m, int mesh);
API bool model_has_transparency(model_t m);
API void model_set_frustum(model_t *m, frustum f);
API void model_clear_frustum(model_t *m);
API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out);
API void model_destroy(model_t);

View File

@ -505,8 +505,16 @@ light_t* scene_index_light(unsigned light_index) {
return &last_scene->lights[light_index];
}
static
int scene_obj_distance_compare(const void *a, const void *b) {
const object_t *da = a, *db = b;
return da->distance < db->distance ? 1 : da->distance > db->distance ? -1 : 0;
}
void scene_render(int flags) {
camera_t *cam = camera_get_active();
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum frustum_state = frustum_build(projview);
if(flags & SCENE_BACKGROUND) {
if(last_scene->skybox.program) {
@ -532,18 +540,18 @@ void scene_render(int flags) {
model_t *model = &obj->model;
anim_t *anim = &obj->anim;
mat44 *views = (mat44*)(&cam->view);
obj->skip_draw = !obj->disable_frustum_check && !frustum_test_aabb(frustum_state, model_aabb(*model, obj->transform));
// @todo: avoid heap allocs here?
static array(handle) old_texture_ids = 0;
static array(texture_t) old_textures = 0;
if (obj->skip_draw) continue;
int do_retexturing = model->iqm && model->shading != SHADING_PBR && array_count(obj->textures) > 0;
if( do_retexturing ) {
for(int i = 0; i < model->iqm->nummeshes; ++i) {
array_push(old_texture_ids, model->iqm->textures[i]);
array_push(obj->old_texture_ids, model->iqm->textures[i]);
model->iqm->textures[i] = (*array_back(obj->textures)).id;
if (model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture) {
array_push(old_textures, *model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture);
array_push(obj->old_textures, *model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture);
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = (*array_back(obj->textures));
}
}
@ -557,32 +565,80 @@ void scene_render(int flags) {
if ( flags&SCENE_UPDATE_SH_COEF ) {
shader_bind(model->program);
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
skybox_sh_shader(&last_scene->skybox);
}
model_skybox(model, last_scene->skybox, 0);
if (!obj->disable_frustum_check)
model_set_frustum(model, frustum_state);
else
model_clear_frustum(model);
if (anim) {
float delta = window_delta() * obj->anim_speed;
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
}
model->billboard = obj->billboard;
model->rs[RENDER_PASS_OPAQUE].cull_face_enabled = flags&SCENE_CULLFACE ? 1 : 0;
model->rs[RENDER_PASS_OPAQUE].polygon_mode_draw = flags&SCENE_WIREFRAME ? GL_LINE : GL_FILL;
model_render(*model, cam->proj, cam->view, obj->transform, model->program);
for (int p = 0; p < RENDER_PASS_OVERRIDES_BEGIN; ++p) {
model->rs[p].cull_face_enabled = flags&SCENE_CULLFACE ? 1 : 0;
model->rs[p].polygon_mode_draw = flags&SCENE_WIREFRAME ? GL_LINE : GL_FILL;
}
}
/* Collect all transparency enabled models and sort them by distance */
static array(object_t*) transparent_objects = 0;
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
if (model_has_transparency(*model)) {
obj->distance = len3sq(sub3(cam->position, transform344(model->pivot, add3(obj->pos, model->meshcenters[0]))));
array_push(transparent_objects, obj);
}
}
array_sort(transparent_objects, scene_obj_distance_compare);
/* Opaque pass */
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
model_render_pass(*model, cam->proj, cam->view, obj->transform, model->program, RENDER_PASS_OPAQUE);
}
/* Transparency pass */
for (unsigned j = 0; j < array_count(transparent_objects); ++j) {
object_t *obj = transparent_objects[j];
model_t *model = &obj->model;
if (obj->skip_draw) continue;
model_render_pass(*model, cam->proj, cam->view, obj->transform, model->program, RENDER_PASS_TRANSPARENT);
}
array_resize(transparent_objects, 0);
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
int do_retexturing = model->iqm && model->shading != SHADING_PBR && array_count(obj->textures) > 0;
if( do_retexturing ) {
for(int i = 0; i < model->iqm->nummeshes; ++i) {
model->iqm->textures[i] = old_texture_ids[i];
if (i < array_count(old_textures)) {
model->iqm->textures[i] = obj->old_texture_ids[i];
if (i < array_count(obj->old_textures)) {
if (model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture)
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = old_textures[i];
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = obj->old_textures[i];
}
}
array_resize(old_texture_ids, 0);
array_resize(old_textures, 0);
array_resize(obj->old_texture_ids, 0);
array_resize(obj->old_textures, 0);
}
}
glBindVertexArray(0);

View File

@ -48,6 +48,13 @@ typedef struct object_t {
float anim_speed;
aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool disable_frustum_check;
// internal states
array(handle) old_texture_ids;
array(texture_t) old_textures;
float distance;
bool skip_draw;
bool light_cached; //< used by scene to update light data
} object_t;

View File

@ -20403,12 +20403,19 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
m->meshbounds = CALLOC(hdr->num_meshes, sizeof(aabb));
m->meshradii = CALLOC(hdr->num_meshes, sizeof(float));
for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id;
q->textures[i] = invalid;
struct iqmmesh *mesh = &q->meshes[i];
#if 1
GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
#else
// for (int j = 0; j < )
#endif
}
const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
@ -21035,6 +21042,46 @@ int drawcall_compare(const void *a, const void *b) {
return da->order < db->order ? 1 : da->order > db->order ? -1 : 0;
}
bool model_has_transparency_mesh(model_t m, int mesh) {
if(!m.iqm) return false;
iqm_t *q = m.iqm;
if (m.flags & MODEL_TRANSPARENT) {
return true;
}
if (m.materials[mesh].layer[0].map.color.a < 1 || (m.materials[mesh].layer[0].map.texture && m.materials[mesh].layer[0].map.texture->transparent)) {
return true;
}
if (m.shading == SHADING_PBR && (m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[mesh].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
return true;
}
return false;
}
bool model_has_transparency(model_t m) {
if(!m.iqm) return false;
iqm_t *q = m.iqm;
for (int i = 0; i < q->nummeshes; i++) {
if (model_has_transparency_mesh(m, i)) {
return true;
}
}
return false;
}
void model_set_frustum(model_t *m, frustum f) {
m->frustum_enabled = 1;
m->frustum_state = f;
}
void model_clear_frustum(model_t *m) {
m->frustum_enabled = 0;
}
static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return;
@ -21056,13 +21103,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
required_rs[i] = rs_idx;
if (required_rs[i] < RENDER_PASS_OVERRIDES_BEGIN) {
if (m.flags & MODEL_TRANSPARENT) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.materials[i].layer[0].map.color.a < 1 || (m.materials[i].layer[0].map.texture && m.materials[i].layer[0].map.texture->transparent)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.shading == SHADING_PBR && (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
if (model_has_transparency_mesh(m, i)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
}
@ -21102,7 +21143,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_
// calculate distance from camera
// @todo: improve me, uses first mesh triangle
{
call.distance = len3(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
call.distance = len3sq(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
}
if (m.shading == SHADING_PBR)
@ -21531,6 +21572,8 @@ void model_destroy(model_t m) {
}
array_free(m.texture_names);
FREE(m.meshcenters);
FREE(m.meshbounds);
FREE(m.meshradii);
iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh);
@ -23179,8 +23222,16 @@ light_t* scene_index_light(unsigned light_index) {
return &last_scene->lights[light_index];
}
static
int scene_obj_distance_compare(const void *a, const void *b) {
const object_t *da = a, *db = b;
return da->distance < db->distance ? 1 : da->distance > db->distance ? -1 : 0;
}
void scene_render(int flags) {
camera_t *cam = camera_get_active();
mat44 projview; multiply44x2(projview, cam->proj, cam->view);
frustum frustum_state = frustum_build(projview);
if(flags & SCENE_BACKGROUND) {
if(last_scene->skybox.program) {
@ -23206,18 +23257,18 @@ void scene_render(int flags) {
model_t *model = &obj->model;
anim_t *anim = &obj->anim;
mat44 *views = (mat44*)(&cam->view);
obj->skip_draw = !obj->disable_frustum_check && !frustum_test_aabb(frustum_state, model_aabb(*model, obj->transform));
// @todo: avoid heap allocs here?
static array(handle) old_texture_ids = 0;
static array(texture_t) old_textures = 0;
if (obj->skip_draw) continue;
int do_retexturing = model->iqm && model->shading != SHADING_PBR && array_count(obj->textures) > 0;
if( do_retexturing ) {
for(int i = 0; i < model->iqm->nummeshes; ++i) {
array_push(old_texture_ids, model->iqm->textures[i]);
array_push(obj->old_texture_ids, model->iqm->textures[i]);
model->iqm->textures[i] = (*array_back(obj->textures)).id;
if (model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture) {
array_push(old_textures, *model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture);
array_push(obj->old_textures, *model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture);
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = (*array_back(obj->textures));
}
}
@ -23231,32 +23282,80 @@ void scene_render(int flags) {
if ( flags&SCENE_UPDATE_SH_COEF ) {
shader_bind(model->program);
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
skybox_sh_shader(&last_scene->skybox);
}
model_skybox(model, last_scene->skybox, 0);
if (!obj->disable_frustum_check)
model_set_frustum(model, frustum_state);
else
model_clear_frustum(model);
if (anim) {
float delta = window_delta() * obj->anim_speed;
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
}
model->billboard = obj->billboard;
model->rs[RENDER_PASS_OPAQUE].cull_face_enabled = flags&SCENE_CULLFACE ? 1 : 0;
model->rs[RENDER_PASS_OPAQUE].polygon_mode_draw = flags&SCENE_WIREFRAME ? GL_LINE : GL_FILL;
model_render(*model, cam->proj, cam->view, obj->transform, model->program);
for (int p = 0; p < RENDER_PASS_OVERRIDES_BEGIN; ++p) {
model->rs[p].cull_face_enabled = flags&SCENE_CULLFACE ? 1 : 0;
model->rs[p].polygon_mode_draw = flags&SCENE_WIREFRAME ? GL_LINE : GL_FILL;
}
}
/* Collect all transparency enabled models and sort them by distance */
static array(object_t*) transparent_objects = 0;
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
if (model_has_transparency(*model)) {
obj->distance = len3sq(sub3(cam->position, transform344(model->pivot, add3(obj->pos, model->meshcenters[0]))));
array_push(transparent_objects, obj);
}
}
array_sort(transparent_objects, scene_obj_distance_compare);
/* Opaque pass */
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
model_render_pass(*model, cam->proj, cam->view, obj->transform, model->program, RENDER_PASS_OPAQUE);
}
/* Transparency pass */
for (unsigned j = 0; j < array_count(transparent_objects); ++j) {
object_t *obj = transparent_objects[j];
model_t *model = &obj->model;
if (obj->skip_draw) continue;
model_render_pass(*model, cam->proj, cam->view, obj->transform, model->program, RENDER_PASS_TRANSPARENT);
}
array_resize(transparent_objects, 0);
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j);
model_t *model = &obj->model;
if (obj->skip_draw) continue;
int do_retexturing = model->iqm && model->shading != SHADING_PBR && array_count(obj->textures) > 0;
if( do_retexturing ) {
for(int i = 0; i < model->iqm->nummeshes; ++i) {
model->iqm->textures[i] = old_texture_ids[i];
if (i < array_count(old_textures)) {
model->iqm->textures[i] = obj->old_texture_ids[i];
if (i < array_count(obj->old_textures)) {
if (model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture)
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = old_textures[i];
*model->materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture = obj->old_textures[i];
}
}
array_resize(old_texture_ids, 0);
array_resize(old_textures, 0);
array_resize(obj->old_texture_ids, 0);
array_resize(obj->old_textures, 0);
}
}
glBindVertexArray(0);

View File

@ -3712,6 +3712,8 @@ typedef struct model_t {
int num_verts;
void *tris;
vec3 *meshcenters;
aabb *meshbounds;
float *meshradii;
int num_tris;
handle vao, ibo, vbo, vao_instanced;
@ -3729,6 +3731,9 @@ typedef struct model_t {
int stored_flags;
renderstate_t rs[NUM_RENDER_PASSES];
bool frustum_enabled;
frustum frustum_state;
} model_t;
enum BILLBOARD_MODE {
@ -3755,6 +3760,10 @@ API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *mode
API void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass);
API void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass);
API void model_set_texture(model_t*, texture_t t);
API bool model_has_transparency_mesh(model_t m, int mesh);
API bool model_has_transparency(model_t m);
API void model_set_frustum(model_t *m, frustum f);
API void model_clear_frustum(model_t *m);
API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out);
API void model_destroy(model_t);
@ -3951,6 +3960,13 @@ typedef struct object_t {
float anim_speed;
aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool disable_frustum_check;
// internal states
array(handle) old_texture_ids;
array(texture_t) old_textures;
float distance;
bool skip_draw;
bool light_cached; //< used by scene to update light data
} object_t;