gKit2 light
tuto_ray_gltf.cpp
Go to the documentation of this file.
1 
3 
4 #include <vector>
5 #include <cfloat>
6 #include <chrono>
7 
8 #include "gltf.h"
9 
10 
11 // rayon
12 struct Ray
13 {
14  Point o; // origine
15  float pad;
16  Vector d; // direction
17  float tmax; // tmax= 1 ou \inf, le rayon est un segment ou une demi droite infinie
18 
19  Ray( const Point& _o, const Point& _e ) : o(_o), d(Vector(_o, _e)), tmax(1) {} // segment, t entre 0 et 1
20  Ray( const Point& _o, const Vector& _d ) : o(_o), d(_d), tmax(FLT_MAX) {} // demi droite, t entre 0 et \inf
21  Ray( const Point& _o, const Vector& _d, const float _tmax ) : o(_o), d(_d), tmax(_tmax) {} // explicite
22 };
23 
24 // intersection / gltf
25 struct Hit
26 {
27  float t; // p(t)= o + td, position du point d'intersection sur le rayon
28  float u, v; // p(u, v), position du point d'intersection sur le triangle
29  int instance_id; // indice de l'instance
30  int mesh_id; // indexation globale du triangle dans la scene gltf
31  int primitive_id;
32  int triangle_id;
33  int pad;
34 
35  Hit( ) : t(FLT_MAX), u(), v(), instance_id(-1), mesh_id(-1), primitive_id(-1), triangle_id(-1) {}
36  Hit( const Ray& ray ) : t(ray.tmax), u(), v(), instance_id(-1), mesh_id(-1), primitive_id(-1), triangle_id(-1) {}
37 
38  Hit( const float _t, const float _u, const float _v, const int _mesh_id, const int _primitive_id, const int _id ) : t(_t), u(_u), v(_v),
39  instance_id(-1), mesh_id(_mesh_id), primitive_id(_primitive_id), triangle_id(_id) {}
40 
41  operator bool ( ) { return (triangle_id != -1); } // renvoie vrai si l'intersection est definie / existe
42 };
43 
44 
45 // triangle / gltf
46 struct Triangle
47 {
48  Point p; // sommet a du triangle
49  Vector e1, e2; // aretes ab, ac du triangle
50  int mesh_id;
51  int primitive_id;
52  int triangle_id;
53 
54  Triangle( const vec3& a, const vec3& b, const vec3& c, const int _mesh_id, const int _primitive_id, const int _id ) :
55  p(a), e1(Vector(a, b)), e2(Vector(a, c)),
56  mesh_id(_mesh_id), primitive_id(_primitive_id), triangle_id(_id) {}
57 
58  /* calcule l'intersection ray/triangle
59  cf "fast, minimum storage ray-triangle intersection"
60 
61  renvoie faux s'il n'y a pas d'intersection valide (une intersection peut exister mais peut ne pas se trouver dans l'intervalle [0 tmax] du rayon.)
62  renvoie vrai + les coordonnees barycentriques (u, v) du point d'intersection + sa position le long du rayon (t).
63  convention barycentrique : p(u, v)= (1 - u - v) * a + u * b + v * c
64  */
65  Hit intersect( const Ray &ray, const float htmax ) const
66  {
67  Vector pvec= cross(ray.d, e2);
68  float det= dot(e1, pvec);
69 
70  float inv_det= 1 / det;
71  Vector tvec(p, ray.o);
72 
73  float u= dot(tvec, pvec) * inv_det;
74  if(u < 0 || u > 1) return Hit();
75 
76  Vector qvec= cross(tvec, e1);
77  float v= dot(ray.d, qvec) * inv_det;
78  if(v < 0 || u + v > 1) return Hit();
79 
80  float t= dot(e2, qvec) * inv_det;
81  if(t < 0 || t > htmax) return Hit();
82 
83  return Hit(t, u, v, mesh_id, primitive_id, triangle_id);
84  }
85 };
86 
87 
88 int main( const int argc, const char **argv )
89 {
90  const char *filename= "cornell.gltf";
91  if(argc > 1)
92  filename= argv[1];
93 
94  // charge la scene
95  GLTFScene scene= read_gltf_scene(filename);
96 
97  // recupere les triangles
98  std::vector<Triangle> triangles;
99  for(unsigned node_id= 0; node_id < scene.nodes.size(); node_id++)
100  {
101  const GLTFNode& node= scene.nodes[node_id];
102 
103  const Transform& model= node.model;
104  int mesh_id= node.mesh_index;
105 
106  const GLTFMesh& mesh= scene.meshes[mesh_id];
107  for(unsigned primitive_id= 0; primitive_id < mesh.primitives.size(); primitive_id++)
108  {
109  const GLTFPrimitives& primitives= mesh.primitives[primitive_id];
110  for(unsigned i= 0; i +2 < primitives.indices.size(); i+= 3)
111  {
112  // indice des sommets
113  int a= primitives.indices[i];
114  int b= primitives.indices[i+1];
115  int c= primitives.indices[i+2];
116 
117  // position des sommets
118  Point pa= primitives.positions[a];
119  Point pb= primitives.positions[b];
120  Point pc= primitives.positions[c];
121 
122  // transforme les sommets dans le repere de la scene
123  pa= model( pa );
124  pb= model( pb );
125  pc= model( pc );
126 
127  triangles.push_back( Triangle(pa, pb, pc, mesh_id, primitive_id, i/3) );
128  }
129  }
130  }
131  assert(triangles.size());
132 
133  // recupere les matrices de la camera gltf
134  assert(scene.cameras.size());
135  Transform view= scene.cameras[0].view;
136  Transform projection= scene.cameras[0].projection;
137 
138  // cree l'image en respectant les proportions largeur/hauteur de la camera gltf
139  int width= 1024;
140  int height= width / scene.cameras[0].aspect;
141  Image image(width, height);
142 
143  // transformations
144  Transform model= Identity();
145  Transform viewport= Viewport(image.width(), image.height());
146  Transform inv= Inverse(viewport * projection * view * model);
147 
148  // c'est parti, parcours tous les pixels de l'image
149  for(int y= 0; y < image.height(); y++)
150  for(int x= 0; x < image.width(); x++)
151  {
152  // generer le rayon
153  Point origine= inv(Point(x, y, 0));
154  Point extremite= inv(Point(x, y, 1));
155  Ray ray(origine, extremite);
156 
157  // calculer les intersections avec tous les triangles
158  Hit hit;
159  for(unsigned i= 0; i < triangles.size(); i++)
160  {
161  if(Hit h= triangles[i].intersect(ray, hit.t))
162  // ne conserve que l'intersection la plus proche de l'origine du rayon
163  // attention !! h.t <= hit.t !! sinon ca ne marche pas...
164  hit= h;
165  }
166 
167  if(hit)
168  // coordonnees barycentriques de l'intersection
169  image(x, y)= Color(1 - hit.u - hit.v, hit.u, hit.v);
170  }
171 
172  write_image(image, "render.png");
173  return 0;
174 }
representation d'une image.
Definition: image.h:21
GLenum primitives() const
renvoie le type de primitives.
Definition: mesh.h:336
scene glTF.
int mesh_index
indice du maillage.
Definition: gltf.h:131
GLTFScene read_gltf_scene(const char *filename)
charge un fichier .gltf et construit une scene statique, sans animation.
Definition: gltf.cpp:726
Transform model
transformation model pour dessiner le maillage.
Definition: gltf.h:130
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
int write_image(const Image &image, const char *filename)
enregistre une image dans un fichier png.
Definition: image_io.cpp:85
Transform Inverse(const Transform &m)
renvoie l'inverse de la matrice.
Definition: mat.cpp:197
Transform Viewport(const float width, const float height)
renvoie la matrice representant une transformation viewport.
Definition: mat.cpp:357
Transform Identity()
construit la transformation identite.
Definition: mat.cpp:187
float dot(const Vector &u, const Vector &v)
renvoie le produit scalaire de 2 vecteurs.
Definition: vec.cpp:137
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
Definition: vec.cpp:129
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:14
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
std::vector< GLTFCamera > cameras
cameras.
Definition: gltf.h:155
intersection avec un triangle.
Definition: tuto_bvh2.cpp:33
representation d'un point 3d.
Definition: vec.h:21
rayon.
Definition: tuto_bvh2.cpp:20
representation d'une transformation, une matrice 4x4, organisee par ligne / row major.
Definition: mat.h:21
vec3 c
positions
Definition: mesh.h:96
triangle pour le bvh, cf fonction bounds() et intersect().
Definition: tuto_bvh.cpp:84
representation d'un vecteur 3d.
Definition: vec.h:59
vecteur generique, utilitaire.
Definition: vec.h:146