29 RayHit(
const Point& _o,
const Point& _e ) : o(_o), t(1), d(
Vector(_o, _e)), triangle_id(-1), u(), v(), x(), y() {}
30 RayHit(
const Point& _o,
const Point& _e,
const int _x,
const int _y ) : o(_o), t(1), d(
Vector(_o, _e)), triangle_id(-1), u(), v(), x(_x), y(_y) {}
31 operator bool ( ) {
return (triangle_id != -1); }
39 BBoxHit() : tmin(FLT_MAX), tmax(-FLT_MAX) {}
40 BBoxHit(
const float _tmin,
const float _tmax ) : tmin(_tmin), tmax(_tmax) {}
41 float centroid( )
const {
return (tmin + tmax) / 2; }
42 operator bool( )
const {
return tmin <= tmax; }
50 BBox( ) : pmin(), pmax() {}
52 BBox(
const Point& p ) : pmin(p), pmax(p) {}
53 BBox(
const BBox& box ) : pmin(box.pmin), pmax(box.pmax) {}
55 BBox& insert(
const Point& p ) { pmin=
min(pmin, p); pmax=
max(pmax, p);
return *
this; }
56 BBox& insert(
const BBox& box ) { pmin=
min(pmin, box.pmin); pmax=
max(pmax, box.pmax);
return *
this; }
58 float centroid(
const int axis )
const {
return (pmin(axis) + pmax(axis)) / 2; }
62 Vector invd=
Vector(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z);
63 return intersect(ray, invd);
70 if(ray.d.x < 0) std::swap(rmin.x, rmax.x);
71 if(ray.d.y < 0) std::swap(rmin.y, rmax.y);
72 if(ray.d.z < 0) std::swap(rmin.z, rmax.z);
73 Vector dmin= (rmin - ray.o) * invd;
74 Vector dmax= (rmax - ray.o) * invd;
98 void intersect(
RayHit &ray )
const
101 float det=
dot(e1, pvec);
103 float inv_det= 1 / det;
106 float u=
dot(tvec, pvec) * inv_det;
107 if(u < 0 || u > 1)
return;
110 float v=
dot(ray.d, qvec) * inv_det;
111 if(v < 0 || u + v > 1)
return;
113 float t=
dot(e2, qvec) * inv_det;
114 if(t < 0 || t > ray.t)
return;
126 return box.insert(p+e1).insert(p+e2);
138 bool internal( )
const {
return right > 0; }
139 int internal_left( )
const { assert(
internal());
return left; }
140 int internal_right( )
const { assert(
internal());
return right; }
142 bool leaf( )
const {
return right < 0; }
143 int leaf_begin( )
const { assert(leaf());
return -left; }
144 int leaf_end( )
const { assert(leaf());
return -right; }
151 assert(node.internal());
169 triangle_less1(
const int _axis,
const float _cut ) : axis(_axis), cut(_cut) {}
171 bool operator() (
const Triangle& triangle )
const
175 return bounds.centroid(axis) < cut;
182 std::vector<Node> nodes;
183 std::vector<Triangle> triangles;
189 int build(
const BBox& _bounds,
const std::vector<Triangle>& _triangles )
191 triangles= _triangles;
193 nodes.reserve(triangles.size());
196 root= build(_bounds, 0, triangles.size());
201 void intersect(
RayHit& ray )
const
203 Vector invd=
Vector(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z);
204 intersect(root, ray, invd);
207 void intersect_fast(
RayHit& ray )
const
209 Vector invd=
Vector(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z);
210 intersect_fast(root, ray, invd);
220 int index= nodes.size();
228 if(d.x > d.y && d.x > d.z)
236 float cut=
bounds.centroid(axis);
251 BBox bounds_left= triangle_bounds(
begin, m);
252 int left= build(bounds_left,
begin, m);
256 BBox bounds_right= triangle_bounds(m,
end);
257 int right= build(bounds_right, m,
end);
259 int index= nodes.size();
268 bbox.insert(triangles[i].bounds());
273 void intersect(
const int index,
RayHit& ray,
const Vector& invd )
const
275 const Node& node= nodes[index];
276 if(node.bounds.intersect(ray, invd))
280 for(
int i= node.leaf_begin(); i < node.leaf_end(); i++)
281 triangles[i].intersect(ray);
285 intersect(node.internal_left(), ray, invd);
286 intersect(node.internal_right(), ray, invd);
291 void intersect_fast(
const int index,
RayHit& ray,
const Vector& invd )
const
293 const Node& node= nodes[index];
296 for(
int i= node.leaf_begin(); i < node.leaf_end(); i++)
297 triangles[i].intersect(ray);
301 const Node& left_node= nodes[node.left];
302 const Node& right_node= nodes[node.right];
304 BBoxHit left= left_node.bounds.intersect(ray, invd);
305 BBoxHit right= right_node.bounds.intersect(ray, invd);
308 if(left.centroid() < right.centroid())
310 intersect_fast(node.internal_left(), ray, invd);
311 intersect_fast(node.internal_right(), ray, invd);
315 intersect_fast(node.internal_right(), ray, invd);
316 intersect_fast(node.internal_left(), ray, invd);
320 intersect_fast(node.internal_left(), ray, invd);
322 intersect_fast(node.internal_right(), ray, invd);
328 int main(
const int argc,
const char **argv )
330 const char *mesh_filename=
"data/cornell.obj";
332 mesh_filename= argv[1];
334 const char *orbiter_filename=
"data/cornell_orbiter.txt";
336 orbiter_filename= argv[2];
347 std::vector<Triangle> triangles;
350 for(
int i= 0; i < n; i++)
351 triangles.emplace_back(mesh.
triangle(i), i);
354 Image image(1024, 768);
358 camera.
projection(image.width(), image.height(), 45);
366 std::vector<RayHit> rays;
367 for(
int y= 0; y < image.height(); y++)
368 for(
int x= 0; x < image.width(); x++)
371 Point origine= inv(
Point(x + .5f, y + .5f, 0));
372 Point extremite= inv(
Point(x + .5f, y + .5f, 1));
374 rays.emplace_back(origine, extremite, x, y);
382 auto start= std::chrono::high_resolution_clock::now();
384 bvh.build(
bounds, triangles);
386 auto stop= std::chrono::high_resolution_clock::now();
387 int cpu= std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
388 printf(
"build %dms\n", cpu);
392 auto start= std::chrono::high_resolution_clock::now();
395 const int n= int(rays.size());
396 for(
int i= 0; i < n; i++)
397 bvh.intersect(rays[i]);
399 auto stop= std::chrono::high_resolution_clock::now();
400 int cpu= std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
401 printf(
"bvh %dms\n", cpu);
405 auto start= std::chrono::high_resolution_clock::now();
408 const int n= int(rays.size());
409 #pragma omp parallel for schedule(dynamic, 1024)
410 for(
int i= 0; i < n; i++)
411 bvh.intersect(rays[i]);
413 auto stop= std::chrono::high_resolution_clock::now();
414 int cpu= std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
415 printf(
"bvh mt %dms\n", cpu);
419 auto start= std::chrono::high_resolution_clock::now();
422 const int n= int(rays.size());
423 #pragma omp parallel for schedule(dynamic, 1024)
424 for(
int i= 0; i < n; i++)
425 bvh.intersect_fast(rays[i]);
427 auto stop= std::chrono::high_resolution_clock::now();
428 int cpu= std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
429 printf(
"bvh fast mt %dms\n", cpu);
434 for(
int i= 0; i < rays.size(); i++)
443 image(x, y)=
Color(w, u, v);
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.
int read_orbiter(const char *filename)
relit la position de l'orbiter depuis un fichier texte.
Transform viewport() const
renvoie la transformation viewport actuelle. doit etre initialise par projection(width,...
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 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.
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 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.
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.
representation d'une couleur (rgba) transparente ou opaque.
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.