gKit2 light
Loading...
Searching...
No Matches
gltf.cpp
1
2#include <cstdio>
3#include <cstring>
4#include <cfloat>
5
6#include "files.h"
7#include "texture.h"
8#include "image_io.h"
9
10#include "cgltf.h"
11#include "gltf.h"
12
13
14Mesh read_gltf_mesh( const char *filename )
15{
16 printf("loading glTF mesh '%s'...\n", filename);
17
18 cgltf_options options= { };
19 cgltf_data *data= nullptr;
20 cgltf_result code= cgltf_parse_file(&options, filename, &data);
21 if(code != cgltf_result_success)
22 {
23 printf("[error] loading glTF mesh '%s'...\n", filename);
24 return {};
25 }
26
27 if(cgltf_validate(data) != cgltf_result_success)
28 {
29 printf("[error] invalid glTF mesh '%s'...\n", filename);
30 return {};
31 }
32
33 code= cgltf_load_buffers(&options, data, filename);
34 if(code != cgltf_result_success)
35 {
36 printf("[error] loading glTF buffers...\n");
37 return {};
38 }
39
40 //
41 std::vector<unsigned> indices;
42 std::vector<int> material_indices;
43 std::vector<vec3> positions;
44 std::vector<vec2> texcoords;
45 std::vector<vec3> normals;
46 std::vector<vec4> colors;
47
48 Materials materials;
49
50 // textures
51 for(unsigned i= 0; i < data->images_count; i++)
52 {
53 if(data->images[i].uri)
54 {
55 printf("texture '%s'...\n", data->images[i].uri);
56 materials.insert_texture(data->images[i].uri);
57 }
58 else if(data->images[i].buffer_view)
59 {
60 //~ cgltf_buffer_view *view= data->images[i].buffer_view;
61 //~ assert(view->buffer->data);
62 //~ printf(" [%u] %s offset %lu size %lu, type '%s'\n", i, data->images[i].name, view->offset, view->size, data->images[i].mime_type);
63
64 //~ SDL_RWops *read= SDL_RWFromConstMem((uint8_t *) view->buffer->data + view->offset, view->size);
65 //~ assert(read);
66
67 // extraire la texture du glb...
68 cgltf_buffer_view *view= data->images[i].buffer_view;
69 //~ assert(view->buffer->data);
70 //~ images[i]= read_image_data((uint8_t *) view->buffer->data + view->offset, view->size);
71
72 if(!view->buffer->uri)
73 {
74 char tmp[1024];
75 if(data->images[i].name && data->images[i].name[0])
76 sprintf(tmp, "%s%s", pathname(filename).c_str(), data->images[i].name);
77 else
78 sprintf(tmp, "%stexture%d.png", pathname(filename).c_str(), i);
79
80 //~ printf("packed texture '%s'...\n", tmp);
81 materials.insert_texture(tmp);
82
83 #if 0
84 if(strcmp(data->images[i].mime_type, "image/png") == 0)
85 strcat(tmp, ".png");
86 else if(strcmp(data->images[i].mime_type, "image/jpg") == 0)
87 strcat(tmp, ".jpg");
88 else
89 strcat(tmp, ".raw"); // ??
90
91 printf("unpacking glb texture '%s' to '%s'...\n", data->images[i].name, tmp);
92
93 FILE *out= fopen(tmp, "wb");
94 if(out)
95 {
96 if(fwrite((char *) view->buffer->data + view->offset, view->size, 1, out) != 1)
97 printf("[error] unpacking glb texture '%s' to '%s'...\n", data->images[i].name, tmp);
98
99 fclose(out);
100 }
101
102 // ultra moche, utiliser les RWops de sdl... pour lire l'image directement en memoire...
103 // retourner l'image, origine en bas a gauche pour opengl
104 ImageData image= read_image_data(tmp);
105 image= flipY(image);
106
107 if(char *ext= strrchr(tmp, '.'))
108 strcpy(ext, "_flip.png");
109
110 printf("writing flipped texture '%s'...\n", tmp);
111 write_image_data(image, tmp);
112
113 materials.insert_texture(tmp);
114 assert(data->images[i].uri == nullptr);
115 data->images[i].uri= strdup(tmp); // nomme la texture / cf analyse des matieres
116 #endif
117 }
118 }
119 }
120
121 // materials
122 for(unsigned i= 0; i < data->materials_count; i++)
123 {
124 cgltf_material *material= &data->materials[i];
125 //~ printf("materials[%u]: '%s'\n", i, material->name);
126
127 Material m(Color(0.8));
128 if(material->has_pbr_metallic_roughness)
129 {
130 cgltf_pbr_metallic_roughness *pbr= &material->pbr_metallic_roughness;
131 //~ printf(" pbr metallic roughness\n");
132 //~ printf(" base color %f %f %f %f\n", pbr->base_color_factor[0], pbr->base_color_factor[1], pbr->base_color_factor[2], pbr->base_color_factor[3]);
133 //~ printf(" texture %d\n", pbr->base_color_texture.texture ? int(std::distance(data->images, pbr->base_color_texture.texture->image)) : -1);
134 //~ printf(" metallic %f, roughness %f\n", pbr->metallic_factor, pbr->roughness_factor);
135 //~ printf(" texture %d\n", pbr->metallic_roughness_texture.texture ? int(std::distance(data->images, pbr->metallic_roughness_texture.texture->image)) : -1);
136
137 Color color= Color(pbr->base_color_factor[0], pbr->base_color_factor[1], pbr->base_color_factor[2], pbr->base_color_factor[3]);
138 float metallic= pbr->metallic_factor;
139 float roughness= pbr->roughness_factor;
140
141 // conversion metallic-roughness vers diffuse-specular + Blinn-Phong
142 // metaux { diffuse= black, specular= color }
143 // non - metaux { diffuse= color, specular= 0.04 }
144 m.diffuse= color * (1 - metallic) + metallic * Black();
145 m.specular= Color(0.04) * (1 - metallic) + color * metallic;
146
147 // conversion roughness vers exposant Blinn-Phong
148 m.ns= 2 / (roughness * roughness * roughness * roughness) - 2;
149 if(m.ns < float(1.1))
150 m= Material(m.diffuse);
151 // les valeurs sont habituellement dans les textures metallic_roughness... utiliser une matiere diffuse + texture...
152
153 //~ printf(" | diffuse %f %f %f, specular %f %f %f, ns %f\n",
154 //~ m.diffuse.r, m.diffuse.g, m.diffuse.b,
155 //~ m.specular.r, m.specular.g, m.specular.b,
156 //~ m.ns);
157
158 if(pbr->base_color_texture.texture && pbr->base_color_texture.texture->image)
159 m.diffuse_texture= int(std::distance(data->images, pbr->base_color_texture.texture->image));
160 }
161
162 if(!material->name)
163 {
164 char tmp[1024];
165 sprintf(tmp, "material%d", i);
166 material->name= strdup(tmp);
167 }
168
169 materials.insert(m, material->name);
170 }
171
172 bool mesh_has_texcoords= false;
173 bool mesh_has_normals= false;
174 bool mesh_has_colors= false;
175
176 std::vector<float> buffer;
177 // parcourir les noeuds de la scene et transformer les meshs associes aux noeuds...
178 for(unsigned node_id= 0; node_id < data->nodes_count; node_id++)
179 {
180 cgltf_node *node= &data->nodes[node_id];
181 if(node->mesh== nullptr)
182 // pas de mesh associe
183 continue;
184
185 // transformation vers la scene
186 float model_matrix[16];
187 cgltf_node_transform_world(node, model_matrix); // transformation globale
188
189 Transform model;
190 model.column_major(model_matrix); // gltf organise les 16 floats par colonne...
191 Transform normal= model.normal(); // transformation pour les normales
192 //~ Transform normal= model; // transformation pour les normales
193
194 cgltf_mesh *mesh= node->mesh;
195 // parcourir les groupes de triangles du mesh...
196 for(unsigned primitive_id= 0; primitive_id < mesh->primitives_count; primitive_id++)
197 {
198 cgltf_primitive *primitives= &mesh->primitives[primitive_id];
199 assert(primitives->type == cgltf_primitive_type_triangles);
200
201 bool primitive_has_texcoords= false;
202 bool primitive_has_normals= false;
203 bool primitive_has_colors= false;
204 unsigned offset= positions.size();
205
206 // matiere associee au groupe de triangles
207 int material_id= -1;
208 if(primitives->material)
209 {
210 assert(material_id < materials.count());
211 assert(materials.find(primitives->material->name) != -1);
212 material_id= materials.find(primitives->material->name);
213 }
214
215 // indices
216 if(primitives->indices)
217 {
218 for(unsigned i= 0; i < primitives->indices->count; i++)
219 indices.push_back(offset + cgltf_accessor_read_index(primitives->indices, i));
220 assert(indices.size() % 3 == 0);
221
222 // un indice de matiere par triplet d'indices / par triangle
223 for(unsigned i= 0; i+2 < primitives->indices->count; i+= 3)
224 material_indices.push_back(material_id);
225 assert(indices.size() / 3 == material_indices.size());
226 }
227
228 // attributs
229 for(unsigned attribute_id= 0; attribute_id < primitives->attributes_count; attribute_id++)
230 {
231 cgltf_attribute *attribute= &primitives->attributes[attribute_id];
232
233 if(attribute->type == cgltf_attribute_type_position)
234 {
235 assert(attribute->data->type == cgltf_type_vec3);
236
237 buffer.resize(cgltf_accessor_unpack_floats(attribute->data, nullptr, 0));
238 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
239
240 // transforme les positions des sommets
241 for(unsigned i= 0; i+2 < buffer.size(); i+= 3)
242 positions.push_back( model(Point(buffer[i], buffer[i+1], buffer[i+2])) );
243 }
244
245 if(attribute->type == cgltf_attribute_type_normal)
246 {
247 assert(attribute->data->type == cgltf_type_vec3);
248
249 primitive_has_normals= true;
250 if(mesh_has_normals == false)
251 {
252 mesh_has_normals= true;
253 // insere une normale par defaut pour tous les sommets precedents...
254 for(unsigned i= 0; i < offset; i++)
255 normals.push_back( vec3() );
256 }
257
258 buffer.resize(cgltf_accessor_unpack_floats(attribute->data, nullptr, 0));
259 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
260
261 // transforme les normales des sommets
262 for(unsigned i= 0; i+2 < buffer.size(); i+= 3)
263 normals.push_back( normal(Vector(buffer[i], buffer[i+1], buffer[i+2])) );
264 //~ assert(normals.size() == positions.size());
265 }
266
267 if(attribute->type == cgltf_attribute_type_texcoord)
268 {
269 assert(attribute->data->type == cgltf_type_vec2);
270
271 primitive_has_texcoords= true;
272 if(mesh_has_texcoords == false)
273 {
274 mesh_has_texcoords= true;
275 // insere des texcoords par defaut pour tous les sommets precedents
276 for(unsigned i= 0; i < offset; i++)
277 texcoords.push_back( vec2() );
278 }
279
280 buffer.resize(cgltf_accessor_unpack_floats(attribute->data, nullptr, 0));
281 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
282
283 for(unsigned i= 0; i+1 < buffer.size(); i+= 2)
284 texcoords.push_back( vec2(buffer[i], buffer[i+1]) );
285 //~ assert(texcoords.size() == positions.size());
286 }
287
288 if(attribute->type == cgltf_attribute_type_color)
289 {
290 assert(attribute->data->type == cgltf_type_vec4);
291
292 primitive_has_colors= true;
293 if(mesh_has_colors == false)
294 {
295 mesh_has_colors= true;
296 // insere une couleur par defaut pour tous les sommtes precedents
297 for(unsigned i= 0; i < offset; i++)
298 colors.push_back( vec4(1, 1, 1, 1) );
299 }
300
301 buffer.resize(cgltf_accessor_unpack_floats(attribute->data, nullptr, 0));
302 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
303 for(unsigned i= 0; i+3 < buffer.size(); i+= 4)
304 colors.push_back( vec4(buffer[i], buffer[i+1], buffer[i+2], buffer[i+3]) );
305 assert(colors.size() == positions.size());
306 }
307 }
308
309 // complete la description des attributs par defaut...
310 if(mesh_has_texcoords && primitive_has_texcoords == false)
311 for(unsigned i= offset; i < positions.size(); i++)
312 texcoords.push_back( vec2() );
313
314 if(mesh_has_normals && primitive_has_normals == false)
315 for(unsigned i= offset; i < positions.size(); i++)
316 normals.push_back( vec3() );
317
318 if(mesh_has_colors && primitive_has_colors == false)
319 for(unsigned i= offset; i < positions.size(); i++)
320 colors.push_back( vec4(1, 1, 1, 1) );
321 }
322 }
323
324 cgltf_free(data);
325
326 // reconstruit le mesh...
327 Mesh mesh(GL_TRIANGLES);
328
329 // 1. les sommets et les attributs, si necessaire...
330 bool has_texcoords= (texcoords.size() == positions.size());
331 bool has_normals= (normals.size() == positions.size());
332 bool has_colors= (colors.size() == positions.size());
333
334 printf("gltf %d positions, %d texcoords, %d normals\n", int(positions.size()), int(texcoords.size()), int(normals.size()));
335
336 for(unsigned i= 0; i < positions.size(); i++)
337 {
338 if(has_texcoords) mesh.texcoord(texcoords[i]);
339 if(has_normals) mesh.normal(normals[i]);
340 if(has_colors) mesh.color(colors[i]);
341
342 mesh.vertex(positions[i]);
343 }
344
345 // 2. les triangles et leurs matieres, si necessaire...
346 mesh.materials(materials);
347 bool has_materials= (materials.count() > 0) && (indices.size() / 3 == material_indices.size());
348 for(unsigned i= 0; i+2 < indices.size(); i+= 3)
349 {
350 if(has_materials) mesh.material(material_indices[i / 3]);
351
352 mesh.triangle(indices[i], indices[i+1], indices[i+2]);
353 }
354 // \bug si les triangles ne sont pas indexes, pas de matieres dans le mesh...
355
356 return mesh;
357}
358
359
360
361static
362std::vector<GLTFCamera> read_cameras( cgltf_data *data )
363{
364 std::vector<GLTFCamera> cameras;
365 for(unsigned i= 0; i < data->nodes_count; i++)
366 {
367 cgltf_node *node= &data->nodes[i];
368 if(node->camera == nullptr)
369 continue;
370
371 cgltf_camera_perspective *perspective= &node->camera->data.perspective;
372
373 //~ if(perspective->has_aspect_ratio)
374 //~ printf(" aspect ratio %f\n", perspective->aspect_ratio);
375 //~ printf(" yfov %f\n", perspective->yfov);
376 //~ printf(" znear %f", perspective->znear);
377 //~ if(perspective->has_zfar)
378 //~ printf(", zfar %f", perspective->zfar);
379 //~ printf("\n");
380
381 Transform projection= Perspective(degrees(perspective->yfov), perspective->aspect_ratio, perspective->znear, perspective->zfar);
382
383 float model_matrix[16];
384 cgltf_node_transform_world(node, model_matrix); // transformation globale
385
386 Transform model;
387 model.column_major(model_matrix); // gltf organise les 16 floats par colonne...
388 Transform view= Inverse(model); // view= inverse(model)
389
390 cameras.push_back( { degrees(perspective->yfov), perspective->aspect_ratio, perspective->znear, perspective->zfar, view, projection } );
391 }
392
393 return cameras;
394}
395
396std::vector<GLTFCamera> read_gltf_cameras( const char *filename )
397{
398 printf("loading glTF camera '%s'...\n", filename);
399
400 cgltf_options options= { };
401 cgltf_data *data= nullptr;
402 cgltf_result code= cgltf_parse_file(&options, filename, &data);
403 if(code != cgltf_result_success)
404 {
405 printf("[error] loading glTF mesh '%s'...\n", filename);
406 return {};
407 }
408
409 if(cgltf_validate(data) != cgltf_result_success)
410 {
411 printf("[error] invalid glTF mesh '%s'...\n", filename);
412 return {};
413 }
414
415 if(data->cameras_count == 0)
416 {
417 printf("[warning] no camera...\n");
418 return {};
419 }
420
421 std::vector<GLTFCamera> cameras= read_cameras(data);
422 cgltf_free(data);
423 return cameras;
424}
425
426
427static
428std::vector<GLTFLight> read_lights( cgltf_data *data )
429{
430 std::vector<GLTFLight> lights;
431 // retrouve les transformations associees aux sources
432 for(unsigned i= 0; i < data->nodes_count; i++)
433 {
434 cgltf_node *node= &data->nodes[i];
435 if(node->light == nullptr)
436 continue;
437
438 //~ int light_id= int(std::distance(data->lights, node->light));
439 //~ printf("light[%u] attached to node[%u]...\n", light_id, i);
440
441 // position de la source
442 float model_matrix[16];
443 cgltf_node_transform_world(node, model_matrix); // transformation globale
444
445 Transform model;
446 model.column_major(model_matrix); // gltf organise les 16 floats par colonne...
447 Point position= model(Origin());
448
449 // proprietes de la source
450 cgltf_light *light= node->light;
451 //~ printf(" position %f %f %f\n", position.x, position.y, position.z);
452 //~ printf(" emission %f %f %f\n", light->color[0], light->color[1], light->color[2]);
453 //~ printf(" intensity %f\n", light->intensity);
454
455 lights.push_back( { position, Color(light->color[0], light->color[1], light->color[2]), light->intensity } );
456 }
457
458 return lights;
459}
460
461std::vector<GLTFLight> read_gltf_lights( const char *filename )
462{
463 printf("loading glTF lights '%s'...\n", filename);
464
465 cgltf_options options= { };
466 cgltf_data *data= nullptr;
467 cgltf_result code= cgltf_parse_file(&options, filename, &data);
468 if(code != cgltf_result_success)
469 {
470 printf("[error] loading glTF mesh '%s'...\n", filename);
471 return {};
472 }
473
474 if(cgltf_validate(data) != cgltf_result_success)
475 {
476 printf("[error] invalid glTF mesh '%s'...\n", filename);
477 return {};
478 }
479
480 if(data->lights_count == 0)
481 {
482 printf("[warning] no lights...\n");
483 return {};
484 }
485
486 std::vector<GLTFLight> lights= read_lights(data);
487 cgltf_free(data);
488 return lights;
489}
490
491
492static
493std::vector<GLTFMaterial> read_materials( cgltf_data *data )
494{
495 std::vector<GLTFMaterial> materials;
496 for(unsigned i= 0; i < data->materials_count; i++)
497 {
498 cgltf_material *material= &data->materials[i];
499 //~ printf("materials[%u] '%s'\n", i, material->name);
500
501 GLTFMaterial m= { };
502 m.color= Color(0.8, 0.8, 0.8, 1);
503 m.metallic= 0;
504 m.roughness= 1;
505 m.transmission= 0;
506 m.ior= 0;
507 m.specular= 0;
509 m.thickness= 0;
510 m.attenuation_distance= 0;
511 m.attenuation_color= Black();
512 m.color_texture= -1;
514 m.occlusion_texture= -1;
515 m.normal_texture= -1;
516 m.emission_texture= -1;
518 m.specular_texture= -1;
520 m.thickness_texture= -1;
521
522 if(material->has_pbr_metallic_roughness)
523 {
524 cgltf_pbr_metallic_roughness *pbr= &material->pbr_metallic_roughness;
525
526 m.color= Color(pbr->base_color_factor[0], pbr->base_color_factor[1], pbr->base_color_factor[2], pbr->base_color_factor[3]);
527 if(pbr->base_color_texture.texture && pbr->base_color_texture.texture->image)
528 m.color_texture= int(std::distance(data->images, pbr->base_color_texture.texture->image));
529
530 m.metallic= pbr->metallic_factor;
531 m.roughness= pbr->roughness_factor;
532 if(pbr->metallic_roughness_texture.texture && pbr->metallic_roughness_texture.texture->image)
533 m.metallic_roughness_texture= int(std::distance(data->images, pbr->metallic_roughness_texture.texture->image));
534
535 printf(" pbr metallic roughness\n");
536 printf(" base color %f %f %f, texture %d\n", m.color.r, m.color.g, m.color.b, m.color_texture);
537 printf(" metallic %f, roughness %f, texture %d\n", m.metallic, m.roughness, m.metallic_roughness_texture);
538 }
539 if(material->has_clearcoat)
540 printf(" clearcoat\n");
541 //~ if(material->has_sheen)
542 //~ printf(" sheen\n");
543
544 if(material->normal_texture.texture && material->normal_texture.texture->image)
545 {
546 //~ printf(" normal texture %d\n", int(std::distance(data->images, material->normal_texture.texture->image)));
547 m.normal_texture= int(std::distance(data->images, material->normal_texture.texture->image));
548 }
549
550 //~ printf(" emissive color %f %f %f\n", material->emissive_factor[0], material->emissive_factor[1], material->emissive_factor[2]);
551 m.emission= Color(material->emissive_factor[0], material->emissive_factor[1], material->emissive_factor[2]);
552 if(material->emissive_texture.texture && material->emissive_texture.texture->image)
553 {
554 //~ printf(" texture %d\n", int(std::distance(data->images, material->emissive_texture.texture->image)));
555 m.emission_texture= int(std::distance(data->images, material->emissive_texture.texture->image));
556 }
557
558
559 if(material->has_ior)
560 {
561 m.ior= material->ior.ior;
562 if(m.ior == float(1.5))
563 m.ior= 0; // valeur par defaut
564
565 if(m.ior)
566 printf(" ior %f\n", m.ior);
567 }
568
569 if(material->has_specular)
570 {
571 m.specular= material->specular.specular_factor;
572 if(material->specular.specular_texture.texture && material->specular.specular_texture.texture->image)
573 m.specular_texture= std::distance(data->images, material->specular.specular_texture.texture->image);
574
575 m.specular_color= Color(material->specular.specular_color_factor[0], material->specular.specular_color_factor[1], material->specular.specular_color_factor[2]);
576 if(material->specular.specular_color_texture.texture && material->specular.specular_color_texture.texture->image)
577 m.specular_color_texture= std::distance(data->images, material->specular.specular_color_texture.texture->image);
578
580 {
581 // parametres incoherents... valeur par defaut / desactive ce comportement
582 m.specular= 0;
584 }
585
586 if(m.specular)
587 printf(" specular %f color %f %f %f, texture %d\n", m.specular, m.specular_color.r, m.specular_color.g, m.specular_color.b, m.specular_texture);
588 }
589
590 if(material->has_transmission)
591 {
592 m.transmission= material->transmission.transmission_factor;
593 if(material->transmission.transmission_texture.texture && material->transmission.transmission_texture.texture->image)
594 m.transmission_texture= std::distance(data->images, material->transmission.transmission_texture.texture->image);
595
596 if(m.transmission)
597 printf(" transmission %f, texture %d\n", m.transmission, m.transmission_texture);
598 }
599
600 if(material->has_volume)
601 {
602 m.thickness= material->volume.thickness_factor;
603 if(material->volume.thickness_texture.texture && material->volume.thickness_texture.texture->image)
604 m.thickness_texture= std::distance(data->images, material->volume.thickness_texture.texture->image);
605
606 m.attenuation_distance= material->volume.attenuation_distance;
607 m.attenuation_color= Color(material->volume.attenuation_color[0], material->volume.attenuation_color[1], material->volume.attenuation_color[2]);
608 printf(" volume thickness %f, texture %d\n",m.thickness, m.thickness_texture);
609 printf(" volume attenation distance %f, color %f %f %f\n", m.attenuation_distance, m.attenuation_color.r, m.attenuation_color.g, m.attenuation_color.b);
610 }
611
612 materials.push_back(m);
613 }
614
615 return materials;
616}
617
618std::vector<GLTFMaterial> read_gltf_materials( const char *filename )
619{
620 printf("loading glTF materials '%s'...\n", filename);
621
622 cgltf_options options= { };
623 cgltf_data *data= nullptr;
624 cgltf_result code= cgltf_parse_file(&options, filename, &data);
625 if(code != cgltf_result_success)
626 {
627 printf("[error] loading glTF mesh '%s'...\n", filename);
628 return {};
629 }
630
631 if(cgltf_validate(data) != cgltf_result_success)
632 {
633 printf("[error] invalid glTF mesh '%s'...\n", filename);
634 return {};
635 }
636
637 if(data->materials_count ==0)
638 {
639 printf("[warning] no materials...\n");
640 return {};
641 }
642
643 std::vector<GLTFMaterial> materials= read_materials(data);
644 cgltf_free(data);
645 return materials;
646}
647
648
649std::vector<ImageData> read_gltf_images( const char *filename )
650{
651 printf("loading glTF images '%s'...\n", filename);
652
653 cgltf_options options= { };
654 cgltf_data *data= nullptr;
655 cgltf_result code= cgltf_parse_file(&options, filename, &data);
656 if(code != cgltf_result_success)
657 {
658 printf("[error] loading glTF mesh '%s'...\n", filename);
659 return {};
660 }
661
662 if(cgltf_validate(data) != cgltf_result_success)
663 {
664 printf("[error] invalid glTF mesh '%s'...\n", filename);
665 return {};
666 }
667
668 if(data->images_count == 0)
669 {
670 printf("[warning] no images...\n");
671 return {};
672 }
673
674 // detecte s'il faut charger aussi les buffers...
675 for(unsigned i= 0; i < data->images_count; i++)
676 if(!data->images[i].uri)
677 {
678 code= cgltf_load_buffers(&options, data, filename);
679 if(code != cgltf_result_success)
680 {
681 printf("[error] loading glTF internal images...\n");
682 cgltf_free(data);
683 return {};
684 }
685
686 break;
687 }
688
689
690 std::vector<ImageData> images(data->images_count);
691
692#pragma omp parallel for schedule(dynamic, 1)
693 for(unsigned i= 0; i < data->images_count; i++)
694 {
695 if(data->images[i].uri)
696 {
697 //~ printf(" [%u] %s\n", i, data->images[i].uri);
698 std::string image_filename= pathname(filename) + std::string(data->images[i].uri);
699 images[i]= read_image_data(image_filename.c_str());
700 }
701 else if(data->images[i].buffer_view)
702 {
703 // extraire l'image du glb...
704 cgltf_buffer_view *view= data->images[i].buffer_view;
705 assert(view->buffer->data);
706 //~ printf(" [%u] %s offset %lu size %lu, type '%s'\n", i, data->images[i].name, view->offset, view->size, data->images[i].mime_type);
707 images[i]= read_image_data((uint8_t *) view->buffer->data + view->offset, view->size);
708 }
709 }
710
711 cgltf_free(data);
712 return images;
713}
714
715
716GLTFScene read_gltf_scene( const char *filename )
717{
718 printf("loading glTF scene '%s'...\n", filename);
719
720 cgltf_options options= { };
721 cgltf_data *data= nullptr;
722 cgltf_result code= cgltf_parse_file(&options, filename, &data);
723 if(code != cgltf_result_success)
724 {
725 printf("[error] loading glTF mesh '%s'...\n", filename);
726 return { };
727 }
728
729 if(cgltf_validate(data) != cgltf_result_success)
730 {
731 printf("[error] invalid glTF mesh '%s'...\n", filename);
732 return { };
733 }
734
735 code= cgltf_load_buffers(&options, data, filename);
736 if(code != cgltf_result_success)
737 {
738 printf("[error] loading glTF buffers...\n");
739 return { };
740 }
741
742 //
743 GLTFScene scene;
744
745// etape 1 : construire les meshs et les groupes de triangles / primitives
746 int primitives_index= 0;
747 std::vector<float> buffer;
748
749 // parcourir tous les meshs de la scene
750 for(unsigned mesh_id= 0; mesh_id < data->meshes_count; mesh_id++)
751 {
752 GLTFMesh m= { };
753 m.pmin= Point(FLT_MAX, FLT_MAX, FLT_MAX);
754 m.pmax= Point(-FLT_MAX, -FLT_MAX, -FLT_MAX);
755
756 cgltf_mesh *mesh= &data->meshes[mesh_id];
757 // parcourir les groupes de triangles du mesh...
758 for(unsigned primitive_id= 0; primitive_id < mesh->primitives_count; primitive_id++)
759 {
760 cgltf_primitive *primitives= &mesh->primitives[primitive_id];
761 assert(primitives->type == cgltf_primitive_type_triangles);
762
763 GLTFPrimitives p= { };
764
765 // matiere associee au groupe de triangles
766 p.material_index= -1;
767 if(primitives->material)
768 p.material_index= std::distance(data->materials, primitives->material);
769
770 // indices
771 if(primitives->indices)
772 {
773 for(unsigned i= 0; i < primitives->indices->count; i++)
774 p.indices.push_back(cgltf_accessor_read_index(primitives->indices, i));
775 assert(p.indices.size() % 3 == 0);
776 }
777
778 // attributs
779 for(unsigned attribute_id= 0; attribute_id < primitives->attributes_count; attribute_id++)
780 {
781 cgltf_attribute *attribute= &primitives->attributes[attribute_id];
782
783 if(attribute->type == cgltf_attribute_type_position)
784 {
785 assert(attribute->data->type == cgltf_type_vec3);
786
787 buffer.resize(cgltf_accessor_unpack_floats(attribute->data, nullptr, 0));
788 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
789
790 // transforme les positions des sommets
791 for(unsigned i= 0; i+2 < buffer.size(); i+= 3)
792 p.positions.push_back( vec3(buffer[i], buffer[i+1], buffer[i+2]) );
793
794 #if 0
795 assert(attribute->data->has_min);
796 assert(attribute->data->has_max);
797 p.pmin= vec3(attribute->data->min[0], attribute->data->min[1], attribute->data->min[2]);
798 p.pmax= vec3(attribute->data->max[0], attribute->data->max[1], attribute->data->max[2]);
799 #else
800 p.pmin= p.positions[0];
801 p.pmax= p.positions[0];
802 for(unsigned i= 1; i < p.positions.size(); i++)
803 {
804 p.pmin= min(p.pmin, p.positions[i]);
805 p.pmax= max(p.pmax, p.positions[i]);
806 }
807 #endif
808 m.pmin= min(m.pmin, p.pmin);
809 m.pmax= max(m.pmax, p.pmax);
810 }
811
812 if(attribute->type == cgltf_attribute_type_normal)
813 {
814 assert(attribute->data->type == cgltf_type_vec3);
815
816 buffer.resize(cgltf_accessor_unpack_floats(attribute->data, nullptr, 0));
817 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
818
819 // transforme les normales des sommets
820 for(unsigned i= 0; i+2 < buffer.size(); i+= 3)
821 p.normals.push_back( vec3(buffer[i], buffer[i+1], buffer[i+2]) );
822 }
823
824 if(attribute->type == cgltf_attribute_type_texcoord)
825 {
826 assert(attribute->data->type == cgltf_type_vec2);
827
828 buffer.resize(cgltf_accessor_unpack_floats(attribute->data, nullptr, 0));
829 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
830
831 for(unsigned i= 0; i+1 < buffer.size(); i+= 2)
832 p.texcoords.push_back( vec2(buffer[i], buffer[i+1]) );
833 }
834 }
835
836 p.primitives_index= primitives_index++;
837 m.primitives.push_back(p);
838 }
839
840 scene.meshes.push_back(m);
841 }
842
843// etape 2 : parcourir les noeuds, retrouver les transforms pour placer les meshes
844 for(unsigned node_id= 0; node_id < data->nodes_count; node_id++)
845 {
846 cgltf_node *node= &data->nodes[node_id];
847 if(node->mesh== nullptr)
848 // pas de mesh associe, rien a dessiner
849 continue;
850
851 // recuperer la transformation pour placer le mesh dans la scene
852 float model_matrix[16];
853 cgltf_node_transform_world(node, model_matrix);
854
855 Transform model;
856 model.column_major(model_matrix); // gltf organise les 16 floats par colonne...
857 //~ Transform normal= model.normal(); // transformation pour les normales
858
859 int mesh_index= std::distance(data->meshes, node->mesh);
860 scene.nodes.push_back( {model, mesh_index} );
861 }
862
863// etape 3 : recuperer les autres infos...
864 scene.materials= read_materials(data);
865 scene.lights= read_lights(data);
866 scene.cameras= read_cameras(data);
867
868// etape : nettoyage...
869 cgltf_free(data);
870
871 return scene;
872}
873
874std::vector<GLTFInstances> GLTFScene::instances( ) const
875{
876 std::vector<GLTFInstances> instances(meshes.size());
877 for(unsigned i= 0; i < meshes.size(); i++)
878 instances[i].mesh_index= i;
879
880 for(unsigned i= 0; i < nodes.size(); i++)
881 {
882 int index= nodes[i].mesh_index;
883 assert(index < int(instances.size()));
884 instances[index].transforms.push_back( nodes[i].model );
885 }
886
887 return instances;
888}
889
890
891void GLTFScene::bounds( Point& pmin, Point& pmax ) const
892{
893 pmin= Point(FLT_MAX, FLT_MAX, FLT_MAX);
894 pmax= Point(-FLT_MAX, -FLT_MAX, -FLT_MAX);
895 for(unsigned node_id= 0; node_id < nodes.size(); node_id++)
896 {
897 const GLTFNode& node= nodes[node_id];
898 const GLTFMesh& mesh= meshes[node.mesh_index];
899 for(unsigned primitive_id= 0; primitive_id < mesh.primitives.size(); primitive_id++)
900 {
901 const GLTFPrimitives& primitives= mesh.primitives[primitive_id];
902 for(unsigned i= 0; i < primitives.positions.size(); i++)
903 {
904 //~ Point p= node.model(Point(primitives.positions[i]));
905 Point p= Point(primitives.positions[i]);
906 pmin= min(pmin, p);
907 pmax= max(pmax, p);
908 }
909 }
910 }
911}
representation d'un objet / maillage.
Definition mesh.h:121
scene glTF.
Point pmax
points extremes de l'englobant dans le repere objet
Definition gltf.h:117
int mesh_index
indice du maillage.
Definition gltf.h:131
int material_index
indice de la matiere des primitives.
Definition gltf.h:102
int primitives_index
indice unique.
Definition gltf.h:101
Point pmax
points extremes de l'englobant dans le repere objet
Definition gltf.h:104
std::vector< GLTFPrimitives > primitives
groupes de triangles associes a une matiere.
Definition gltf.h:116
description d'un maillage.
Definition gltf.h:115
position et orientation d'un maillage dans la scene.
Definition gltf.h:129
groupe de triangles d'un maillage. chaque groupe est associe a une matiere.
Definition gltf.h:99
void printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
Definition text.cpp:140
Color Black()
utilitaire. renvoie une couleur noire.
Definition color.cpp:18
Image flipY(const Image &image)
retourne l'image
Definition image_io.cpp:112
int write_image_data(ImageData &image, const char *filename, const bool flipY)
enregistre des donnees dans un fichier png.
Definition image_io.cpp:346
ImageData read_image_data(const void *buffer, const unsigned size, const bool flipY)
charge les donnees d'un fichier png stocke en memoire. renvoie une image initialisee par defaut en ca...
Definition image_io.cpp:315
Transform Inverse(const Transform &m)
renvoie l'inverse de la matrice.
Definition mat.cpp:197
Point Origin()
renvoie le point origine (0, 0, 0)
Definition vec.cpp:8
Point max(const Point &a, const Point &b)
renvoie la plus grande composante de chaque point { max(a.x, b.x), max(a.y, b.y), max(a....
Definition vec.cpp:35
float degrees(const float angle)
conversion en degres.
Definition mat.cpp:15
Point min(const Point &a, const Point &b)
renvoie la plus petite composante de chaque point { min(a.x, b.x), min(a.y, b.y), min(a....
Definition vec.cpp:30
Transform Perspective(const float fov, const float aspect, const float znear, const float zfar)
renvoie la matrice representant une transformation projection perspective.
Definition mat.cpp:329
void normals(MeshData &data)
(re-) calcule les normales des sommets. utiliser avant les reindexations, cf indices() et vertices().
representation d'une couleur (rgba) transparente ou opaque.
Definition color.h:14
float transmission
transmission, transparent ou pas (= 0)
Definition gltf.h:64
int color_texture
indice de la texture ou -1. cf read_gltf_images() pour charger les textures dans le bon ordre....
Definition gltf.h:73
float roughness
rugosite de la micro surface.
Definition gltf.h:63
int metallic_roughness_texture
indice de la texture ou -1. les valeurs RGB representent les parametres du modele : B= metallic,...
Definition gltf.h:74
int emission_texture
indice de la texture ou -1.
Definition gltf.h:75
Color specular_color
modification de la reflexion speculaire des dielectriques ou pas (= 0)
Definition gltf.h:67
Color emission
emission pour les sources de lumieres ou pas (= noir).
Definition gltf.h:61
int normal_texture
indice de la texture ou -1.
Definition gltf.h:77
float specular
modification de la reflexion speculaire des dielectriques ou pas (= 0)
Definition gltf.h:66
int transmission_texture
indice de la texture ou -1.
Definition gltf.h:78
float ior
indice de refraction des dielectriques ou pas (= 0)
Definition gltf.h:65
float thickness
epaisseur des surfaces transparentes
Definition gltf.h:68
int specular_color_texture
indice de la texture ou -1.
Definition gltf.h:80
float metallic
metallic / dielectrique.
Definition gltf.h:62
int specular_texture
indice de la texture ou -1.
Definition gltf.h:79
Color color
base color.
Definition gltf.h:60
int occlusion_texture
indice de la texture ou -1. //
Definition gltf.h:76
void bounds(Point &pmin, Point &pmax) const
calcule les points extremes de la scene, utile pour regler un orbiter.
Definition gltf.cpp:891
std::vector< GLTFMaterial > materials
matieres.
Definition gltf.h:153
std::vector< GLTFInstances > instances() const
regroupe les instances de chaque maillage.
Definition gltf.cpp:874
std::vector< GLTFNode > nodes
noeuds / position et orientation des maillages dans la scene.
Definition gltf.h:151
std::vector< GLTFMesh > meshes
ensemble de maillages.
Definition gltf.h:150
stockage temporaire des donnees d'une image.
Definition image_io.h:53
int diffuse_texture
indice de la texture de la couleur de base, ou -1.
Definition materials.h:21
float ns
concentration des reflets, exposant pour les reflets blinn-phong.
Definition materials.h:20
Color diffuse
couleur diffuse / de base.
Definition materials.h:17
Color specular
couleur du reflet.
Definition materials.h:18
int insert(const Material &material, const char *name)
ajoute une matiere.
Definition materials.h:62
int find(const char *name)
recherche une matiere avec son nom. renvoie son indice dans materials, ou -1.
Definition materials.h:88
int insert_texture(const char *filename)
ajoute une texture / nom du fichier.
Definition materials.h:76
int count() const
nombre de matieres.
Definition materials.h:102
representation d'un point 3d.
Definition vec.h:21
representation d'une transformation, une matrice 4x4, organisee par ligne / row major.
Definition mat.h:21
Transform & column_major(const float matrix[16])
initialise la matrice avec 16 floats organises par colonne.
Definition mat.cpp:32
Transform normal() const
renvoie la transformation a appliquer aux normales d'un objet transforme par la matrice m.
Definition mat.cpp:181
representation d'un vecteur 3d.
Definition vec.h:67
vecteur generique, utilitaire.
Definition vec.h:152
vecteur generique, utilitaire.
Definition vec.h:169
vecteur generique 4d, ou 3d homogene, utilitaire.
Definition vec.h:192
bool has_normals(const Hit &hit, const GLTFScene &scene)
verifie la presence des normales par sommet.
bool has_texcoords(const Hit &hit, const GLTFScene &scene)
verifie la presence des coordonnees de texture...