27 Ray(
const Point& _o,
const Vector& _d ) : o(_o), d(_d), tmax(FLT_MAX) {}
28 Ray(
const Point& _o,
const Vector& _d,
const float _tmax ) : o(_o), d(_d), tmax(_tmax) {}
42 Hit( ) : t(FLT_MAX), u(), v(), instance_id(-1), mesh_id(-1), primitive_id(-1), triangle_id(-1) {}
43 Hit(
const Ray& ray ) : t(ray.tmax), u(), v(), instance_id(-1), mesh_id(-1), primitive_id(-1), triangle_id(-1) {}
45 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),
46 instance_id(-1), mesh_id(_mesh_id), primitive_id(_primitive_id), triangle_id(_id) {}
48 operator bool ( ) {
return (triangle_id != -1); }
56 BBoxHit() : tmin(FLT_MAX), tmax(-FLT_MAX) {}
57 BBoxHit(
const float _tmin,
const float _tmax ) : tmin(_tmin), tmax(_tmax) {}
59 operator bool( )
const {
return tmin <= tmax; }
68 BBox( ) : pmin(), pmax() {}
70 BBox(
const Point& p ) : pmin(p), pmax(p) {}
71 BBox(
const BBox& box ) : pmin(box.pmin), pmax(box.pmax) {}
72 BBox(
const BBox& a,
const BBox& b ) : pmin(
min(a.pmin, b.pmin)), pmax(
max(a.pmax, b.pmax)) {}
74 BBox& insert(
const Point& p ) { pmin=
min(pmin, p); pmax=
max(pmax, p);
return *
this; }
75 BBox& insert(
const BBox& box ) { pmin=
min(pmin, box.pmin); pmax=
max(pmax, box.pmax);
return *
this; }
77 float centroid(
const int axis )
const {
return (pmin(axis) + pmax(axis)) / 2; }
78 Point centroid( )
const {
return (pmin + pmax) / 2; }
80 BBoxHit intersect(
const Ray& ray,
const Vector& invd,
const float htmax )
const
84 if(ray.d.x < 0) std::swap(rmin.x, rmax.x);
85 if(ray.d.y < 0) std::swap(rmin.y, rmax.y);
86 if(ray.d.z < 0) std::swap(rmin.z, rmax.z);
87 Vector dmin= (rmin - ray.o) * invd;
88 Vector dmax= (rmax - ray.o) * invd;
104 bool internal( )
const {
return right > 0; }
105 int internal_left( )
const { assert(
internal());
return left; }
106 int internal_right( )
const { assert(
internal());
return right; }
108 bool leaf( )
const {
return right < 0; }
109 int leaf_begin( )
const { assert(leaf());
return -left; }
110 int leaf_end( )
const { assert(leaf());
return -right; }
117 assert(node.internal());
131 template <
typename T >
135 int build(
const std::vector<T>& _primitives )
137 primitives= _primitives;
139 nodes.reserve(primitives.size());
142 root= build(0, primitives.size());
147 Hit intersect(
const Ray& ray,
const float htmax )
const
151 Vector invd=
Vector(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z);
152 intersect(root, ray, invd, hit);
157 Hit intersect(
const Ray& ray )
const {
return intersect(ray, ray.tmax); }
160 std::vector<Node> nodes;
161 std::vector<T> primitives;
164 int build(
const int begin,
const int end )
169 int index= nodes.size();
178 if(d.x > d.y && d.x > d.z)
186 float cut= cbounds.centroid(axis);
189 T *pm= std::partition(primitives.data() +
begin, primitives.data() +
end,
190 [axis, cut](
const T& primitive )
192 return primitive.bounds().centroid(axis) < cut;
205 int left= build(
begin, m);
208 int right= build(m,
end);
211 int index= nodes.size();
221 bbox.insert(primitives[i].bounds());
229 BBox bbox= primitives[
begin].bounds().centroid();
231 bbox.insert(primitives[i].bounds().centroid());
237 void intersect(
const int index,
const Ray& ray,
const Vector& invd,
Hit& hit )
const
239 const Node& node= nodes[index];
240 if(node.bounds.intersect(ray, invd, hit.t))
244 for(
int i= node.leaf_begin(); i < node.leaf_end(); i++)
245 if(
Hit h= primitives[i].intersect(ray, hit.t))
250 intersect(node.internal_left(), ray, invd, hit);
251 intersect(node.internal_right(), ray, invd, hit);
267 Triangle(
const vec3& a,
const vec3& b,
const vec3&
c,
const int _mesh_id,
const int _primitive_id,
const int _id ) :
269 mesh_id(_mesh_id), primitive_id(_primitive_id), triangle_id(_id) {}
278 Hit intersect(
const Ray &ray,
const float htmax )
const
281 float det=
dot(e1, pvec);
283 float inv_det= 1 / det;
286 float u=
dot(tvec, pvec) * inv_det;
287 if(u < 0 || u > 1)
return Hit();
290 float v=
dot(ray.d, qvec) * inv_det;
291 if(v < 0 || u + v > 1)
return Hit();
293 float t=
dot(e2, qvec) * inv_det;
294 if(t < 0 || t > htmax)
return Hit();
296 return Hit(t, u, v, mesh_id, primitive_id, triangle_id);
302 return box.insert(p+e1).insert(p+e2);
319 object_transform(
Inverse(model)), world_bounds(transform(
bounds, model)),
326 Hit intersect(
const Ray &ray,
const float htmax )
const
329 Ray object_ray(object_transform(ray.o), object_transform(ray.d), htmax);
332 Hit hit= object_bvh->intersect(object_ray, htmax);
335 hit.instance_id= instance_id;
345 for(
unsigned i= 1; i < 8; i++)
349 if(i & 1) p.x= bbox.pmax.x;
350 if(i & 2) p.y= bbox.pmax.y;
351 if(i & 4) p.z= bbox.pmax.z;
366 std::uniform_real_distribution<float> u01;
367 std::default_random_engine rng;
369 Sampler(
const unsigned _seed ) : u01(), rng(_seed) {}
370 void seed(
const unsigned _seed ) { rng= std::default_random_engine(_seed); }
372 float sample( ) {
return u01(rng); }
374 int sample_range(
const int n ) {
return int(sample() * n); }
378 int main(
int argc,
char **argv )
380 const char *mesh_filename=
"data/robot.gltf";
381 const char *orbiter_filename=
nullptr;
383 if(argc > 1) mesh_filename= argv[1];
384 if(argc > 2) orbiter_filename= argv[2];
389 std::vector<BVH *> bvhs(scene.
meshes.size());
394 #pragma omp parallel for
395 for(
unsigned mesh_id= 0; mesh_id < scene.
meshes.size(); mesh_id++)
400 std::vector<Triangle> triangles;
401 for(
unsigned primitive_id= 0; primitive_id < mesh.
primitives.size(); primitive_id++)
405 for(
unsigned i= 0; i +2 < primitives.indices.size(); i+= 3)
408 vec3 a= primitives.positions[primitives.indices[i]];
409 vec3 b= primitives.positions[primitives.indices[i+1]];
410 vec3 c= primitives.positions[primitives.indices[i+2]];
411 triangles.push_back(
Triangle(a, b, c, mesh_id, primitive_id, i/3) );
417 bvh->build(triangles);
428 std::vector<Instance> instances;
429 for(
unsigned node_id= 0; node_id < scene.
nodes.size(); node_id++)
437 top_bvh.build(instances);
438 printf(
"done. %d instances\n",
int(instances.size()));
448 int height= width / scene.
cameras[0].aspect;
449 Image image(width, height);
458 #pragma omp parallel for
459 for(
int y= 0; y < image.height(); y++)
460 for(
int x= 0; x < image.width(); x++)
468 if(
Hit hit= top_bvh.intersect(ray))
470 assert(hit.instance_id != -1);
471 assert(hit.mesh_id != -1);
472 assert(hit.primitive_id != -1);
477 unsigned a= primitives.indices[3*hit.triangle_id];
478 unsigned b= primitives.indices[3*hit.triangle_id+1];
479 unsigned c= primitives.indices[3*hit.triangle_id+2];
509 image(x, y)=
Color(diffuse, 1);
representation d'une image.
GLenum primitives() const
renvoie le type de primitives.
int mesh_index
indice du maillage.
int material_index
indice de la matiere des primitives.
GLTFScene read_gltf_scene(const char *filename)
charge un fichier .gltf et construit une scene statique, sans animation.
Transform model
transformation model pour dessiner le maillage.
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 begin(Widgets &w)
debut de la description des elements de l'interface graphique.
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().
void end(Widgets &w)
termine la description des elements de l'interface graphique.
Color Yellow()
utilitaire. renvoie une couleur jaune.
int write_image(const Image &image, const char *filename)
enregistre une image dans un fichier png.
Transform Inverse(const Transform &m)
renvoie l'inverse de la matrice.
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,...
Transform Viewport(const float width, const float height)
renvoie la matrice representant une transformation viewport.
Transform Identity()
construit la transformation identite.
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,...
float dot(const Vector &u, const Vector &v)
renvoie le produit scalaire de 2 vecteurs.
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
void bounds(const MeshData &data, Point &pmin, Point &pmax)
renvoie l'englobant.
intersection avec une boite / un englobant.
bvh parametre par le type des primitives, cf triangle et instance...
representation d'une couleur (rgba) transparente ou opaque.
std::vector< GLTFMaterial > materials
matieres.
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.
intersection avec un triangle.
instance pour le bvh, cf fonctions bounds() et intersect().
construction de l'arbre / BVH.
representation d'un point 3d.
generation de nombres aleatoires entre 0 et 1.
triangle pour le bvh, cf fonction bounds() et intersect().
representation d'un vecteur 3d.
vecteur generique, utilitaire.
Node make_leaf(const BBox &bounds, const int begin, const int end)
creation d'une feuille.
Node make_node(const BBox &bounds, const int left, const int right)
creation d'un noeud interne.