gKit3
Loading...
Searching...
No Matches
Classes | Functions
utilitaires pour manipuler des objets 3d

Classes

struct  MeshIOGroup
 
struct  MeshIOData
 

Functions

bool read_positions (const char *filename, std::vector< Point > &positions)
 
bool read_indexed_positions (const char *filename, std::vector< Point > &positions, std::vector< unsigned > &indices)
 
bool read_materials (const char *filename, Materials &materials, std::vector< int > &indices)
 
bool read_images (const Materials &materials, std::vector< Image > &images)
 
bool read_meshio_data (const char *filename, MeshIOData &data)
 
bool read_images (const MeshIOData &data, std::vector< Image > &images)
 

Detailed Description


Class Documentation

◆ MeshIOGroup

struct MeshIOGroup

Definition at line 160 of file mesh_io.h.

Class Members
int id
unsigned first
unsigned count

Function Documentation

◆ read_positions()

bool read_positions ( const char *  filename,
std::vector< Point > &  positions 
)

charge les positions des sommets des triangles d'un objet. format .obj / wavefront. un triangle est represente par 3 positions successives.

exemple : charger un fichier .obj et parcourir tous les triangles

std::vector<Point> positions;
if(!read_positions("data/robot.obj", positions))
return "erreur";
// parcours les triangles
for(unsigned i= 0; i +2 < positions.size(); i+= 3)
{
// triangle abc
Point a= positions[ i];
Point b= positions[ i +1 ];
Point c= positions[ i +2 ];
// par exemple, calcule la normale du triangle
Vector n= normalize( cross( Vector(a, b), Vector(a, c) ) );
...
}
Vector normalize(const Vector &v)
renvoie un vecteur unitaire / longueur == 1.
Definition vec.cpp:133
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
Definition vec.cpp:139
bool read_positions(const char *filename, std::vector< Point > &positions)
Definition mesh_io.cpp:12
representation d'un point 3d.
Definition vec.h:21
representation d'un vecteur 3d.
Definition vec.h:58

on peut facilement recuperer les sommets du triangle numero id :

std::vector<Point> positions;
if(!read_positions("data/robot.obj", positions))
return "erreur";
int id= ... ;
Point a= positions[ 3*id ];
Point b= positions[ 3*id +1 ];
Point c= positions[ 3*id +2 ];

Definition at line 12 of file mesh_io.cpp.

13{
14 positions.clear();
15
16 FILE *in= fopen(filename, "rt");
17 if(!in)
18 {
19 printf("[error] loading mesh '%s'...\n", filename);
20 return false;
21 }
22
23 printf("loading mesh '%s'...\n", filename);
24
25 std::vector<Point> wpositions;
26 std::vector<int> wp;
27
28 char line_buffer[1024];
29 bool error= true;
30 for(;;)
31 {
32 // charge une ligne du fichier
33 if(!fgets(line_buffer, sizeof(line_buffer), in))
34 {
35 error= false; // fin du fichier, pas d'erreur detectee
36 break;
37 }
38
39 // force la fin de la ligne, au cas ou
40 line_buffer[sizeof(line_buffer) -1]= 0;
41
42 // saute les espaces en debut de ligne
43 char *line= line_buffer;
44 while(*line && isspace(*line))
45 line++;
46
47 if(line[0] == 'v')
48 {
49 float x, y, z;
50 if(line[1] == ' ') // position x y z
51 {
52 if(sscanf(line, "v %f %f %f", &x, &y, &z) != 3)
53 break;
54 wpositions.push_back( Point(x, y, z) );
55 }
56 }
57
58 else if(line[0] == 'f') // triangle a b c, les sommets sont numerotes a partir de 1 ou de la fin du tableau (< 0)
59 {
60 wp.clear();
61
62 int next= 0;
63 for(line= line +1; ; line= line + next)
64 {
65 wp.push_back(0);
66
67 // analyse les attributs du sommet : p/t/n ou p//n ou p/t ou p...
68 next= 0;
69 int wt= 0;
70 int wn= 0;
71 if(sscanf(line, " %d/%d/%d %n", &wp.back(), &wt, &wn, &next) == 3)
72 continue;
73 else if(sscanf(line, " %d/%d %n", &wp.back(), &wt, &next) == 2)
74 continue;
75 else if(sscanf(line, " %d//%d %n", &wp.back(), &wn, &next) == 2)
76 continue;
77 else if(sscanf(line, " %d %n", &wp.back(), &next) == 1)
78 continue;
79 else if(next == 0) // fin de ligne
80 break;
81 }
82
83 // triangule la face
84 for(unsigned v= 2; v +1 < wp.size(); v++)
85 {
86 unsigned idv[3]= { 0, v -1, v };
87 for(unsigned i= 0; i < 3; i++)
88 {
89 unsigned k= idv[i];
90 int p= (wp[k] < 0) ? int(wpositions.size()) + wp[k] : wp[k] -1;
91 if(p < 0) break; // error
92
93 // et duplique les positions...
94 assert(p < int(wpositions.size()));
95 positions.push_back(wpositions[p]);
96 }
97 }
98 }
99 }
100
101 fclose(in);
102
103 if(error)
104 printf("[error] loading mesh '%s'...\n%s\n\n", filename, line_buffer);
105 else
106 printf("mesh '%s': %d positions\n", filename, int(positions.size()));
107
108 return !error;
109}

