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;
76 float tmin= std::max(dmin.z, std::max(dmin.y, std::max(dmin.x, 0.f)));
77 float tmax= std::min(dmax.z, std::min(dmax.y, std::min(dmax.x, ray.t)));
89 Triangle(
const TriangleData& data,
const int _id ) : p(data.a), e1(
Vector(data.a, data.b)), e2(
Vector(data.a, data.c)), id(_id) {}
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; }
148Node make_node(
const BBox&
bounds,
const int left,
const int 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);
240 int m= std::distance(triangles.data(), pm);
244 if(m ==
begin || m == end)
245 m= (
begin + end) / 2;
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();
260 nodes.push_back(make_node(
bounds, left, right));
264 BBox triangle_bounds(
const int begin,
const int end )
267 for(
int i=
begin +1; i < end; i++)
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);
328int 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];
339 if(camera.read_orbiter(orbiter_filename) < 0)
347 std::vector<Triangle> triangles;
349 int n= mesh.triangle_count();
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);
361 Transform projection= camera.projection();
366 std::vector<RayHit> rays;
367 for(
unsigned y= 0; y < image.height(); y++)
368 for(
unsigned 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(
unsigned i= 0; i < rays.size(); i++)
443 image(x, y)=
Color(w, u, v);
representation d'une image.
representation d'un objet / maillage.
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet.
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().
bool write_image(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .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 { max(a.x, b.x), max(a.y, b.y), max(a....
Transform Identity()
construit la transformation identite.
Point min(const Point &a, const Point &b)
renvoie la plus petite composante de chaque point { min(a.x, b.x), min(a.y, b.y), min(a....
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.