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;
65 float tmin= std::max(dmin.z, std::max(dmin.y, std::max(dmin.x, 0.f)));
66 float tmax= std::min(dmax.z, std::min(dmax.y, std::min(dmax.x, ray.t)));
67 return (tmin <= tmax);
78 Triangle(
const TriangleData& data,
const int _id ) : p(data.a), e1(Vector(data.a, data.b)), e2(Vector(data.a, data.
c)), id(_id) {}
87 void intersect( RayHit &ray )
const
89 Vector pvec=
cross(ray.d, e2);
90 float det=
dot(e1, pvec);
92 float inv_det= 1 / det;
93 Vector tvec(p, ray.o);
95 float u=
dot(tvec, pvec) * inv_det;
96 if(u < 0 || u > 1)
return;
98 Vector qvec=
cross(tvec, e1);
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;
149 ray_less1(
const BBox& _bounds ) : bounds(_bounds) {}
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));
188 int m= std::distance(triangles.data(), pm);
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));
204 int rleft= std::distance(rays.data(), prleft);
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));
214 int rright= std::distance(rays.data(), prright);
216 divide(right, triangles, m, tend, rays, rbegin, rright);
220int 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];
231 if(camera.read_orbiter(orbiter_filename) < 0)
239 std::vector<Triangle> triangles;
241 int n= mesh.triangle_count();
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);
252 Transform projection= camera.projection();
257 std::vector<RayHit> rays;
258 for(
unsigned y= 0; y < image.height(); y++)
259 for(
unsigned 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(
unsigned 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...
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet.
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.
representation d'une couleur (rgba) transparente ou opaque.
representation d'un point 3d.
triangle pour le bvh, cf fonction bounds() et intersect().
representation d'un vecteur 3d.