◆ read_indexed_positions()

bool read_indexed_positions ( const char *  filename,
std::vector< Point > &  positions,
std::vector< unsigned > &  indices 
)

version indexee de read_positions(). un triangle est represente par 3 indices successifs dans indices[].

exemple : charger un fichier .obj et parcourir tous les triangles

std::vector<int> indices;
std::vector<Point> positions;
if(!read_indexed_positions("data/robot.obj", positions, indices))
return "erreur";
// parcours les triangles indexes
for(unsigned i= 0; i +2 < indices.size(); i+= 3)
{
// triangle abc
Point a= positions[ indices[i] ];
Point b= positions[ indices[i+1] ];
Point c= positions[ indices[i+2] ];
// par exemple, calcule la normale du triangle
Vector n= normalize( cross( Vector(a, b), Vector(a, c) ) );
...
}
bool read_indexed_positions(const char *filename, std::vector< Point > &positions, std::vector< unsigned > &indices)
Definition mesh_io.cpp:112

on peut recuperer directement les sommets du triangle numero id :

std::vector<int> indices;
std::vector<Point> positions;
if(!read_indexed_positions("data/robot.obj", positions, indices))
return "erreur";
int id= ... ;
Point a= positions[ indices[ 3*id ] ];
Point b= positions[ indices[ 3*id +1 ] ];
Point c= positions[ indices[ 3*id +2 ] ];

Definition at line 112 of file mesh_io.cpp.

