13 #include "SDL2/SDL_rwops.h"
14 #include "SDL2/SDL_surface.h"
15 #include "SDL2/SDL_image.h"
21 printf(
"loading glTF mesh '%s'...\n", filename);
25 cgltf_result code= cgltf_parse_file(&options, filename, &data);
26 if(code != cgltf_result_success)
28 printf(
"[error] loading glTF mesh '%s'...\n", filename);
32 if(cgltf_validate(data) != cgltf_result_success)
34 printf(
"[error] invalid glTF mesh '%s'...\n", filename);
38 code= cgltf_load_buffers(&options, data, filename);
39 if(code != cgltf_result_success)
41 printf(
"[error] loading glTF buffers...\n");
46 std::vector<unsigned> indices;
47 std::vector<int> material_indices;
48 std::vector<vec3> positions;
49 std::vector<vec2> texcoords;
51 std::vector<vec4> colors;
56 for(
unsigned i= 0; i < data->images_count; i++)
58 if(data->images[i].uri)
60 printf(
"texture '%s'...\n", data->images[i].uri);
63 else if(data->images[i].buffer_view)
78 if(!view->buffer->uri)
81 if(data->images[i].name && data->images[i].name[0])
82 sprintf(tmp,
"%s%s",
pathname(filename).c_str(), data->images[i].name);
84 sprintf(tmp,
"%stexture%d.png",
pathname(filename).c_str(), i);
86 printf(
"packed texture '%s'...\n", tmp);
90 if(strcmp(data->images[i].mime_type,
"image/png") == 0)
92 else if(strcmp(data->images[i].mime_type,
"image/jpg") == 0)
97 printf(
"unpacking glb texture '%s' to '%s'...\n", data->images[i].name, tmp);
99 FILE *out= fopen(tmp,
"wb");
102 if(fwrite((
char *) view->buffer->data + view->offset, view->size, 1, out) != 1)
103 printf(
"[error] unpacking glb texture '%s' to '%s'...\n", data->images[i].name, tmp);
113 if(
char *ext= strrchr(tmp,
'.'))
114 strcpy(ext,
"_flip.png");
116 printf(
"writing flipped texture '%s'...\n", tmp);
120 assert(data->images[i].uri ==
nullptr);
121 data->images[i].uri= strdup(tmp);
128 for(
unsigned i= 0; i < data->materials_count; i++)
134 if(material->has_pbr_metallic_roughness)
143 Color color=
Color(pbr->base_color_factor[0], pbr->base_color_factor[1], pbr->base_color_factor[2], pbr->base_color_factor[3]);
144 float metallic= pbr->metallic_factor;
145 float roughness= pbr->roughness_factor;
154 m.
ns= 2 / (roughness * roughness * roughness * roughness) - 2;
155 if(m.
ns <
float(1.1))
164 if(pbr->base_color_texture.texture && pbr->base_color_texture.texture->image)
171 sprintf(tmp,
"material%d", i);
172 material->name= strdup(tmp);
175 materials.
insert(m, material->name);
178 bool mesh_has_texcoords=
false;
179 bool mesh_has_normals=
false;
180 bool mesh_has_colors=
false;
182 std::vector<float> buffer;
184 for(
unsigned node_id= 0; node_id < data->nodes_count; node_id++)
187 if(node->mesh==
nullptr)
192 float model_matrix[16];
193 cgltf_node_transform_world(node, model_matrix);
202 for(
unsigned primitive_id= 0; primitive_id < mesh->primitives_count; primitive_id++)
205 assert(primitives->type == cgltf_primitive_type_triangles);
207 bool primitive_has_texcoords=
false;
208 bool primitive_has_normals=
false;
209 bool primitive_has_colors=
false;
210 unsigned offset= positions.size();
214 if(primitives->material)
216 assert(material_id < materials.
count());
217 assert(materials.
find(primitives->material->name) != -1);
218 material_id= materials.
find(primitives->material->name);
222 if(primitives->indices)
224 for(
unsigned i= 0; i < primitives->indices->count; i++)
225 indices.push_back(offset + cgltf_accessor_read_index(primitives->indices, i));
226 assert(indices.size() % 3 == 0);
229 for(
unsigned i= 0; i+2 < primitives->indices->count; i+= 3)
230 material_indices.push_back(material_id);
231 assert(indices.size() / 3 == material_indices.size());
235 for(
unsigned attribute_id= 0; attribute_id < primitives->attributes_count; attribute_id++)
239 if(attribute->type == cgltf_attribute_type_position)
241 assert(attribute->data->type == cgltf_type_vec3);
243 buffer.resize(cgltf_accessor_unpack_floats(attribute->data,
nullptr, 0));
244 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
247 for(
unsigned i= 0; i+2 < buffer.size(); i+= 3)
248 positions.push_back( model(
Point(buffer[i], buffer[i+1], buffer[i+2])) );
251 if(attribute->type == cgltf_attribute_type_normal)
253 assert(attribute->data->type == cgltf_type_vec3);
255 primitive_has_normals=
true;
256 if(mesh_has_normals ==
false)
258 mesh_has_normals=
true;
260 for(
unsigned i= 0; i < offset; i++)
264 buffer.resize(cgltf_accessor_unpack_floats(attribute->data,
nullptr, 0));
265 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
268 for(
unsigned i= 0; i+2 < buffer.size(); i+= 3)
269 normals.push_back( normal(
Vector(buffer[i], buffer[i+1], buffer[i+2])) );
273 if(attribute->type == cgltf_attribute_type_texcoord)
275 assert(attribute->data->type == cgltf_type_vec2);
277 primitive_has_texcoords=
true;
278 if(mesh_has_texcoords ==
false)
280 mesh_has_texcoords=
true;
282 for(
unsigned i= 0; i < offset; i++)
283 texcoords.push_back(
vec2() );
286 buffer.resize(cgltf_accessor_unpack_floats(attribute->data,
nullptr, 0));
287 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
289 for(
unsigned i= 0; i+1 < buffer.size(); i+= 2)
290 texcoords.push_back(
vec2(buffer[i], buffer[i+1]) );
294 if(attribute->type == cgltf_attribute_type_color)
296 assert(attribute->data->type == cgltf_type_vec4);
298 primitive_has_colors=
true;
299 if(mesh_has_colors ==
false)
301 mesh_has_colors=
true;
303 for(
unsigned i= 0; i < offset; i++)
304 colors.push_back(
vec4(1, 1, 1, 1) );
307 buffer.resize(cgltf_accessor_unpack_floats(attribute->data,
nullptr, 0));
308 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
309 for(
unsigned i= 0; i+3 < buffer.size(); i+= 4)
310 colors.push_back(
vec4(buffer[i], buffer[i+1], buffer[i+2], buffer[i+3]) );
311 assert(colors.size() == positions.size());
316 if(mesh_has_texcoords && primitive_has_texcoords ==
false)
317 for(
unsigned i= offset; i < positions.size(); i++)
318 texcoords.push_back(
vec2() );
320 if(mesh_has_normals && primitive_has_normals ==
false)
321 for(
unsigned i= offset; i < positions.size(); i++)
324 if(mesh_has_colors && primitive_has_colors ==
false)
325 for(
unsigned i= offset; i < positions.size(); i++)
326 colors.push_back(
vec4(1, 1, 1, 1) );
333 Mesh mesh(GL_TRIANGLES);
338 bool has_colors= (colors.size() == positions.size());
340 printf(
"gltf %d positions, %d texcoords, %d normals\n",
int(positions.size()),
int(texcoords.size()),
int(
normals.size()));
342 for(
unsigned i= 0; i < positions.size(); i++)
346 if(has_colors) mesh.
color(colors[i]);
348 mesh.
vertex(positions[i]);
353 bool has_materials= (materials.
count() > 0) && (indices.size() / 3 == material_indices.size());
354 for(
unsigned i= 0; i+2 < indices.size(); i+= 3)
356 if(has_materials) mesh.
material(material_indices[i / 3]);
358 mesh.
triangle(indices[i], indices[i+1], indices[i+2]);
368 std::vector<GLTFCamera> read_cameras(
cgltf_data *data )
370 std::vector<GLTFCamera> cameras;
371 for(
unsigned i= 0; i < data->nodes_count; i++)
374 if(node->camera ==
nullptr)
389 float model_matrix[16];
390 cgltf_node_transform_world(node, model_matrix);
396 cameras.push_back( {
degrees(perspective->yfov), perspective->aspect_ratio, perspective->znear, perspective->zfar, view, projection } );
404 printf(
"loading glTF camera '%s'...\n", filename);
408 cgltf_result code= cgltf_parse_file(&options, filename, &data);
409 if(code != cgltf_result_success)
411 printf(
"[error] loading glTF mesh '%s'...\n", filename);
415 if(cgltf_validate(data) != cgltf_result_success)
417 printf(
"[error] invalid glTF mesh '%s'...\n", filename);
421 if(data->cameras_count == 0)
423 printf(
"[warning] no camera...\n");
427 std::vector<GLTFCamera> cameras= read_cameras(data);
434 std::vector<GLTFLight> read_lights(
cgltf_data *data )
436 std::vector<GLTFLight> lights;
438 for(
unsigned i= 0; i < data->nodes_count; i++)
441 if(node->light ==
nullptr)
448 float model_matrix[16];
449 cgltf_node_transform_world(node, model_matrix);
461 lights.push_back( { position,
Color(light->color[0], light->color[1], light->color[2]), light->intensity } );
469 printf(
"loading glTF lights '%s'...\n", filename);
473 cgltf_result code= cgltf_parse_file(&options, filename, &data);
474 if(code != cgltf_result_success)
476 printf(
"[error] loading glTF mesh '%s'...\n", filename);
480 if(cgltf_validate(data) != cgltf_result_success)
482 printf(
"[error] invalid glTF mesh '%s'...\n", filename);
486 if(data->lights_count == 0)
488 printf(
"[warning] no lights...\n");
492 std::vector<GLTFLight> lights= read_lights(data);
501 std::vector<GLTFMaterial> materials;
502 for(
unsigned i= 0; i < data->materials_count; i++)
516 m.attenuation_distance= 0;
517 m.attenuation_color=
Black();
526 m.thickness_texture= -1;
528 if(material->has_pbr_metallic_roughness)
532 m.
color=
Color(pbr->base_color_factor[0], pbr->base_color_factor[1], pbr->base_color_factor[2], pbr->base_color_factor[3]);
533 if(pbr->base_color_texture.texture && pbr->base_color_texture.texture->image)
538 if(pbr->metallic_roughness_texture.texture && pbr->metallic_roughness_texture.texture->image)
541 printf(
" pbr metallic roughness\n");
545 if(material->has_clearcoat)
550 if(material->normal_texture.texture && material->normal_texture.texture->image)
557 m.
emission=
Color(material->emissive_factor[0], material->emissive_factor[1], material->emissive_factor[2]);
558 if(material->emissive_texture.texture && material->emissive_texture.texture->image)
565 if(material->has_ior)
567 m.
ior= material->ior.ior;
568 if(m.
ior ==
float(1.5))
575 if(material->has_specular)
577 m.
specular= material->specular.specular_factor;
578 if(material->specular.specular_texture.texture && material->specular.specular_texture.texture->image)
581 m.
specular_color=
Color(material->specular.specular_color_factor[0], material->specular.specular_color_factor[1], material->specular.specular_color_factor[2]);
582 if(material->specular.specular_color_texture.texture && material->specular.specular_color_texture.texture->image)
596 if(material->has_transmission)
598 m.
transmission= material->transmission.transmission_factor;
599 if(material->transmission.transmission_texture.texture && material->transmission.transmission_texture.texture->image)
606 if(material->has_volume)
608 m.
thickness= material->volume.thickness_factor;
609 if(material->volume.thickness_texture.texture && material->volume.thickness_texture.texture->image)
610 m.thickness_texture=
std::distance(data->images, material->volume.thickness_texture.texture->image);
612 m.attenuation_distance= material->volume.attenuation_distance;
613 m.attenuation_color=
Color(material->volume.attenuation_color[0], material->volume.attenuation_color[1], material->volume.attenuation_color[2]);
614 printf(
" volume thickness %f, texture %d\n",m.
thickness, m.thickness_texture);
615 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);
618 materials.push_back(m);
626 printf(
"loading glTF materials '%s'...\n", filename);
630 cgltf_result code= cgltf_parse_file(&options, filename, &data);
631 if(code != cgltf_result_success)
633 printf(
"[error] loading glTF mesh '%s'...\n", filename);
637 if(cgltf_validate(data) != cgltf_result_success)
639 printf(
"[error] invalid glTF mesh '%s'...\n", filename);
643 if(data->materials_count ==0)
645 printf(
"[warning] no materials...\n");
657 printf(
"loading glTF images '%s'...\n", filename);
661 cgltf_result code= cgltf_parse_file(&options, filename, &data);
662 if(code != cgltf_result_success)
664 printf(
"[error] loading glTF mesh '%s'...\n", filename);
668 if(cgltf_validate(data) != cgltf_result_success)
670 printf(
"[error] invalid glTF mesh '%s'...\n", filename);
674 if(data->images_count == 0)
676 printf(
"[warning] no images...\n");
681 for(
unsigned i= 0; i < data->images_count; i++)
682 if(!data->images[i].uri)
684 code= cgltf_load_buffers(&options, data, filename);
685 if(code != cgltf_result_success)
687 printf(
"[error] loading glTF internal images...\n");
696 std::vector<ImageData> images(data->images_count);
698 #pragma omp parallel for schedule(dynamic, 1)
699 for(
unsigned i= 0; i < data->images_count; i++)
701 if(data->images[i].uri)
704 std::string image_filename=
pathname(filename) + std::string(data->images[i].uri);
707 else if(data->images[i].buffer_view)
711 assert(view->buffer->data);
714 SDL_RWops *read= SDL_RWFromConstMem((uint8_t *) view->buffer->data + view->offset, view->size);
717 images[i]=
image_data( IMG_Load_RW(read, 1) );
728 printf(
"loading glTF scene '%s'...\n", filename);
732 cgltf_result code= cgltf_parse_file(&options, filename, &data);
733 if(code != cgltf_result_success)
735 printf(
"[error] loading glTF mesh '%s'...\n", filename);
739 if(cgltf_validate(data) != cgltf_result_success)
741 printf(
"[error] invalid glTF mesh '%s'...\n", filename);
745 code= cgltf_load_buffers(&options, data, filename);
746 if(code != cgltf_result_success)
748 printf(
"[error] loading glTF buffers...\n");
756 int primitives_index= 0;
757 std::vector<float> buffer;
760 for(
unsigned mesh_id= 0; mesh_id < data->meshes_count; mesh_id++)
763 m.pmin=
Point(FLT_MAX, FLT_MAX, FLT_MAX);
764 m.
pmax=
Point(-FLT_MAX, -FLT_MAX, -FLT_MAX);
768 for(
unsigned primitive_id= 0; primitive_id < mesh->primitives_count; primitive_id++)
771 assert(primitives->type == cgltf_primitive_type_triangles);
777 if(primitives->material)
781 if(primitives->indices)
783 for(
unsigned i= 0; i < primitives->indices->count; i++)
784 p.indices.push_back(cgltf_accessor_read_index(primitives->indices, i));
785 assert(p.indices.size() % 3 == 0);
789 for(
unsigned attribute_id= 0; attribute_id < primitives->attributes_count; attribute_id++)
793 if(attribute->type == cgltf_attribute_type_position)
795 assert(attribute->data->type == cgltf_type_vec3);
797 buffer.resize(cgltf_accessor_unpack_floats(attribute->data,
nullptr, 0));
798 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
801 for(
unsigned i= 0; i+2 < buffer.size(); i+= 3)
802 p.positions.push_back(
vec3(buffer[i], buffer[i+1], buffer[i+2]) );
805 assert(attribute->data->has_min);
806 assert(attribute->data->has_max);
807 p.pmin=
vec3(attribute->data->min[0], attribute->data->min[1], attribute->data->min[2]);
808 p.
pmax=
vec3(attribute->data->max[0], attribute->data->max[1], attribute->data->max[2]);
810 p.pmin= p.positions[0];
811 p.
pmax= p.positions[0];
812 for(
unsigned i= 1; i < p.positions.size(); i++)
814 p.pmin=
min(p.pmin, p.positions[i]);
818 m.pmin=
min(m.pmin, p.pmin);
822 if(attribute->type == cgltf_attribute_type_normal)
824 assert(attribute->data->type == cgltf_type_vec3);
826 buffer.resize(cgltf_accessor_unpack_floats(attribute->data,
nullptr, 0));
827 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
830 for(
unsigned i= 0; i+2 < buffer.size(); i+= 3)
831 p.normals.push_back(
vec3(buffer[i], buffer[i+1], buffer[i+2]) );
834 if(attribute->type == cgltf_attribute_type_texcoord)
836 assert(attribute->data->type == cgltf_type_vec2);
838 buffer.resize(cgltf_accessor_unpack_floats(attribute->data,
nullptr, 0));
839 cgltf_accessor_unpack_floats(attribute->data, buffer.data(), buffer.size());
841 for(
unsigned i= 0; i+1 < buffer.size(); i+= 2)
842 p.texcoords.push_back(
vec2(buffer[i], buffer[i+1]) );
850 scene.
meshes.push_back(m);
854 for(
unsigned node_id= 0; node_id < data->nodes_count; node_id++)
857 if(node->mesh==
nullptr)
862 float model_matrix[16];
863 cgltf_node_transform_world(node, model_matrix);
870 scene.
nodes.push_back( {model, mesh_index} );
875 scene.
lights= read_lights(data);
876 scene.
cameras= read_cameras(data);
887 for(
unsigned i= 0; i <
meshes.size(); i++)
890 for(
unsigned i= 0; i <
nodes.size(); i++)
892 int index=
nodes[i].mesh_index;
903 pmin=
Point(FLT_MAX, FLT_MAX, FLT_MAX);
904 pmax=
Point(-FLT_MAX, -FLT_MAX, -FLT_MAX);
905 for(
unsigned node_id= 0; node_id <
nodes.size(); node_id++)
909 for(
unsigned primitive_id= 0; primitive_id < mesh.
primitives.size(); primitive_id++)
912 for(
unsigned i= 0; i < primitives.positions.size(); i++)
representation d'un objet / maillage.
unsigned int vertex(const vec3 &p)
insere un sommet de position p, et ses attributs (s'ils sont definis par color(), texcoord(),...
Mesh & texcoord(const vec2 &uv)
definit les coordonnees de texture du prochain sommet.
Mesh & material(const unsigned int id)
definit la matiere du prochain triangle. id est l'indice d'une matiere ajoutee dans materials(),...
Mesh & triangle(const unsigned int a, const unsigned int b, const unsigned int c)
Mesh & normal(const vec3 &n)
definit la normale du prochain sommet.
GLenum primitives() const
renvoie le type de primitives.
Mesh & color(const vec4 &c)
definit la couleur du prochain sommet.
const Materials & materials() const
renvoie la description des matieres.
Point pmax
points extremes de l'englobant dans le repere objet
Mesh read_gltf_mesh(const char *filename)
charge un fichier .gltf et construit un mesh statique, sans animation.
int mesh_index
indice du maillage.
std::vector< ImageData > read_gltf_images(const char *filename)
charge un fichier .gltf et charge les images referencees par les matieres.
std::vector< GLTFMaterial > read_gltf_materials(const char *filename)
charge un fichier .gltf et renvoie les matieres.
int material_index
indice de la matiere des primitives.
int primitives_index
indice unique.
Point pmax
points extremes de l'englobant dans le repere objet
GLTFScene read_gltf_scene(const char *filename)
charge un fichier .gltf et construit une scene statique, sans animation.
std::vector< GLTFPrimitives > primitives
groupes de triangles associes a une matiere.
std::vector< GLTFLight > read_gltf_lights(const char *filename)
charge un fichier .gltf et renvoie les sources de lumiere ponctuelles.
std::vector< GLTFCamera > read_gltf_cameras(const char *filename)
charge un fichier .gltf renvoie les cameras.
description d'un maillage.
position et orientation d'un maillage dans la scene.
groupe de triangles d'un maillage. chaque groupe est associe a une matiere.
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().
ImageData read_image_data(const char *filename)
charge les donnees d'un fichier png. renvoie une image initialisee par defaut en cas d'echec.
int write_image_data(ImageData &image, const char *filename)
enregistre des donnees dans un fichier png.
Color Black()
utilitaire. renvoie une couleur noire.
ImageData image_data(SDL_Surface *surface)
converti une surface SDL en imageData, cf RWops pour charger les images deja en memoire.
Image flipY(const Image &image)
retourne l'image
Transform Inverse(const Transform &m)
renvoie l'inverse de la matrice.
Point Origin()
renvoie le point origine (0, 0, 0)
Point max(const Point &a, const Point &b)
renvoie la plus grande composante de chaque point. x, y, z= max(a.x, b.x), max(a.y,...
float degrees(const float rad)
conversion en degres.
float distance(const Point &a, const Point &b)
renvoie la distance etre 2 points.
Point min(const Point &a, const Point &b)
renvoie la plus petite composante de chaque point. x, y, z= min(a.x, b.x), min(a.y,...
Transform Perspective(const float fov, const float aspect, const float znear, const float zfar)
renvoie la matrice representant une transformation projection perspective.
Materials read_materials(const char *filename)
charge une description de matieres, utilise par read_mesh.
void normals(MeshData &data)
(re-) calcule les normales des sommets. utiliser avant les reindexations, cf indices() et vertices().
std::string pathname(const std::string &filename)
representation d'une couleur (rgba) transparente ou opaque.
float transmission
transmission, transparent ou pas (= 0)
int color_texture
indice de la texture ou -1. cf read_gltf_images() pour charger les textures dans le bon ordre....
float roughness
rugosite de la micro surface.
int metallic_roughness_texture
indice de la texture ou -1. les valeurs RGB representent les parametres du modele : B= metallic,...
int emission_texture
indice de la texture ou -1.
Color specular_color
modification de la reflexion speculaire des dielectriques ou pas (= 0)
Color emission
emission pour les sources de lumieres ou pas (= noir).
int normal_texture
indice de la texture ou -1.
float specular
modification de la reflexion speculaire des dielectriques ou pas (= 0)
int transmission_texture
indice de la texture ou -1.
float ior
indice de refraction des dielectriques ou pas (= 0)
float thickness
epaisseur des surfaces transparentes
int specular_color_texture
indice de la texture ou -1.
float metallic
metallic / dielectrique.
int specular_texture
indice de la texture ou -1.
int occlusion_texture
indice de la texture ou -1. //
void bounds(Point &pmin, Point &pmax) const
calcule les points extremes de la scene, utile pour regler un orbiter.
std::vector< GLTFMaterial > materials
matieres.
std::vector< GLTFLight > lights
lumieres.
std::vector< GLTFInstances > instances() const
regroupe les instances de chaque maillage.
std::vector< GLTFNode > nodes
noeuds / position et orientation des maillages dans la scene.
std::vector< GLTFMesh > meshes
ensemble de maillages.
std::vector< GLTFCamera > cameras
cameras.
stockage temporaire des donnees d'une image.
int diffuse_texture
indice de la texture de la couleur de base, ou -1.
float ns
concentration des reflets, exposant pour les reflets blinn-phong.
Color diffuse
couleur diffuse / de base.
Color specular
couleur du reflet.
int insert(const Material &material, const char *name)
ajoute une matiere.
int find(const char *name)
recherche une matiere avec son nom. renvoie son indice dans materials, ou -1.
int insert_texture(const char *filename)
ajoute une texture / nom du fichier.
int count() const
nombre de matieres.
representation d'un point 3d.
representation d'un vecteur 3d.
vecteur generique, utilitaire.
vecteur generique, utilitaire.
vecteur generique 4d, ou 3d homogene, utilitaire.
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...