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) {}
39 Hit( ) : t(FLT_MAX), u(), v(), instance_id(-1), triangle_id(-1) {}
40 Hit(
const Ray& ray ) : t(ray.tmax), u(), v(), instance_id(-1), triangle_id(-1) {}
41 Hit(
const float _t,
const float _u,
const float _v,
const int _id ) : t(_t), u(_u), v(_v), instance_id(-1), triangle_id(_id) {}
43 operator bool ( ) {
return (triangle_id != -1); }
51 BBoxHit() : tmin(FLT_MAX), tmax(-FLT_MAX) {}
52 BBoxHit(
const float _tmin,
const float _tmax ) : tmin(_tmin), tmax(_tmax) {}
54 operator bool( )
const {
return tmin <= tmax; }
63 BBox( ) : pmin(), pmax() {}
65 BBox(
const Point& p ) : pmin(p), pmax(p) {}
66 BBox(
const BBox& box ) : pmin(box.pmin), pmax(box.pmax) {}
67 BBox(
const BBox& a,
const BBox& b ) : pmin(
min(a.pmin, b.pmin)), pmax(
max(a.pmax, b.pmax)) {}
69 BBox& insert(
const Point& p ) { pmin=
min(pmin, p); pmax=
max(pmax, p);
return *
this; }
70 BBox& insert(
const BBox& box ) { pmin=
min(pmin, box.pmin); pmax=
max(pmax, box.pmax);
return *
this; }
72 float centroid(
const int axis )
const {
return (pmin(axis) + pmax(axis)) / 2; }
73 Point centroid( )
const {
return (pmin + pmax) / 2; }
75 BBoxHit intersect(
const Ray& ray,
const Vector& invd,
const float htmax )
const
79 if(ray.d.x < 0) std::swap(rmin.x, rmax.x);
80 if(ray.d.y < 0) std::swap(rmin.y, rmax.y);
81 if(ray.d.z < 0) std::swap(rmin.z, rmax.z);
82 Vector dmin= (rmin - ray.o) * invd;
83 Vector dmax= (rmax - ray.o) * invd;
99 bool internal( )
const {
return right > 0; }
100 int internal_left( )
const { assert(
internal());
return left; }
101 int internal_right( )
const { assert(
internal());
return right; }
103 bool leaf( )
const {
return right < 0; }
104 int leaf_begin( )
const { assert(leaf());
return -left; }
105 int leaf_end( )
const { assert(leaf());
return -right; }
112 assert(node.internal());
126 template <
typename T >
130 int build(
const std::vector<T>& _primitives )
132 primitives= _primitives;
134 nodes.reserve(primitives.size());
137 root= build(0, primitives.size());
142 Hit intersect(
const Ray& ray,
const float htmax )
const
146 Vector invd=
Vector(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z);
147 intersect(root, ray, invd, hit);
152 Hit intersect(
const Ray& ray )
const {
return intersect(ray, ray.tmax); }
155 std::vector<Node> nodes;
156 std::vector<T> primitives;
159 int build(
const int begin,
const int end )
164 int index= nodes.size();
173 if(d.x > d.y && d.x > d.z)
181 float cut= cbounds.centroid(axis);
184 T *pm= std::partition(primitives.data() +
begin, primitives.data() +
end,
185 [axis, cut](
const T& primitive )
187 return primitive.bounds().centroid(axis) < cut;
200 int left= build(
begin, m);
203 int right= build(m,
end);
206 int index= nodes.size();
216 bbox.insert(primitives[i].bounds());
224 BBox bbox= primitives[
begin].bounds().centroid();
226 bbox.insert(primitives[i].bounds().centroid());
232 void intersect(
const int index,
const Ray& ray,
const Vector& invd,
Hit& hit )
const
234 const Node& node= nodes[index];
235 if(node.bounds.intersect(ray, invd, hit.t))
239 for(
int i= node.leaf_begin(); i < node.leaf_end(); i++)
240 if(
Hit h= primitives[i].intersect(ray, hit.t))
245 intersect(node.internal_left(), ray, invd, hit);
246 intersect(node.internal_right(), ray, invd, hit);
269 Hit intersect(
const Ray &ray,
const float htmax )
const
272 float det=
dot(e1, pvec);
274 float inv_det= 1 / det;
277 float u=
dot(tvec, pvec) * inv_det;
278 if(u < 0 || u > 1)
return Hit();
281 float v=
dot(ray.d, qvec) * inv_det;
282 if(v < 0 || u + v > 1)
return Hit();
284 float t=
dot(e2, qvec) * inv_det;
285 if(t < 0 || t > htmax)
return Hit();
287 return Hit(t, u, v,
id);
293 return box.insert(p+e1).insert(p+e2);
310 object_transform(
Inverse(model)), world_bounds(transform(
bounds, model)),
317 Hit intersect(
const Ray &ray,
const float htmax )
const
320 Ray object_ray(object_transform(ray.o), object_transform(ray.d), htmax);
323 Hit hit= object_bvh->intersect(object_ray, htmax);
326 hit.instance_id= instance_id;
336 for(
unsigned i= 1; i < 8; i++)
340 if(i & 1) p.x= bbox.pmax.x;
341 if(i & 2) p.y= bbox.pmax.y;
342 if(i & 4) p.z= bbox.pmax.z;
355 int main(
int argc,
char **argv )
357 const char *mesh_filename=
"data/robot.obj";
358 const char *orbiter_filename=
nullptr;
360 if(argc > 1) mesh_filename= argv[1];
361 if(argc > 2) orbiter_filename= argv[2];
368 mesh.
bounds(mesh_bounds.pmin, mesh_bounds.pmax);
374 std::vector<Triangle> triangles;
378 triangles.push_back(
Triangle(data, triangles.size()) );
382 bvh.build(triangles);
388 std::vector<Instance> instances;
389 for(
int i= -2; i <= 2; i++)
392 instances.push_back(
Instance(mesh_bounds, model, bvh, instances.size()) );
396 top_bvh.build(instances);
401 if(orbiter_filename ==
nullptr || camera.
read_orbiter(orbiter_filename) < 0)
403 camera.
lookat(mesh_bounds.pmin * 5, mesh_bounds.pmax * 5);
406 Image image(1024, 640);
416 #pragma omp parallel for
417 for(
int y= 0; y < image.height(); y++)
418 for(
int x= 0; x < image.width(); x++)
426 if(
Hit hit= top_bvh.intersect(ray))
representation d'une image.
representation d'un objet / maillage.
void bounds(Point &pmin, Point &pmax) const
renvoie min et max les coordonnees des extremites des positions des sommets de l'objet (boite engloba...
Mesh & triangle(const unsigned int a, const unsigned int b, const unsigned int c)
int triangle_count() const
renvoie le nombre de triangles.
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet.
void lookat(const Point ¢er, const float size)
observe le point center a une distance size.
int read_orbiter(const char *filename)
relit la position de l'orbiter depuis un fichier texte.
Transform projection(const int width, const int height, const float fov)
fixe la projection reglee pour une image d'aspect width / height, et une demi ouverture de fov degres...
Transform view() const
renvoie la transformation vue.
void begin(Widgets &w)
debut de la description des elements de l'interface graphique.
void end(Widgets &w)
termine la description des elements de l'interface graphique.
Color Red()
utilitaire. renvoie une couleur rouge.
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.
Transform Translation(const Vector &v)
renvoie la matrice representant une translation par un vecteur.
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
Mesh read_mesh(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes....
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...
intersection avec un triangle.
instance pour le bvh, cf fonctions bounds() et intersect().
construction de l'arbre / BVH.
representation d'un point 3d.
representation d'un triangle.
triangle pour le bvh, cf fonction bounds() et intersect().
representation d'un vecteur 3d.
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.