113{
114 positions.clear();
115 indices.clear();
116
117 FILE *in= fopen(filename, "rt");
118 if(!in)
119 {
120 printf("[error] loading indexed mesh '%s'...\n", filename);
121 return false;
122 }
123
124 printf("loading indexed mesh '%s'...\n", filename);
125
126 std::vector<int> wp;
127
128 char line_buffer[1024];
129 bool error= true;
130 for(;;)
131 {
132 // charge une ligne du fichier
133 if(!fgets(line_buffer, sizeof(line_buffer), in))
134 {
135 error= false; // fin du fichier, pas d'erreur detectee
136 break;
137 }
138
139 // force la fin de la ligne, au cas ou
140 line_buffer[sizeof(line_buffer) -1]= 0;
141
142 // saute les espaces en debut de ligne
143 char *line= line_buffer;
144 while(*line && isspace(*line))
145 line++;
146
147 if(line[0] == 'v')
148 {
149 float x, y, z;
150 if(line[1] == ' ') // position x y z
151 {
152 if(sscanf(line, "v %f %f %f", &x, &y, &z) != 3)
153 break;
154 positions.push_back( Point(x, y, z) );
155 }
156 }
157
158 else if(line[0] == 'f') // triangle a b c, les sommets sont numerotes a partir de 1 ou de la fin du tableau (< 0)
159 {
160 wp.clear();
161
162 int next= 0;
163 for(line= line +1; ; line= line + next)
164 {
165 wp.push_back(0);
166
167 // analyse les attributs du sommet : p/t/n ou p//n ou p/t ou p...
168 next= 0;
169 int wt= 0;
170 int wn= 0;
171 if(sscanf(line, " %d/%d/%d %n", &wp.back(), &wt, &wn, &next) == 3)
172 continue;
173 else if(sscanf(line, " %d/%d %n", &wp.back(), &wt, &next) == 2)
174 continue;
175 else if(sscanf(line, " %d//%d %n", &wp.back(), &wn, &next) == 2)
176 continue;
177 else if(sscanf(line, " %d %n", &wp.back(), &next) == 1)
178 continue;
179 else if(next == 0) // fin de ligne
180 break;
181 }
182
183 // triangule la face
184 for(unsigned v= 2; v +1 < wp.size(); v++)
185 {
186 unsigned idv[3]= { 0, v -1, v };
187 for(unsigned i= 0; i < 3; i++)
188 {
189 unsigned k= idv[i];
190 int p= (wp[k] < 0) ? int(positions.size()) + wp[k] : wp[k] -1;
191 if(p < 0) break; // error
192
193 assert(p < int(positions.size()));
194 indices.push_back(p);
195 }
196 }
197 }
198 }
199
200 fclose(in);
201
202 if(error)
203 printf("[error] loading indexed mesh '%s'...\n%s\n\n", filename, line_buffer);
204 else
205 printf("indexed mesh '%s': %d positions, %d indices\n", filename, int(positions.size()), int(indices.size()));
206
207 return !error;
208}

◆ read_materials()

bool read_materials ( const char *  filename,
Materials materials,
std::vector< int > &  indices 
)

charge les matieres associees aux triangles d'un fichier .obj / wavefront. renvoie l'ensemble de matieres et l'indice de la matiere pour chaque triangle.

exemple :

#include "materials.h"
Materials materials;
std::vector<int> material_indices; // indices des matieres
if(!read_materials("data/robot.obj", materials, material_indices)) // !! oui c'est bien le fichier .obj !!
return "erreur";
// recuperer la matiere du triangle numero id :
int material_id= material_indices[ id ];
Material& material= materials( material_id );
bool read_materials(const char *filename, Materials &materials, std::vector< int > &indices)
Definition mesh_io.cpp:302

exemple plus complet, charge un objet, ses matieres et recupere la couleur de chaque triangle

