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 BBox( ) : pmin(), pmax() {}
41 BBox(
const Point& p ) : pmin(p), pmax(p) {}
42 BBox(
const BBox& box ) : pmin(box.pmin), pmax(box.pmax) {}
44 BBox& insert(
const Point& p ) { pmin=
min(pmin, p); pmax=
max(pmax, p);
return *
this; }
45 BBox& insert(
const BBox& box ) { pmin=
min(pmin, box.pmin); pmax=
max(pmax, box.pmax);
return *
this; }
47 float centroid(
const int axis )
const {
return (pmin(axis) + pmax(axis)) / 2; }
49 bool intersect(
const RayHit& ray )
const
51 Vector invd=
Vector(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z);
52 return intersect(ray, invd);
55 bool intersect(
const RayHit& ray,
const Vector& invd )
const
59 if(ray.d.x < 0) std::swap(rmin.x, rmax.x);
60 if(ray.d.y < 0) std::swap(rmin.y, rmax.y);
61 if(ray.d.z < 0) std::swap(rmin.z, rmax.z);
62 Vector dmin= (rmin - ray.o) * invd;
63 Vector dmax= (rmax - ray.o) * invd;
67 return (tmin <= tmax);
87 void intersect(
RayHit &ray )
const
90 float det=
dot(e1, pvec);
92 float inv_det= 1 / det;
95 float u=
dot(tvec, pvec) * inv_det;
96 if(u < 0 || u > 1)
return;
99 float v=
dot(ray.d, qvec) * inv_det;
100 if(v < 0 || u + v > 1)
return;
102 float t=
dot(e2, qvec) * inv_det;
103 if(t < 0 || t > ray.t)
return;
115 return box.insert(p+e1).insert(p+e2);
122 const std::vector<Triangle>& triangles,
const int tbegin,
const int tend,
123 std::vector<RayHit>& rays,
const int rbegin,
const int rend )
125 for(
int i= rbegin; i < rend; i++)
126 for(
int k= tbegin; k < tend; k++)
127 triangles[k].intersect(rays[i]);
135 triangle_less1(
const int _axis,
const float _cut ) : axis(_axis), cut(_cut) {}
137 bool operator() (
const Triangle& triangle )
const
141 return bounds.centroid(axis) < cut;
151 bool operator() (
const RayHit& ray )
const
153 return bounds.intersect(ray);
159 std::vector<Triangle>& triangles,
const int tbegin,
const int tend,
160 std::vector<RayHit>& rays,
const int rbegin,
const int rend )
162 if(tbegin == tend || rbegin == rend)
167 if(tend - tbegin <= 4)
169 direct(triangles, tbegin, tend, rays, rbegin, rend);
176 if(d.x > d.y && d.x > d.z)
184 float cut=
bounds.centroid(axis);
187 Triangle *pm= std::partition(triangles.data() + tbegin, triangles.data() + tend,
triangle_less1(axis, cut));
192 if(m == tbegin || m == tend)
193 m= (tbegin + tend) / 2;
198 BBox left= triangles[tbegin].bounds();
199 for(
int i= tbegin+1; i < m; i++)
200 left.insert(triangles[i].bounds());
203 RayHit *prleft= std::partition(rays.data() + rbegin, rays.data() + rend,
ray_less1(left));
206 divide(left, triangles, tbegin, m, rays, rbegin, rleft);
209 BBox right= triangles[m].bounds();
210 for(
int i= m+1; i < tend; i++)
211 right.insert(triangles[i].bounds());
213 RayHit *prright= std::partition(rays.data() + rbegin, rays.data() + rend,
ray_less1(right));
216 divide(right, triangles, m, tend, rays, rbegin, rright);
220 int main(
const int argc,
const char **argv )
222 const char *mesh_filename=
"data/cornell.obj";
224 mesh_filename= argv[1];
226 const char *orbiter_filename=
"data/cornell_orbiter.txt";
228 orbiter_filename= argv[2];
239 std::vector<Triangle> triangles;
242 for(
int i= 0; i < n; i++)
243 triangles.emplace_back(mesh.
triangle(i), i);
246 Image image(1024, 768);
249 camera.
projection(image.width(), image.height(), 45);
257 std::vector<RayHit> rays;
258 for(
int y= 0; y < image.height(); y++)
259 for(
int x= 0; x < image.width(); x++)
262 Point origine= inv(
Point(x + .5f, y + .5f, 0));
263 Point extremite= inv(
Point(x + .5f, y + .5f, 1));
265 rays.emplace_back(origine, extremite, x, y);
271 auto start= std::chrono::high_resolution_clock::now();
272 direct(triangles, 0,
int(triangles.size()), rays, 0,
int(rays.size()));
274 auto stop= std::chrono::high_resolution_clock::now();
275 int cpu= std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
276 printf(
"direct %dms\n", cpu);
281 auto start= std::chrono::high_resolution_clock::now();
282 divide(
bounds, triangles, 0,
int(triangles.size()), rays, 0,
int(rays.size()));
284 auto stop= std::chrono::high_resolution_clock::now();
285 int cpu= std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
286 printf(
"divide %dms\n", cpu);
290 for(
int i= 0; i < rays.size(); i++)
299 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 printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
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.
representation d'une couleur (rgba) transparente ou opaque.
representation d'un point 3d.
representation d'un triangle.
triangle pour le bvh, cf fonction bounds() et intersect().
representation d'un vecteur 3d.