charge un fichier .gltf et construit un mesh statique, sans animation.
15{
16 printf(
"loading glTF mesh '%s'...\n", filename);
17
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;
46 std::vector<vec4> colors;
47
49
50
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);
57 }
58 else if(data->images[i].buffer_view)
59 {
60
61
62
63
64
65
66
67
69
70
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
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
103
106
107 if(char *ext= strrchr(tmp, '.'))
108 strcpy(ext, "_flip.png");
109
110 printf(
"writing flipped texture '%s'...\n", tmp);
112
114 assert(data->images[i].uri == nullptr);
115 data->images[i].uri= strdup(tmp);
116 #endif
117 }
118 }
119 }
120
121
122 for(unsigned i= 0; i < data->materials_count; i++)
123 {
125
126
128 if(material->has_pbr_metallic_roughness)
129 {
131
132
133
134
135
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
142
143
144 m.diffuse= color * (1 - metallic) + metallic *
Black();
145 m.specular=
Color(0.04) * (1 - metallic) + color * metallic;
146
147
148 m.ns= 2 / (roughness * roughness * roughness * roughness) - 2;
149 if(m.ns < float(1.1))
151
152
153
154
155
156
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
178 for(unsigned node_id= 0; node_id < data->nodes_count; node_id++)
179 {
181 if(node->mesh== nullptr)
182
183 continue;
184
185
186 float model_matrix[16];
187 cgltf_node_transform_world(node, model_matrix);
188
192
193
195
196 for(unsigned primitive_id= 0; primitive_id < mesh->primitives_count; primitive_id++)
197 {
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
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
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
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
229 for(unsigned attribute_id= 0; attribute_id < primitives->attributes_count; attribute_id++)
230 {
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
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
254 for(unsigned i= 0; i < offset; i++)
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
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
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
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
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
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
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++)
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
327 Mesh mesh(GL_TRIANGLES);
328
329
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 {
340 if(has_colors) mesh.color(colors[i]);
341
342 mesh.vertex(positions[i]);
343 }
344
345
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
355
356 return mesh;
357}
representation d'un objet / maillage.
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().
Color Black()
utilitaire. renvoie une couleur noire.
Image flipY(const Image &image)
retourne l'image
int write_image_data(ImageData &image, const char *filename, const bool flipY)
enregistre des donnees dans un fichier png.
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...
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.
stockage temporaire des donnees d'une image.
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...