#include "mesh_io.h"
#include "materials.h"
std::vector<Point> positions;
if(!read_positions("data/robot.obj", positions))
return "erreur";
Materials materials;
std::vector<int> material_indices; // indices des matieres
if(!read_materials(data/robot.obj", materials, material_indices))
return "erreur";
// recuperer les sommets du triangle numero id
int id= ... ;
Point a= positions[ 3*id ];
Point b= positions[ 3*id +1 ];
Point c= positions[ 3*id +2 ];
// recuperer la matiere du triangle numero id
int material_id= material_indices[ id ];
Material& material= materials( material_id );
// recuperer la couleur (de la matiere) du triangle
Color color= material.diffuse;

Definition at line 302 of file mesh_io.cpp.

303{
304 indices.clear();
305
306 FILE *in= fopen(filename, "rt");
307 if(!in)
308 {
309 printf("[error] loading materials '%s'...\n", filename);
310 return false;
311 }
312
313 printf("loading materials '%s'...\n", filename);
314
315 std::vector<int> wp;
316 int material_id= -1;
317
318 char tmp[1024];
319 char line_buffer[1024];
320 bool error= true;
321 for(;;)
322 {
323 // charge une ligne du fichier
324 if(!fgets(line_buffer, sizeof(line_buffer), in))
325 {
326 error= false; // fin du fichier, pas d'erreur detectee
327 break;
328 }
329
330 // force la fin de la ligne, au cas ou
331 line_buffer[sizeof(line_buffer) -1]= 0;
332
333 // saute les espaces en debut de ligne
334 char *line= line_buffer;
335 while(*line && isspace(*line))
336 line++;
337
338 if(line[0] == 'f') // triangle a b c
339 {
340 wp.clear();
341
342 int next= 0;
343 for(line= line +1; ; line= line + next)
344 {
345 wp.push_back(0);
346
347 // analyse les attributs du sommet : p/t/n ou p//n ou p/t ou p...
348 next= 0;
349 int wt= 0;
350 int wn= 0;
351 if(sscanf(line, " %d/%d/%d %n", &wp.back(), &wt, &wn, &next) == 3)
352 continue;
353 else if(sscanf(line, " %d/%d %n", &wp.back(), &wt, &next) == 2)
354 continue;
355 else if(sscanf(line, " %d//%d %n", &wp.back(), &wn, &next) == 2)
356 continue;
357 else if(sscanf(line, " %d %n", &wp.back(), &next) == 1)
358 continue;
359 else if(next == 0) // fin de ligne
360 break;
361 }
362
363 // force une matiere par defaut, si necessaire
364 if(material_id == -1)
365 material_id= materials.default_material_index();
366
367 // triangule la face
368 for(unsigned v= 2; v +1 < wp.size(); v++)
369 // indice de la matiere de chaque triangle
370 indices.push_back(material_id);
371 }
372 else if(line[0] == 'm')
373 {
374 if(sscanf(line, "mtllib %[^\r\n]", tmp) == 1)
375 {
376 std::string materials_filename;
377 if(tmp[0] != '/' && tmp[1] != ':') // windows c:\ pour les chemins complets...
378 materials_filename= normalize_filename(pathname(filename) + tmp);
379 else
380 materials_filename= std::string(tmp);
381
382 // charge les matieres
383 if(!read_materials_mtl( materials_filename.c_str(), materials ))
384 break;
385 }
386 }
387
388 else if(line[0] == 'u')
389 {
390 if(sscanf(line, "usemtl %[^\r\n]", tmp) == 1)
391 material_id= materials.find(tmp);
392 }
393 }
394
395 fclose(in);
396
397 if(error)
398 printf("[error] loading materials '%s'...\n%s\n\n", filename, line_buffer);
399
400 return !error;
401}
int find(const char *name)
recherche une matiere avec son nom. renvoie son indice dans materials, ou -1.
Definition materials.h:89
int default_material_index()
indice de la matiere par defaut dans le tableau materials.
Definition materials.h:139

◆ read_images() [1/2]

bool read_images ( const Materials materials,
std::vector< Image > &  images 
)

charge les images / textures referencees par les matieres d'un objet.

exemple :

#include "mesh_io.h"
#include "materials.h"
std::vector<Point> positions;
if(!read_positions("data/robot.obj", positions))
return "erreur";
Materials materials;
std::vector<int> material_indices; // indices des matieres
if(!read_materials("data/robot.obj", materials, material_indices)) // !! oui c'est bien le fichier .obj !!
return "erreur";
std::vector<Image> images;
if(!read_images(materials, images))
return "erreur";
bool read_images(const Materials &materials, std::vector< Image > &images)
Definition mesh_io.cpp:714

Definition at line 714 of file mesh_io.cpp.

715{
716 int n= materials.filename_count();
717 if(n == 0) // pas de textures
718 return true;
719
720 images.resize(n);
721
722#pragma omp parallel for
723 for(int i= 0; i < n; i++)
724 {
725 //~ printf("loading '%s'...\n", materials.filename(i));
726 images[i]= read_image(materials.filename(i));
727 }
728
729 return true;
730}
Image read_image(const char *filename, const bool flipY)
charge une image .bmp .tga .jpeg .png ou .hdr
Definition image_io.cpp:94
int filename_count() const
renvoie le nombre de noms de fichiers de textures.
Definition materials.h:148
const char * filename(const int id) const
renvoie le nom de fichier d'une texture.
Definition materials.h:150

◆ read_meshio_data()

bool read_meshio_data ( const char *  filename,
MeshIOData data 
)

charge tous les attributs et les matieres. en une seule fois.

exemple :

MeshIOData data= read_meshio_data( "data/robot.obj" );
if(data.positions.empty())
return "erreur";
// recuperer les sommets du triangle d'indice id :
// triangle abc
Point a= data.positions[ data.indices[3*id] ];
Point b= data.positions[ data.indices[3*id+1] ];
Point c= data.positions[ data.indices[3*id+2] ];
// et recuperer sa matiere / couleur
int material_id= data.material_indices[ id ];
Material& material= data.materials( material_id );
// recuperer la couleur (de la matiere) du triangle
Color color= material.diffuse;
...
bool read_meshio_data(const char *filename, MeshIOData &data)
Definition mesh_io.cpp:505
representation d'une couleur (rgba) transparente ou opaque.
Definition color.h:14
Color diffuse
couleur diffuse / de base.
Definition materials.h:17

utiliser read_meshio_data() est equivalent a :

const char *filename= "... .obj";
std::vector<Point> positions;
std::vector<int> indices;
read_indexed_positions( filename, positions, indices );
Materials materials;
std::vector<int> material_indices;
read_materials( filename, materials, materials_indices );
std::vector<Image> images;
read_images( filename, images );
mais toutes les infos sont chargees en seule fois, et sont stockees dans une seule structure, cf MeshIOData, plus simple a manipuler.

Definition at line 505 of file mesh_io.cpp.

506{
507 FILE *in= fopen(filename, "rt");
508 if(!in)
509 {
510 printf("[error] loading indexed mesh '%s'...\n", filename);
511 return false;
512 }
513
514 printf("loading indexed mesh '%s'...\n", filename);
515
516 std::vector<Point> wpositions;
517 std::vector<Point> wtexcoords;
518 std::vector<Vector> wnormals;
519
520 std::vector<int> wp;
521 std::vector<int> wt;
522 std::vector<int> wn;
523
524 std::map<vertex, unsigned> remap;
525 int material_id= -1;
526 int object_id= -1;
527
528 char tmp[1024];
529 char line_buffer[1024];
530 bool error= true;
531 for(;;)
532 {
533 // charge une ligne du fichier
534 if(!fgets(line_buffer, sizeof(line_buffer), in))
535 {
536 error= false; // fin du fichier, pas d'erreur detectee
537 break;
538 }
539
540 // force la fin de la ligne, au cas ou
541 line_buffer[sizeof(line_buffer) -1]= 0;
542
543 // saute les espaces en debut de ligne
544 char *line= line_buffer;
545 while(*line && isspace(*line))
546 line++;
547
548 if(line[0] == 'v')
549 {
550 float x, y, z;
551 if(line[1] == ' ') // position x y z
552 {
553 if(sscanf(line, "v %f %f %f", &x, &y, &z) != 3)
554 break;
555 wpositions.push_back( Point(x, y, z) );
556 }
557 else if(line[1] == 'n') // normal x y z
558 {
559 if(sscanf(line, "vn %f %f %f", &x, &y, &z) != 3)
560 break;
561 wnormals.push_back( Vector(x, y, z) );
562 }
563 else if(line[1] == 't') // texcoord x y
564 {
565 if(sscanf(line, "vt %f %f", &x, &y) != 2)
566 break;
567 wtexcoords.push_back( Point(x, y, 0) );
568 }
569 }
570 else if(line[0] == 'f') // triangle a b c, les sommets sont numerotes a partir de 1 ou de la fin du tableau (< 0)
571 {
572 wp.clear();
573 wt.clear();
574 wn.clear();
575
576 int next;
577 for(line= line +1; ; line= line + next)
578 {
579 wp.push_back(0);
580 wt.push_back(0);
581 wn.push_back(0); // 0: invalid index
582
583 // analyse les attributs du sommet : p/t/n ou p//n ou p/t ou p...
584 next= 0;
585 if(sscanf(line, " %d/%d/%d %n", &wp.back(), &wt.back(), &wn.back(), &next) == 3)
586 continue;
587 else if(sscanf(line, " %d/%d %n", &wp.back(), &wt.back(), &next) == 2)
588 continue;
589 else if(sscanf(line, " %d//%d %n", &wp.back(), &wn.back(), &next) == 2)
590 continue;
591 else if(sscanf(line, " %d %n", &wp.back(), &next) == 1)
592 continue;
593 else if(next == 0) // fin de ligne
594 break;
595 }
596
597 // force une matiere par defaut, si necessaire
598 if(material_id == -1)
599 material_id= data.materials.default_material_index();
600
601 if(object_id == -1)
602 {
603 object_id= data.find_object("default");
604 if(object_id == -1)
605 {
606 object_id= data.object_names.size();
607 data.object_names.push_back("default");
608 }
609 }
610
611 // triangule la face
612 for(unsigned v= 2; v +1 < wp.size(); v++)
613 {
614 data.material_indices.push_back(material_id);
615 data.object_indices.push_back(object_id);
616
617 unsigned idv[3]= { 0, v -1, v };
618 for(unsigned i= 0; i < 3; i++)
619 {
620 unsigned k= idv[i];
621 // indices des attributs du sommet
622 int p= (wp[k] < 0) ? int(wpositions.size()) + wp[k] : wp[k] -1;
623 int t= (wt[k] < 0) ? int(wtexcoords.size()) + wt[k] : wt[k] -1;
624 int n= (wn[k] < 0) ? int(wnormals.size()) + wn[k] : wn[k] -1;
625
626 if(p < 0) break; // error
627
628 // recherche / insere le sommet
629 auto found= remap.insert( std::make_pair(vertex(material_id, p, t, n), unsigned(remap.size())) );
630 if(found.second)
631 {
632 // pas trouve, copie les nouveaux attributs
633 if(t != -1) data.texcoords.push_back(wtexcoords[t]);
634 if(n != -1) data.normals.push_back(wnormals[n]);
635 data.positions.push_back(wpositions[p]);
636 }
637
638 // construit l'index buffer
639 assert(found.first->second < data.positions.size());
640 data.indices.push_back(found.first->second);
641 }
642 }
643 }
644
645 else if(line[0] == 'm')
646 {
647 if(sscanf(line, "mtllib %[^\r\n]", tmp) == 1)
648 {
649 std::string materials_filename;
650 if(tmp[0] != '/' && tmp[1] != ':') // windows c:\ pour les chemins complets...
651 materials_filename= normalize_filename(pathname(filename) + tmp);
652 else
653 materials_filename= std::string(tmp);
654
655 // charge les matieres, ou pas...
656 read_materials_mtl( materials_filename.c_str(), data.materials );
657 }
658 }
659
660 else if(line[0] == 'u')
661 {
662 if(sscanf(line, "usemtl %[^\r\n]", tmp) == 1)
663 material_id= data.materials.find(tmp);
664 }
665
666 else if(line[0] == 'o')
667 {
668 if(sscanf(line, "o %s", tmp) == 1)
669 {
670 object_id= data.find_object(tmp);
671 if(object_id == -1)
672 {
673 object_id= data.object_names.size();
674 data.object_names.push_back(tmp);
675 }
676
677 //~ printf("object '%s': %d\n", tmp, object_id);
678 }
679 }
680 #if 0
681 else if(line[0] == 'g')
682 {
683 // ne lit que le 1er groupe
684 if(sscanf(line, "g %s", tmp) == 1)
685 {
686 object_id= data.find_object(tmp);
687 if(object_id == -1)
688 {
689 object_id= data.object_names.size();
690 data.object_names.push_back(tmp);
691 }
692
693 printf("object '%s': %d\n", tmp, object_id);
694 }
695 }
696 #endif
697 }
698
699 fclose(in);
700
701 if(error)
702 {
703 printf("[error] loading indexed mesh '%s'...\n%s\n\n", filename, line_buffer);
704 return false;
705 }
706
707 printf(" %d indices, %d positions %d texcoords %d normals\n",
708 int(data.indices.size()), int(data.positions.size()), int(data.texcoords.size()), int(data.normals.size()));
709 printf(" %d materials, %d textures\n", data.materials.count(), data.materials.filename_count());
710 return true;
711}
int count() const
nombre de matieres.
Definition materials.h:103

◆ read_images() [2/2]

bool read_images ( const MeshIOData data,
std::vector< Image > &  images 
)

Definition at line 732 of file mesh_io.cpp.

733{
734 return read_images(data.materials, images);
735}