25 Ray(
const Point& _o,
const Vector& _d ) : o(_o), d(_d), tmax(FLT_MAX) {}
26 Ray(
const Point& _o,
const Vector& _d,
const float _tmax ) : o(_o), d(_d), tmax(_tmax) {}
40 Hit( ) : t(FLT_MAX), u(), v(), node_id(-1), mesh_id(-1), primitive_id(-1), triangle_id(-1) {}
41 Hit(
const Ray& ray ) : t(ray.tmax), u(), v(), node_id(-1), mesh_id(-1), primitive_id(-1), triangle_id(-1) {}
43 Hit(
const float _t,
const float _u,
const float _v,
const int _node_id,
const int _mesh_id,
const int _primitive_id,
const int _id ) : t(_t), u(_u), v(_v),
44 node_id(_node_id), mesh_id(_mesh_id), primitive_id(_primitive_id), triangle_id(_id) {}
46 operator bool ( ) {
return (triangle_id != -1); }
54 BBoxHit() : tmin(FLT_MAX), tmax(-FLT_MAX) {}
55 BBoxHit(
const float _tmin,
const float _tmax ) : tmin(_tmin), tmax(_tmax) {}
57 operator bool( )
const {
return tmin <= tmax; }
66 BBox( ) : pmin(), pmax() {}
68 BBox(
const Point& p ) : pmin(p), pmax(p) {}
69 BBox(
const BBox& box ) : pmin(box.pmin), pmax(box.pmax) {}
70 BBox(
const BBox& a,
const BBox& b ) : pmin(
min(a.pmin, b.pmin)), pmax(
max(a.pmax, b.pmax)) {}
72 BBox& insert(
const Point& p ) { pmin=
min(pmin, p); pmax=
max(pmax, p);
return *
this; }
73 BBox& insert(
const BBox& box ) { pmin=
min(pmin, box.pmin); pmax=
max(pmax, box.pmax);
return *
this; }
75 float centroid(
const int axis )
const {
return (pmin(axis) + pmax(axis)) / 2; }
76 Point centroid( )
const {
return (pmin + pmax) / 2; }
78 BBoxHit intersect(
const Ray& ray,
const Vector& invd,
const float htmax )
const
82 if(ray.d.x < 0) std::swap(rmin.x, rmax.x);
83 if(ray.d.y < 0) std::swap(rmin.y, rmax.y);
84 if(ray.d.z < 0) std::swap(rmin.z, rmax.z);
85 Vector dmin= (rmin - ray.o) * invd;
86 Vector dmax= (rmax - ray.o) * invd;
102 bool internal( )
const {
return right > 0; }
103 int internal_left( )
const { assert(
internal());
return left; }
104 int internal_right( )
const { assert(
internal());
return right; }
106 bool leaf( )
const {
return right < 0; }
107 int leaf_begin( )
const { assert(leaf());
return -left; }
108 int leaf_end( )
const { assert(leaf());
return -right; }
115 assert(node.internal());
129 template <
typename T >
133 int build(
const std::vector<T>& _primitives )
135 primitives= _primitives;
137 nodes.reserve(primitives.size());
140 root= build(0, primitives.size());
145 Hit intersect(
const Ray& ray,
const float htmax )
const
149 Vector invd=
Vector(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z);
150 intersect_fast(root, ray, invd, hit);
155 Hit intersect(
const Ray& ray )
const {
return intersect(ray, ray.tmax); }
157 bool occluded(
const Ray& ray )
const
159 Vector invd=
Vector(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z);
160 return occluded(root, ray, invd, 1);
163 bool occluded(
const Point& p,
const Point& q )
const {
Ray ray(p, q);
return occluded(ray); }
165 bool visible(
const Point& p,
const Point& q )
const {
return !occluded(p, q); }
166 bool visible(
const Ray& ray )
const {
return !occluded(ray); }
170 std::vector<Node> nodes;
171 std::vector<T> primitives;
174 int build(
const int begin,
const int end )
179 int index= nodes.size();
188 if(d.x > d.y && d.x > d.z)
196 float cut= cbounds.centroid(axis);
199 T *pm= std::partition(primitives.data() +
begin, primitives.data() +
end,
200 [axis, cut](
const T& primitive )
202 return primitive.bounds().centroid(axis) < cut;
215 int left= build(
begin, m);
218 int right= build(m,
end);
221 int index= nodes.size();
231 bbox.insert(primitives[i].bounds());
239 BBox bbox= primitives[
begin].bounds().centroid();
241 bbox.insert(primitives[i].bounds().centroid());
246 void intersect_fast(
const int index,
const Ray& ray,
const Vector& invd,
Hit& hit )
const
248 const Node& node= nodes[index];
254 for(
int i= node.leaf_begin(); i < node.leaf_end(); i++)
255 if(
Hit h= primitives[i].intersect(ray, hit.t))
261 BBoxHit left= nodes[node.internal_left()].bounds.intersect(ray, invd, hit.t);
262 BBoxHit right= nodes[node.internal_right()].bounds.intersect(ray, invd, hit.t);
267 if(left.tmin < right.tmin)
269 intersect_fast(node.internal_left(), ray, invd, hit);
270 intersect_fast(node.internal_right(), ray, invd, hit);
274 intersect_fast(node.internal_right(), ray, invd, hit);
275 intersect_fast(node.internal_left(), ray, invd, hit);
281 intersect_fast(node.internal_left(), ray, invd, hit);
283 intersect_fast(node.internal_right(), ray, invd, hit);
287 bool occluded(
const int index,
const Ray& ray,
const Vector& invd,
const float htmax )
const
289 const Node& node= nodes[index];
290 if(node.bounds.intersect(ray, invd, htmax))
294 for(
int i= node.leaf_begin(); i < node.leaf_end(); i++)
295 if(primitives[i].intersect(ray, htmax))
300 if(occluded(node.internal_left(), ray, invd, htmax) || occluded(node.internal_right(), ray, invd, htmax))
320 Triangle(
const vec3& a,
const vec3& b,
const vec3&
c,
const int _node_id,
const int _mesh_id,
const int _primitive_id,
const int _id ) :
322 node_id(_node_id), mesh_id(_mesh_id), primitive_id(_primitive_id), triangle_id(_id) {}
331 Hit intersect(
const Ray &ray,
const float htmax )
const
334 float det=
dot(e1, pvec);
336 float inv_det= 1 / det;
339 float u=
dot(tvec, pvec) * inv_det;
340 if(u < 0 || u > 1)
return Hit();
343 float v=
dot(ray.d, qvec) * inv_det;
344 if(v < 0 || u + v > 1)
return Hit();
346 float t=
dot(e2, qvec) * inv_det;
347 if(t < 0 || t > htmax)
return Hit();
349 return Hit(t, u, v, node_id, mesh_id, primitive_id, triangle_id);
355 return box.insert(p+e1).insert(p+e2);
365 assert(hit.triangle_id != -1);
366 return ray.o + hit.t * ray.d;
376 assert(hit.mesh_id != -1);
377 assert(hit.primitive_id != -1);
383 return default_material;
391 return (1 - material.
metallic) * material.
color / float(M_PI);
398 assert(hit.node_id != -1);
399 assert(hit.mesh_id != -1);
400 assert(hit.primitive_id != -1);
401 assert(hit.triangle_id != -1);
407 int a= primitives.indices[hit.triangle_id];
408 int b= primitives.indices[hit.triangle_id+1];
409 int c= primitives.indices[hit.triangle_id+2];
412 assert(primitives.normals.size());
413 Vector na= primitives.normals[a];
414 Vector nb= primitives.normals[b];
415 Vector nc= primitives.normals[c];
419 Vector n= (1 - hit.u - hit.v) * na + hit.u * nb + hit.v * nc;
440 World( ) : t(), b(), n() {}
443 float sign= std::copysign(1.0f, n.z);
444 float a= -1.0f / (sign + n.z);
445 float d= n.x * n.y * a;
446 t=
Vector(1.0f + sign * n.x * n.x * a, sign * d, -sign * n.x);
447 b=
Vector(d, sign + n.y * n.y * a, -n.y);
451 Vector operator( ) (
const Vector& local )
const {
return local.x * t + local.y * b + local.z * n; }
464 std::uniform_real_distribution<float> u01;
465 std::default_random_engine rng;
468 Sampler(
const unsigned _seed ) : u01(), rng(_seed) {}
469 void seed(
const unsigned _seed ) { rng.seed(_seed); }
471 float sample( ) {
return u01(rng); }
472 unsigned sample_binary( ) {
return rng(); }
473 int sample_range(
const int n ) {
return int(sample() * n); }
484 Source(
const Point& _a,
const Point& _b,
const Point& _c,
const Color& _emission ) : a(_a), b(_b), c(_c), n(), emission(_emission), area()
490 assert(area * emission.max() > 0);
493 Point sample(
const float u1,
const float u2 )
const
498 float r1= std::sqrt(u1);
500 float beta= (1 - u2) * r1;
501 float gamma= u2 * r1;
503 return alpha*a + beta*b +
gamma*c;
510 float offset= t2 - t1;
516 return t1*a + t2*b + (1 - t1 - t2)*c;
520 float pdf(
const Point& p )
const
527 float blinn(
const float roughness )
529 if(roughness < 0.001)
532 return 2 / (roughness*roughness*roughness*roughness) - 2;
545 Brdf(
const Vector& ng,
const Color& color,
const float plastic,
const float n ) : world(ng),
diffuse(color), kd(1 - plastic), ns(
n) {}
549 float cos_theta=
dot(world.n, l);
554 float cos_theta_h=
dot(world.n, h);
560 Color s= (ns + 8) /
float(8*M_PI) * std::pow(cos_theta_h, ns) *
White();
561 return kd * d + (1 - kd) * s;
564 Vector sample(
const float u1,
const float u2,
const float u3,
const Vector& o )
const
571 float phi= float(2*M_PI) * u3;
572 float cos_theta= std::sqrt(u2);
573 float sin_theta= std::sqrt(1 - cos_theta*cos_theta);
575 return world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta));
582 float phi= float(2*M_PI) * u3;
583 float cos_theta= std::pow(u2, 1 /
float(ns +1));
584 assert(cos_theta >= 0);
585 float sin_theta= std::sqrt(1 - cos_theta*cos_theta);
586 Vector h= world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta));
588 return -o + 2 *
dot(h, o) * h;
595 float cos_theta=
dot(world.n, l);
600 float d= cos_theta / float(M_PI);
604 if(
dot(world.n, h) <= 0)
609 float cos_theta_h=
std::max(
float(0),
dot(world.n, h));
610 float s= (ns + 1) /
float(2*M_PI) * std::pow(cos_theta_h, ns) / (4 *
dot(l, h));
614 return kd*d + (1 - kd)*s;
630 const float epsilon= 0.001;
632 Image direct(
const Orbiter& camera,
const GLTFScene& scene,
const BVH& bvh,
const int samples,
const std::vector<Source>& sources )
634 Image image(camera.width(), camera.height());
637 const int N= samples;
639 printf(
"render %dx%d %d samples...\n", image.width(), image.height(), samples);
643 for(
unsigned i= 0; i < sources.size(); i++)
644 total+= sources[i].area;
652 #pragma omp parallel for schedule(dynamic, 1)
653 for(
int py= 0; py < image.height(); py++)
655 std::random_device hwseed;
658 for(
int px= 0; px < image.width(); px++)
665 for(
int pa= 0; pa < AA; pa++)
677 if(
Hit hit= bvh.intersect(ray))
683 if(
dot(ray.d, pn) > 0)
689 for(
int i= 0; i < N; i++)
692 int id= int(sources.size()) -1;
694 float u= rng.sample();
697 for(
unsigned i= 0; i < sources.size(); i++)
699 cdf+= sources[i].area / total;
710 if(
id == -1)
id= int(sources.size()) -1;
714 assert(
id <
int(sources.size()));
718 Point q= sources[id].sample(rng.sample(), rng.sample());
719 float pdf= 1 / total;
722 if(bvh.visible( p+epsilon*pn, q+epsilon*sources[
id].n ))
728 sample= diffuse * sources[id].emission * cos_theta * cos_theta_q /
length2(l) / pdf;
735 M= Mn1 + (sample - Mn1) /
float(n);
736 M2= M2 + (sample - Mn1) * (sample - M);
741 emission= emission / float(AA);
742 image(px, py)=
Color(M + emission, 1);
752 Image image(camera.width(), camera.height());
755 const int N= samples;
757 printf(
"render %dx%d %d samples...\n", image.width(), image.height(), samples);
765 #pragma omp parallel for schedule(dynamic, 1)
766 for(
int py= 0; py < image.height(); py++)
768 std::random_device hwseed;
771 for(
int px= 0; px < image.width(); px++)
778 for(
int pa= 0; pa < AA; pa++)
790 if(
Hit hit= bvh.intersect(ray))
796 if(
dot(ray.d, pn) > 0)
802 for(
int i= 0; i < N; i++)
809 float cos_theta= rng.sample();
810 float sin_theta= std::sqrt(1 - cos_theta * cos_theta);
811 float phi= float(2*M_PI) * rng.sample();
814 l= world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta) );
817 pdf= 1 / float(2*M_PI);
822 float cos_theta= std::sqrt( rng.sample() );
823 float sin_theta= std::sqrt(1 - cos_theta * cos_theta);
824 float phi= float(2*M_PI) * rng.sample();
827 l= world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta) );
830 pdf= cos_theta / float(M_PI);
835 if(
Hit source= bvh.intersect(
Ray(p+epsilon*pn, l) ))
840 sample= diffuse * Le * cos_theta / pdf;
847 M= Mn1 + (sample - Mn1) /
float(n);
848 M2= M2 + (sample - Mn1) * (sample - M);
853 emission= emission / float(AA);
854 image(px, py)=
Color(M + emission, 1);
863 Color direct(
const Point& p,
const World& world,
const GLTFScene& scene,
const BVH& bvh,
Sampler& rng,
const std::vector<Source>& sources,
const float sources_area )
865 int id= int(sources.size()) -1;
867 float u= rng.sample();
870 for(
unsigned i= 0; i < sources.size(); i++)
872 cdf+= sources[i].area / sources_area;
882 Point q= sources[id].sample(rng.sample(), rng.sample());
883 float pdf= 1 / sources_area;
886 if(bvh.visible(
Ray(p+epsilon*world.n, q+epsilon*sources[
id].n) ))
891 return sources[id].emission * cos_theta * cos_theta_q /
length2(l) / pdf;
897 Color indirect(
const Point& p,
const World& world,
const GLTFScene& scene,
const BVH& bvh,
Sampler& rng,
const std::vector<Source>& sources,
const float sources_area )
903 float cos_theta= std::sqrt( rng.sample() );
904 float sin_theta= std::sqrt(1 - cos_theta * cos_theta);
905 float phi= float(2*M_PI) * rng.sample();
908 l= world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta) );
911 pdf= cos_theta / float(M_PI);
915 Ray ray(p+epsilon*world.n, l);
916 if(
Hit qhit= bvh.intersect(ray))
922 if(
dot(ray.d, qn) > 0)
926 float cos_theta=
std::max(
float(0),
dot(world.n, l));
928 return qdiffuse * direct(q, qworld, scene, bvh, rng, sources, sources_area) * cos_theta / pdf;
935 Image indirect(
const Orbiter& camera,
const GLTFScene& scene,
const BVH& bvh,
const int samples,
const std::vector<Source>& sources )
937 Image image(camera.width(), camera.height());
940 const int N= samples;
942 printf(
"render %dx%d %d samples...\n", image.width(), image.height(), samples);
946 for(
unsigned i= 0; i < sources.size(); i++)
947 total+= sources[i].area;
955 #pragma omp parallel for schedule(dynamic, 1)
956 for(
int py= 0; py < image.height(); py++)
958 std::random_device hwseed;
961 for(
int px= 0; px < image.width(); px++)
968 for(
int pa= 0; pa < AA; pa++)
980 if(
Hit hit= bvh.intersect(ray))
988 if(
dot(ray.d, pn) > 0)
992 for(
int i= 0; i < N; i++)
994 Color d= diffuse * direct(p, world, scene, bvh, rng, sources, total);
995 Color i1= diffuse * indirect(p, world, scene, bvh, rng, sources, total);
996 Color sample= d + i1;
1003 M= Mn1 + (sample - Mn1) /
float(n);
1004 M2= M2 + (sample - Mn1) * (sample - M);
1009 emission= emission / float(AA);
1016 image(px, py)=
Color(M + emission, 1);
1030 float cos_theta= std::sqrt( rng.sample() );
1031 float sin_theta= std::sqrt(1 - cos_theta * cos_theta);
1032 float phi= float(2*M_PI) * rng.sample();
1035 l= world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta) );
1038 pdf= cos_theta / float(M_PI);
1042 Ray ray(p+epsilon*world.n, l);
1043 if(
Hit qhit= bvh.intersect(ray))
1052 float cos_theta=
std::max(
float(0),
dot(world.n, l));
1053 return qemission * cos_theta / pdf;
1065 float cos_theta= std::sqrt( rng.sample() );
1066 float sin_theta= std::sqrt(1 - cos_theta * cos_theta);
1067 float phi= float(2*M_PI) * rng.sample();
1070 l= world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta) );
1073 pdf= cos_theta / float(M_PI);
1077 Ray ray(p+epsilon*world.n, l);
1078 if(
Hit qhit= bvh.intersect(ray))
1088 if(
dot(ray.d, qn) > 0)
1092 Color qdiffuse= material_diffuse( qmaterial );
1093 float cos_theta=
std::max(
float(0),
dot(world.n, l));
1094 return qdiffuse * direct(q, qworld, scene, bvh, rng) * cos_theta / pdf;
1102 Image image(camera.width(), camera.height());
1105 const int N= samples;
1107 printf(
"render %dx%d %d samples...\n", image.width(), image.height(), samples);
1115 #pragma omp parallel for schedule(dynamic, 1)
1116 for(
int py= 0; py < image.height(); py++)
1118 std::random_device hwseed;
1121 for(
int px= 0; px < image.width(); px++)
1125 for(
int pa= 0; pa < AA; pa++)
1137 if(
Hit hit= bvh.intersect(ray))
1146 if(
dot(ray.d, pn) > 0)
1150 for(
int i= 0; i < N; i++)
1152 Color d= diffuse * direct(p, world, scene, bvh, rng);
1153 Color i1= diffuse * indirect(p, world, scene, bvh, rng);
1154 color= color + d + i1;
1159 emission= emission / float(AA);
1160 color= color / float(AA*N);
1162 image(px, py)=
Color(color + emission, 1);
1169 Image ao(
const Orbiter& camera,
const GLTFScene& scene,
const BVH& bvh,
const int samples,
const std::vector<Source>& sources )
1171 Image image(camera.width(), camera.height());
1174 const int N= samples;
1176 printf(
"render %dx%d %d samples...\n", image.width(), image.height(), samples);
1180 for(
unsigned i= 0; i < sources.size(); i++)
1181 total+= sources[i].area;
1189 #pragma omp parallel for schedule(dynamic, 1)
1190 for(
int py= 0; py < image.height(); py++)
1192 std::random_device hwseed;
1195 for(
int px= 0; px < image.width(); px++)
1202 for(
int pa= 0; pa < AA; pa++)
1214 if(
Hit hit= bvh.intersect(ray))
1220 if(
dot(ray.d, pn) > 0)
1226 for(
int i= 0; i < N; i++)
1233 float cos_theta= rng.sample();
1234 float sin_theta= std::sqrt(1 - cos_theta * cos_theta);
1235 float phi= float(2*M_PI) * rng.sample();
1238 l= world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta) );
1241 pdf= 1 / float(2*M_PI);
1246 float cos_theta= std::sqrt( rng.sample() );
1247 float sin_theta= std::sqrt(1 - cos_theta * cos_theta);
1248 float phi= float(2*M_PI) * rng.sample();
1251 l= world(
Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta) );
1254 pdf= cos_theta / float(M_PI);
1260 if(!bvh.intersect(
Ray(p + epsilon*pn, l)))
1267 sample= diffuse * Li * cos_theta / pdf;
1274 M= Mn1 + (sample - Mn1) /
float(n);
1275 M2= M2 + (sample - Mn1) * (sample - M);
1280 emission= emission / float(AA);
1286 image(px, py)=
Color(M2 /
float(n), 1);
1294 int main(
int argc,
char **argv )
1296 const char *filename=
"cornell.gltf";
1297 const char *orbiter_filename=
"orbiter.txt";
1298 if(argc > 1) filename= argv[1];
1299 if(argc > 2) orbiter_filename= argv[2];
1306 if(scene.
meshes.size() == 0)
1311 std::vector<Source> sources;
1313 std::vector<Triangle> triangles;
1315 for(
unsigned node_id= 0; node_id < scene.
nodes.size(); node_id++)
1323 for(
unsigned primitive_id= 0; primitive_id < mesh.
primitives.size(); primitive_id++)
1330 bool emission= (material.
emission.max() > 0);
1331 for(
unsigned i= 0; i +2 < primitives.indices.size(); i+= 3)
1334 Point a= model(
Point(primitives.positions[primitives.indices[i]]) );
1335 Point b= model(
Point(primitives.positions[primitives.indices[i+1]]) );
1336 Point c= model(
Point(primitives.positions[primitives.indices[i+2]]) );
1343 triangles.push_back(
Triangle(a, b, c, node_id, mesh_id, primitive_id, i) );
1354 assert(triangles.size());
1357 bvh.build(triangles);
1366 for(
int n : { 16384 })
1370 Image image= indirect(camera, scene, bvh, n);
1375 sprintf(tmp,
"cornell_direct-%04d.hdr", n);
representation d'une image.
GLenum primitives() const
renvoie le type de primitives.
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.
int mesh_index
indice du maillage.
int material_index
indice de la matiere des primitives.
GLTFScene read_gltf_scene(const char *filename)
charge un fichier .gltf et construit une scene statique, sans animation.
Transform model
transformation model pour dessiner le maillage.
description d'un maillage.
position et orientation d'un maillage dans la scene.
groupe de triangles d'un maillage. chaque groupe est associe a une matiere.
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.
Color Black()
utilitaire. renvoie une couleur noire.
Color gamma(const Color &color)
correction gamma : rgb vers srgb
Color White()
utilitaire. renvoie une couleur blanche.
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 length2(const Vector &v)
renvoie la carre de la longueur d'un vecteur.
float dot(const Vector &u, const Vector &v)
renvoie le produit scalaire de 2 vecteurs.
Vector normalize(const Vector &v)
renvoie un vecteur unitaire / longueur == 1.
float length(const Vector &v)
renvoie la longueur d'un vecteur.
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
int write_image_hdr(const Image &image, const char *filename)
enregistre une image dans un fichier .hdr.
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...
regroupe tous les parametres de la matiere du point d'intersection.
Vector n
normale interpolee du point d'intersection
representation d'une couleur (rgba) transparente ou opaque.
Color emission
emission pour les sources de lumieres ou pas (= noir).
float metallic
metallic / dielectrique.
std::vector< GLTFMaterial > materials
matieres.
std::vector< GLTFNode > nodes
noeuds / position et orientation des maillages dans la scene.
std::vector< GLTFMesh > meshes
ensemble de maillages.
intersection avec un triangle.
construction de l'arbre / BVH.
representation d'un point 3d.
generation de nombres aleatoires entre 0 et 1.
triangle pour le bvh, cf fonction bounds() et intersect().
representation d'un vecteur 3d.
vecteur generique, utilitaire.
const GLTFMaterial & hit_material(const Hit &hit, const GLTFScene &scene)
renvoie la matiere du point d'intersection.
Vector hit_normal(const Hit &hit, const GLTFScene &scene)
renvoie la normale interpolee au point d'intersection dans le repere de la scene.
Point hit_position(const Hit &hit, const Ray &ray)
renvoie la position du point d'intersection sur le rayon.
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.