v4k-git-backup/demos/04-lod.c

235 lines
35 KiB
C
Raw Normal View History

// LOD demo, based on Polygon Reduction Demo by Stan Melax (PD)
// - rlyeh, public domain.
2023-08-10 22:14:08 +00:00
#include "v4k.h"
vec2 world2screen(vec3 p) {
vec4 clip_pos = transform444(camera_get_active()->proj, transform444(camera_get_active()->view, vec4(p.x,p.y,p.z,1.0)));
vec4 ndc_pos = scale4(clip_pos, 1.0 / (clip_pos.w + !clip_pos.w)); // [-1..1]
vec2 screen_pos = vec2( window_width() * (ndc_pos.x + 1) / 2.0, window_height() * (1 - ndc_pos.y) / 2.0 );
return screen_pos;
}
float mesh_area(mesh_t *m) {
// @fixme: return 0 if mesh is out of frustum, or window is minimized
aabb box = mesh_bounds(m);
ddraw_aabb(box.min, box.max);
vec2 A = world2screen(vec3(box.min.x,box.min.y,box.min.z)); ddraw_text2d(A, va("A: %5.2f,%5.2f", A.x, A.y));
vec2 B = world2screen(vec3(box.min.x,box.min.y,box.max.z)); ddraw_text2d(B, va("B: %5.2f,%5.2f", B.x, B.y));
vec2 C = world2screen(vec3(box.min.x,box.max.y,box.min.z)); ddraw_text2d(C, va("C: %5.2f,%5.2f", C.x, C.y));
vec2 D = world2screen(vec3(box.min.x,box.max.y,box.max.z)); ddraw_text2d(D, va("D: %5.2f,%5.2f", D.x, D.y));
vec2 E = world2screen(vec3(box.max.x,box.min.y,box.min.z)); ddraw_text2d(E, va("E: %5.2f,%5.2f", E.x, E.y));
vec2 F = world2screen(vec3(box.max.x,box.min.y,box.max.z)); ddraw_text2d(F, va("F: %5.2f,%5.2f", F.x, F.y));
vec2 G = world2screen(vec3(box.max.x,box.max.y,box.min.z)); ddraw_text2d(G, va("G: %5.2f,%5.2f", G.x, G.y));
vec2 H = world2screen(vec3(box.max.x,box.max.y,box.max.z)); ddraw_text2d(H, va("H: %5.2f,%5.2f", H.x, H.y));
vec2 O = min2(min2(min2(min2(min2(min2(min2(A,B),C),D),E),F),G),H); ddraw_text2d(O, "|\\");
vec2 P = max2(max2(max2(max2(max2(max2(max2(A,B),C),D),E),F),G),H); ddraw_text2d(P, "\\|");
float area = (P.x-O.x) * (P.y-O.y); // len2(sub2(P,O));
float pct = area / (float)(window_height() * window_width());
font_print(va(FONT_RIGHT "area: %5.2f%%", pct*100));
return pct;
}
API void ProgressiveMesh(int vert_n, int vert_stride, const float *v, int tri_n, const int *tri, int *map, int *permutation);
// Map()
//
// Note that the use of the Map() function and the collapse_map Array isn't part of the polygon reduction
// algorithm. We set up the function here so that we could retrieve the model at any desired vertex count.
//
// When the model is rendered using a maximum of mx vertices then it is vertices 0 through mx-1 that are used.
// We are able to do this because the vertex Array gets sorted according to the collapse order.
// The Map() routine takes a vertex number 'n' and the maximum number of vertices 'mx' and returns the
// appropriate vertex in the range 0 to mx-1. When 'n' is greater than 'mx' the Map() routine follows the
// chain of edge collapses until a vertex within the limit is reached.
// An example to make this clear: assume there is a triangle with vertices 1, 3 and 12. But when
// rendering the model we limit ourselves to 10 vertices. In that case we find out how vertex 12 was
// removed by the polygon reduction algorithm. i.e. which edge was collapsed. Lets say that vertex 12 was
// collapsed to vertex number 7. This number would have been stored in the collapse_map array (i.e.
// collapse_map[12]==7). Since vertex 7 is in range (less than max of 10) we will want to render the
// triangle 1,3,7. Pretend now that we want to limit ourselves to 5 vertices. and vertex 7 was collapsed
// to vertex 3 (i.e. collapse_map[7]==3). Then triangle 1,3,12 would now be triangle 1,3,3. i.e. this
// polygon was removed by the progressive mesh polygon reduction algorithm by the time it had gotten down
// to 5 vertices. No need to draw a one dimensional polygon. :-)
static inline int MapReduce(array(int) collapse_map, int n, int mx) {
while( n >= mx ) n = collapse_map[n];
return n;
}
mesh_t *ReduceModel(mesh_t *m, float lo_detail, float hi_detail, float morph) {
int max_verts_to_render = hi_detail * array_count(m->in_vertex3);
int min_verts_to_render = lo_detail * array_count(m->in_vertex3);
if( max_verts_to_render <= 0 || min_verts_to_render <= 0 )
return m;
array_resize(m->out_index3, 0);
array_resize(m->out_vertex3, 0);
ASSERT(array_count(m->lod_collapse_map));
for( unsigned int i = 0; i < array_count(m->in_index3); i++ ) {
int p0 = MapReduce(m->lod_collapse_map, m->in_index3[i].x, max_verts_to_render);
int p1 = MapReduce(m->lod_collapse_map, m->in_index3[i].y, max_verts_to_render);
int p2 = MapReduce(m->lod_collapse_map, m->in_index3[i].z, max_verts_to_render);
// @fixme: serious optimization opportunity here,
// by sorting the triangles the following "continue"
// could have been made into a "break" statement.
if(p0==p1 || p0==p2 || p1==p2) continue;
// if we are not currenly morphing between 2 levels of detail
// (i.e. if morph=1.0) then q0,q1, and q2 may not be necessary
int q0 = MapReduce(m->lod_collapse_map, p0, min_verts_to_render);
int q1 = MapReduce(m->lod_collapse_map, p1, min_verts_to_render);
int q2 = MapReduce(m->lod_collapse_map, p2, min_verts_to_render);
vec3 v0, v1, v2;
v0 = mix3(m->in_vertex3[p0], m->in_vertex3[q0], (1-morph));
v1 = mix3(m->in_vertex3[p1], m->in_vertex3[q1], (1-morph));
v2 = mix3(m->in_vertex3[p2], m->in_vertex3[q2], (1-morph));
vec3 normal = norm3(cross3(sub3(v1,v0),sub3(v2,v1)));
array_push(m->out_vertex3, v0);
array_push(m->out_vertex3, normal);
array_push(m->out_vertex3, v1);
array_push(m->out_vertex3, normal);
array_push(m->out_vertex3, v2);
array_push(m->out_vertex3, normal);
int idx = array_count(m->out_vertex3) / 2;
array_push(m->out_index3, vec3i(idx-3,idx-2,idx-1));
}
return m;
}
void DrawModel(mesh_t *m) {
static mat44 M; do_once id44(M);
static mat44 VP; multiply44x2(VP, camera_get_active()->proj, camera_get_active()->view);
static const char *vs =
"#version 130\n"
"//" FILELINE "\n"
"uniform mat4 M,VP;\n"
"in vec3 att_position;\n"
"in vec3 att_normal;\n"
"out vec3 v_normal;\n"
"void main() {\n"
" v_normal = normalize(att_normal);\n"
" gl_Position = M * VP * vec4( att_position, 1.0 );\n"
"}\n";
static const char *fs =
"#version 130\n"
"//" FILELINE "\n"
"in vec3 v_normal;\n"
"out vec4 fragcolor;\n"
"void main() {\n"
"fragcolor = vec4(v_normal, 1.0);\n" // diffuse
"}";
static unsigned program; do_once program = shader(vs, fs, "att_position,att_normal", "fragcolor", "");
shader_bind(program);
shader_mat44("VP", VP);
shader_mat44("M", M);
mesh_update(m, "p3 n3", 0,array_count(m->out_vertex3)/2,m->out_vertex3, array_count(m->out_index3)*3,m->out_index3,0);
mesh_render(m);
}
void InitModel(mesh_t *m) {
static const double verts[]={-0.334392,+0.133007,+0.062259,-0.350189,+0.150354,-0.147769,-0.234201,+0.343811,-0.174307,-0.200259,+0.285207,+0.093749,+0.003520,+0.475208,-0.159365,+0.001856,+0.419203,+0.098582,-0.252802,+0.093666,+0.237538,-0.162901,+0.237984,+0.206905,+0.000865,+0.318141,+0.235370,-0.414624,+0.164083,-0.278254,-0.262213,+0.357334,-0.293246,+0.004628,+0.482694,-0.338626,-0.402162,+0.133528,-0.443247,-0.243781,+0.324275,-0.436763,+0.005293,+0.437592,-0.458332,-0.339884,-0.041150,-0.668211,-0.248382,+0.255825,-0.627493,+0.006261,+0.376103,-0.631506,-0.216201,-0.126776,-0.886936,-0.171075,+0.011544,-0.881386,-0.181074,+0.098223,-0.814779,-0.119891,+0.218786,-0.760153,-0.078895,+0.276780,-0.739281,+0.006801,+0.310959,-0.735661,-0.168842,+0.102387,-0.920381,-0.104072,+0.177278,-0.952530,-0.129704,+0.211848,-0.836678,-0.099875,+0.310931,-0.799381,+0.007237,+0.361687,-0.794439,-0.077913,+0.258753,-0.921640,+0.007957,+0.282241,-0.931680,-0.252222,-0.550401,-0.557810,-0.267633,-0.603419,-0.655209,-0.446838,-0.118517,-0.466159,-0.459488,-0.093017,-0.311341,-0.370645,-0.100108,-0.159454,-0.371984,-0.091991,-0.011044,-0.328945,-0.098269,+0.088659,-0.282452,-0.018862,+0.311501,-0.352403,-0.131341,+0.144902,-0.364126,-0.200299,+0.202388,-0.283965,-0.231869,+0.023668,-0.298943,-0.155218,+0.369716,-0.293787,-0.121856,+0.419097,-0.290163,-0.290797,+0.107824,-0.264165,-0.272849,+0.036347,-0.228567,-0.372573,+0.290309,-0.190431,-0.286997,+0.421917,-0.191039,-0.240973,+0.507118,-0.287272,-0.276431,-0.065444,-0.295675,-0.280818,-0.174200,-0.399537,-0.313131,-0.376167,-0.392666,-0.488581,-0.427494,-0.331669,-0.570185,-0.466054,-0.282290,-0.618140,-0.589220,-0.374238,-0.594882,-0.323298,-0.381071,-0.629723,-0.350777,-0.382112,-0.624060,-0.221577,-0.272701,-0.566522,+0.259157,-0.256702,-0.663406,+0.286079,-0.280948,-0.428359,+0.055790,-0.184974,-0.508894,+0.326265,-0.279971,-0.526918,+0.395319,-0.282599,-0.663393,+0.412411,-0.188329,-0.475093,+0.417954,-0.263384,-0.663396,+0.466604,-0.209063,-0.663393,+0.509344,-0.002044,-0.319624,+0.553078,-0.001266,-0.371260,+0.413296,-0.219753,-0.339762,-0.040921,-0.256986,-0.282511,-0.006349,-0.271706,-0.260881,+0.001764,-0.091191,-0.419184,-0.045912,-0.114944,-0.429752,-0.124739,-0.113970,-0.382987,-0.188540,-0.243012,-0.464942,-0.242850,-0.314815,-0.505402,-0.324768,+0.002774,-0.437526,-0.262766,-0.072625,-0.417748,-0.221440,-0.160112,-0.476932,-0.293450,+0.003859,-0.453425,-0.443916,-0.120363,-0.581567,-0.438689,-0.091499,-0.584191,-0.294511,-0.116469,-0.599861,-0.188308,-0.208032,-0.513640,-0.134649,-0.235749,-0.610017,-0.040939,-0.344916,-0.622487,-0.085380,-0.336401,-0.531864,-0.212298,+0.001961,-0.459550,-0.135547,-0.058296,-0.430536,-0.043440,+0.001378,-0.449511,-0.037762,-0.130135,-0.510222,+0.079144,+0.000142,-0.477549,+0.157064,-0.114284,-0.453206,+0.304397,-0.000592,-0.443558,+0.285401,-0.056215,-0.663402,+0.326073,-0.026248,-0.568010,+0.273318,-0.049261,-0.531064,+0.389854,-0.127096,-0.663398,+0.479316,-0.058384,-0.663401,+0.372891,-0.303961,+0.054199,+0.625921,-0.268594,+0.193403,+0.502766,-0.277159,+0.126123,+0.443289,-0.287605,-0.005722,+0.531844,-0.231396,-0.121289,+0.587387,-0.253475,-0.081797,+0.756541,-0.195164,-0.137969,+0.728011,-0.167673,-0.156573,+0.609388,-0.145917,-0.169029,+0.697600,-0.077776,-0.214247,+0.622586,-0.076873,-0.214971,+0.696301,-0.002341,-0.233135,+0.622859,-0.002730,-0.213526,+0.691267,-0.003136,-0.192628,+0.762731,-0.056136,-0.201222,+0.763806,-0.114589,-0.166192,+0.770723,-0.155145,-0.129632,+0.791738,-0.183611,-0.058705,+0.847012,-0.165562,+0.001980,+0.833386,-0.220084,+0.019914,+0.768935,-0.255730,+0.090306,+0.670782,-0.255594,+0.113833,+0.663389,-0.226380,+0.212655,+0.617740,-0.003367,-0.195342,+0.799680,-0.029743,-0.210508,+0.827180,-0.003818,-0.194783,+0.873636,-0.004116,-0.157907,+0.931268,-0.031280,-0.184555,+0.889476,-0.059885,-0.184448,+0.841330,-0.135333,-0.164332,+0.878200,-0.085574,-0.170948,+0.925547,-0.163833,-0.094170,+0.897114,-0.138444,-0.104250,+0.945975,-0.083497,-0.084934,+0.979607,-0.004433,-0.146642,+0.985872,-0.150715,+0
static const int tris[]={126,134,133,342,138,134,133,134,138,126,342,134,312,316,317,169,163,162,312,317,319,312,319,318,169,162,164,169,168,163,312,314,315,169,164,165,169,167,168,312,315,316,312,313,314,169,165,166,169,166,167,312,318,313,308,304,305,308,305,306,179,181,188,177,173,175,177,175,176,302,293,300,322,294,304,188,176,175,188,175,179,158,177,187,305,293,302,305,302,306,322,304,308,188,181,183,158,173,177,293,298,300,304,294,296,304,296,305,185,176,188,185,188,183,187,177,176,187,176,185,305,296,298,305,298,293,436,432, 28,436, 28, 23,434,278,431, 30,208,209, 30,209, 29, 19, 20, 24,208,207,211,208,211,209, 19,210,212,433,434,431,433,431,432,433,432,436,436,437,433,277,275,276,277,276,278,209,210, 25, 21, 26, 24, 21, 24, 20, 25, 26, 27, 25, 27, 29,435,439,277,439,275,277,432,431, 30,432, 30, 28,433,437,438,433,438,435,434,277,278, 24, 25,210, 24, 26, 25, 29, 27, 28, 29, 28, 30, 19, 24,210,208, 30,431,208,431,278,435,434,433,435,277,434, 25, 29,209, 27, 22, 23, 27, 23, 28, 26, 22, 27, 26, 21, 22,212,210,209,212,209,211,207,208,278,207,278,276,439,435,438, 12, 9, 10, 12, 10, 13, 2, 3, 5, 2, 5, 4, 16, 13, 14, 16, 14, 17, 22, 21, 16, 13, 10, 11, 13, 11, 14, 1, 0, 3, 1, 3, 2, 15, 12, 16, 19, 18, 15, 19, 15, 16, 19, 16, 20, 9, 1, 2, 9, 2, 10, 3, 7, 8, 3, 8, 5, 16, 17, 23, 16, 23, 22, 21, 20, 16, 10, 2, 4, 10, 4, 11, 0, 6, 7, 0, 7, 3, 12, 13, 16,451,446,445,451,445,450,442,440,439,442,439,438,442,438,441,421,420,422,412,411,426,412,426,425,408,405,407,413, 67, 68,413, 68,414,391,390,412, 80,384,386,404,406,378,390,391,377,390,377, 88,400,415,375,398,396,395,398,395,371,398,371,370,112,359,358,112,358,113,351,352,369,125,349,348,345,343,342,342,340,339,341,335,337,328,341,327,331,323,333,331,322,323,327,318,319,327,319,328,315,314,324,302,300,301,302,301,303,320,311,292,285,284,289,310,307,288,310,288,290,321,350,281,321,281,282,423,448,367,272,273,384,272,384,274,264,265,382,264,382,383,440,442,261,440,261,263,252,253,254,252,254,251,262,256,249,262,249,248,228,243,242,228, 31,243,213,215,238,213,238,237, 19,212,230,224,225,233,224,233,231,217,218, 56,217, 56, 54,217,216,239,217,239,238,217,238,215,218,217,215,218,215,214, 6,102,206,186,199,200,197,182,180,170,171,157,201,200,189,170,190,191,170,191,192,175,174,178,175,178,179,168,167,155,122,149,158,122,158,159,135,153,154,135,154,118,143,140,141,143,141,144,132,133,136,130,126,133,124,125,127,122,101,100,122,100,121,110,108,107,110,107,109, 98, 99, 97, 98, 97, 64, 98, 64, 66, 87, 55, 57, 83, 82, 79, 83, 79, 84, 78, 74, 50, 49, 71, 41, 49, 41, 37, 49, 37, 36, 58, 44, 60, 60, 59, 58, 51, 34, 33, 39, 40, 42, 39, 42, 38,243,240, 33,243, 33,229, 39, 38, 6, 44, 46, 40, 55, 56, 57, 64, 62, 65, 64, 65, 66, 41, 71, 45, 75, 50, 51, 81, 79, 82, 77, 88, 73, 93, 92, 94, 68, 47, 46, 96, 97, 99, 96, 99, 95,110,109,111,111,112,110,114,113,123,114,123,124,132,131,129,133,137,136,135,142,145,145,152,135,149,147,157,157,158,149,164,150,151,153,163,168,153,168,154,185,183,182,185,182,184,161,189,190,200,199,191,200,191,190,180,178,195,180,195,196,102,101,204,102,204,206, 43, 48,104, 43,104,103,216,217, 54,216, 54, 32,207,224,231,230,212,211,230,211,231,227,232,241,227,241,242,235,234,241,235,241,244,430,248,247,272,274,253,272,253,252,439,260,275,225,224,259,225,259,257,269,270,407,269,407,405,270,269,273,270,273,272,273,269,268,273,268,267,273,267,266,273,266,265,273,265,264,448,279,367,281,350,368,285,286,301,290,323,310,290,311,323,282,281,189,292,311,290,292,290,291,307,306,302,307,302,303,316,315,324,316,324,329,331,351,350,330,334,335,330,335,328,341,337,338,344,355,354,346,345,348,346,348,347,364,369,352,364,352,353,365,363,361,365,361,362,376,401,402,373,372,397,373,397,400,376, 92,377,381,378,387,381,387,385,386, 77, 80,390,389,412,416,417,401,403,417,415,408,429,430,419,423,418,427,428,444,427,444,446,437,436,441,450,445, 11,450, 11, 4,447,449, 5,447, 5, 8,441,438,437,425,426,451,425,451,452,417,421,415,408,407,429,399,403,400,399,400,397,394,393,416,389,411,412,386,383,385,408,387,378,408,378,406,377,391,376, 94,375,415,372,373,37
enum { NUM_VERTS = countof(verts) / 3, NUM_TRIS = countof(tris) / 3 };
// Copy the geometry from the arrays of data into the arrays which we send to the reduction routine
for(int i = 0; i < NUM_VERTS; i++ ) {
const double *vp = &verts[i*3];
array_push(m->in_vertex3, vec3(vp[0],vp[1],vp[2]));
}
for(int i = 0; i < NUM_TRIS; i++ ) {
const int *td = &tris[i*3];
array_push(m->in_index3, vec3i(td[0],td[1],td[2]));
}
int tri_n = array_count(m->in_index3);
int vert_n = array_count(m->in_vertex3);
int vert_stride = sizeof(float) * 3;
array(int) permutation = 0;
array_resize(m->lod_collapse_map, vert_n);
array_resize(permutation, vert_n);
ProgressiveMesh(vert_n, vert_stride, (const float *)m->in_vertex3, tri_n, (const int *)m->in_index3, m->lod_collapse_map, permutation);
// PermuteVertices {
ASSERT(array_count(permutation) == array_count(m->in_vertex3));
// rearrange the vertex Array
array(vec3) tmp = 0;
for(int i = 0; i < array_count(m->in_vertex3); i++) array_push(tmp, m->in_vertex3[i]);
for(int i = 0; i < array_count(m->in_vertex3); i++) m->in_vertex3[permutation[i]]=tmp[i];
// update the changes in the entries in the triangle Array
for (int i = 0; i < array_count(m->in_index3); i++) {
m->in_index3[i].x = permutation[m->in_index3[i].x];
m->in_index3[i].y = permutation[m->in_index3[i].y];
m->in_index3[i].z = permutation[m->in_index3[i].z];
}
array_free(tmp);
// } PermuteVertices
array_free(permutation);
}
int main() {
window_create(0.75, 0);
window_color(PURPLE);
camera_t cam = camera();
cam.speed /= 4;
cam.position = vec3(1.667,0.503,2.417);
camera_lookat(&cam, vec3(0,0,0));
mesh_t m = mesh();
InitModel(&m);
float lo_detail=0.25f;
float hi_detail=1.00f;
float morph=0.75f;
while( window_swap() && !input(KEY_ESC) ) {
if( input(KEY_LALT) && input_down(KEY_Z) ) window_record(__FILE__ ".mp4");
// fps camera
if( input(GAMEPAD_CONNECTED) ) {
vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
vec2 filtered_rpad = input_filter_deadzone(input2(GAMEPAD_RPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
vec2 mouse = scale2(vec2(filtered_rpad.x, filtered_rpad.y), 1.0f);
vec3 wasdec = scale3(vec3(filtered_lpad.x, input(GAMEPAD_LT) - input(GAMEPAD_RT), filtered_lpad.y), 1.0f);
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
camera_fps(&cam, mouse.x,mouse.y);
window_cursor( true );
} else {
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_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
camera_fps(&cam, mouse.x,mouse.y);
window_cursor( !active );
}
profile("LOD generation") {
ReduceModel(&m, lo_detail, hi_detail, morph);
mesh_area(&m);
}
DrawModel(&m);
if( ui_panel("LODs", PANEL_OPEN) ) {
ui_label(va("Polys: %d/%d Vertices: %d/%d", array_count(m.out_index3), array_count(m.in_index3), (int)(lo_detail * array_count(m.in_vertex3)), (int)(hi_detail * array_count(m.in_vertex3))));
if(ui_slider("Lo detail", &lo_detail)) { lo_detail = clampf(lo_detail, 0.01f, 1.0f); if(lo_detail > hi_detail) hi_detail = lo_detail; }
if(ui_slider("Hi detail", &hi_detail)) { hi_detail = clampf(hi_detail, 0.01f, 1.0f); if(hi_detail < lo_detail) lo_detail = hi_detail; }
ui_slider("Morph", &morph);
ui_panel_end();
}
}
}