gKit2 light
ray_tuto3.cpp
1 
2 #include <cstdio>
3 #include <cstdlib>
4 #include <cmath>
5 #include <cfloat>
6 
7 #include "vec.h"
8 #include "mat.h"
9 #include "image.h"
10 #include "image_io.h"
11 #include "orbiter.h"
12 #include "ray.h"
13 
15 struct Material
16 {
17  Color diffuse;
18  Color specular;
19  float ir;
20  float ns;
21  float kd;
22  float ks;
23  bool reflect;
24  bool refract;
25 
26  Material( ) : diffuse(make_white()), specular(make_black()), ir(1.f), ns(0.f), kd(1.f), ks(0.f), reflect(false), refract(false) {}
27 };
28 
29 Material make_diffuse( const Color& color )
30 {
31  Material m;
32  m.diffuse= color;
33  m.kd= 1;
34  m.ks= 0;
35  return m;
36 }
37 
38 Material make_mirror( const Color& color, const float ir )
39 {
40  Material m;
41  m.diffuse= make_color(1, 1, 1);
42  m.specular= color;
43  m.kd= 0;
44  m.ks= 1;
45  m.ir= ir;
46  m.reflect= true;
47  m.reflect= false;
48  return m;
49 }
50 
51 Material make_glass( const Color& color, const float ir )
52 {
53  Material m;
54  m.diffuse= make_color(1, 0, 1);
55  m.specular= color;
56  m.kd= 0;
57  m.ks= 1;
58  m.ir= ir;
59  m.reflect= true;
60  m.refract= true;
61  return m;
62 }
63 
64 
66 struct Sphere
67 {
68  Material material;
69  Transform model;
70  Point center;
71  float radius;
72 
73  Sphere( const Point& c, const float r, const Color& cc ) : material(make_diffuse(cc)), model(make_identity()), center(c), radius(r) {}
74  Sphere( const Point& c, const float r, const Material& m ) : material(m), model(make_identity()), center(c), radius(r) {}
75 };
76 
78 bool intersect( const Sphere& sphere, const Ray& ray, float& hit )
79 {
80  Point center= transform(sphere.model, sphere.center);
81  Vector oc= ray.origin - center;
82  float b= dot(oc, ray.direction);
83  float c= dot(oc, oc) - sphere.radius*sphere.radius;
84  // float d= dot(ray.direction, ray.direction) == 1, ray.direction == 1
85  float h= b*b - c;
86  if(h < 0.0) return false;
87 
88  h= sqrt(h);
89  float t1= (-b - h);
90 
91 /* solution classique avec les 2 racines :
92  */
93  float t2= (-b + h);
94  if(t1 <= 0 && t2 <= 0)
95  return false;
96 
97  else if(t1 > 0 && t2 > 0)
98  t1= std::min(t1, t2); // plus petite racine postive
99  else
100  t1= std::max(t1, t2); // racine positive
101 
102  // intersection valide ?
103  if(t1 < hit)
104  {
105  hit= t1;
106  return true;
107  }
108  else
109  return false;
110 
111 /* solution courte : si l'origine du rayon est a l'exterieur de la sphere...
112  if(t1 < 0)
113  return false;
114  else if(t1 < hit)
115  {
116  hit= t1;
117  return true;
118  }
119  else
120  return false;
121  */
122 }
123 
125 struct Plane
126 {
127  Material material;
128  Point anchor;
129  Vector normal;
130 
131  Plane( const Point& a, const Vector& n, const Color& c= make_white() ) : material(make_diffuse(c)), anchor(a), normal(n) {}
132  Plane( const Point& a, const Vector& n, const Material& m ) : material(m), anchor(a), normal(n) {}
133 };
134 
136 bool intersect( const Plane& plane, const Ray& ray, float &hit )
137 {
138  float t= dot(plane.anchor - ray.origin, plane.normal) / dot(ray.direction, plane.normal);
139  if(t < 0) return false;
140  if(t < hit)
141  {
142  hit= t;
143  return true;
144  }
145  else
146  return false;
147 }
148 
149 
151 std::vector<Plane> planes;
152 std::vector<Sphere> spheres;
153 
155 bool intersect( const Ray& ray, const float tmax, Hit& hit, Material& m )
156 {
157  hit.hit= false;
158  float t= tmax;
159  for(unsigned int i= 0; i < (unsigned int) planes.size(); i++)
160  if(intersect(planes[i], ray, t))
161  {
162  hit.t= t;
163  hit.p= ray.origin + t * ray.direction;
164  hit.n= planes[i].normal;
165  hit.color= planes[i].material.diffuse;
166  hit.hit= true;
167 
168  // damier
169  Vector p= make_vector(planes[i].anchor, hit.p);
170  int x= std::abs(std::floor(p.x));
171  int y= std::abs(std::floor(p.y));
172  int z= std::abs(std::floor(p.z));
173  Color color= ((x%2) ^ (z%2)) ? planes[i].material.diffuse : make_white();
174  hit.color= color;
175  m= make_diffuse(color);
176  //~ m= make_mirror(color, 1.f);
177  }
178 
179  for(unsigned int i= 0; i < (unsigned int) spheres.size(); i++)
180  if(intersect(spheres[i], ray, t))
181  {
182  hit.t= t;
183  hit.p= ray.origin + t * ray.direction;
184  hit.n= normalize(make_vector(transform(spheres[i].model, spheres[i].center), hit.p));
185  m= spheres[i].material;
186  hit.hit= true;
187  }
188 
189  return (t < tmax);
190 }
191 
192 float shadow( const Point& p, const Vector& n, const Point& l )
193 {
194  Ray ray= make_ray(p + .001f * n, l);
195  Hit hit;
196  Material m;
197  intersect(ray, distance(p + .001f * n, l), hit, m);
198 
199  return hit.hit ? 0.f : 1.f; // s'il y a une intersection p et q ne se voient pas...
200 }
201 
202 
203 int main( int argc, char **argv )
204 {
205  srand48(0);
206 
207  // creer quelques objets
208  planes.push_back( Plane(make_point(0, 0, 0), normalize(make_vector(0, 1, 0)), make_red()) );
209  planes.push_back( Plane(make_point(0, 0, 16), normalize(make_vector(0, 0, -1)), make_red()) );
210  planes.push_back( Plane(make_point(0, 0, -16), normalize(make_vector(0, 0, 1)), make_white()) );
211 
212  spheres.push_back( Sphere(make_point(0, 0, 0), 1, make_white()) );
213  //~ spheres.push_back( Sphere(make_point(0, 0, 0), 1, make_mirror(make_white(), 1.5f)) );
214  spheres.push_back( Sphere(make_point(1, 0, 0), 0.5f, make_red()) );
215  spheres.push_back( Sphere(make_point(0, 1, 0), 0.5f, make_green()) );
216  spheres.push_back( Sphere(make_point(0, 0, 1), 0.5f, make_blue()) );
217 
218  // et quelques spheres miroir placees aleatoirement
219  for(int i= 0; i < 10; i++)
220  {
221  float x= drand48() * 20 - 10;
222  float y= drand48() * 5 + 2;
223  float z= drand48() * 20 - 10;
224  float r= drand48() * 2 + .25f;
225  spheres.push_back( Sphere(make_point(x, y, z), r, make_glass(make_white(), 1.3f)) );
226  }
227 
228  // et une source de lumiere
229  Point light= make_point(10, 20, -2);
230  Color emission= make_white() * 500;
231 
232  // reculer la camera pour observer les objets
233  Orbiter camera= make_orbiter_lookat( make_point(0, 0, 0), 15 );
234  orbiter_rotation(camera, 0, 45);
235 
236  // go
237  Image image(1024, 640);
238 
239  Point d0;
240  Vector dx, dy;
241  Point o= orbiter_position(camera);
242  orbiter_image_frame(camera, image.width(), image.height(), 0, 45, d0, dx, dy);
243 
244 #pragma omp parallel for schedule(dynamic, 16)
245  for(int y= 0; y < image.height(); y++)
246  for(int x= 0; x < image.width(); x++)
247  {
248  Color pixel= make_black();
249 
250  const int samples= 16;
251  for(int s= 0; s < samples; s++)
252  {
253  Point e= d0 + ((float) x + drand48() - 0.5f) * dx + ((float) y + drand48() - 0.5f) * dy;
254  Ray ray= make_ray(o, e);
255 
256  Hit hit;
257  Material m;
258  if(intersect(ray, FLT_MAX, hit, m))
259  {
260  Color color= make_black();
261 
262  if(m.reflect)
263  {
264  Ray mray= reflect(ray, hit.p, hit.n);
265  Hit mhit;
266  Material mm;
267  if(intersect(mray, FLT_MAX, mhit, mm))
268  {
269  // reflexion miroir
270  float cos_theta= std::max( 0.f, dot(normalize(make_vector(mhit.p, light)), mhit.n));
271  color= color + m.specular * fresnel(ray, hit.p, hit.n, m.ir) * emission / distance2(mhit.p, light) * mm.diffuse * shadow(mhit.p, mhit.n, light) * cos_theta;
272  }
273  else
274  color= color + m.specular * fresnel(ray, hit.p, hit.n, m.ir) * make_color(1, 1, 0) *2;
275  }
276 
277  if(m.refract)
278  {
279  // entree dans l'objet
280  if(fresnel_refract(ray, hit.p, hit.n, m.ir))
281  {
282  Ray iray= refract(ray, hit.p, hit.n, m.ir);
283  Hit ihit;
284  Material im;
285  if(intersect(iray, FLT_MAX, ihit, im))
286  {
287  // sortie de l'objet
288  if(fresnel_refract(iray, ihit.p, ihit.n, im.ir))
289  {
290  Ray oray= refract(iray, ihit.p, ihit.n, im.ir);
291  Hit ohit;
292  Material om;
293  if(intersect(oray, FLT_MAX, ohit, om))
294  {
295  // transparence
296  float cos_theta= std::max( 0.f, dot(normalize(make_vector(ohit.p, light)), ohit.n));
297  color= color + m.specular * (1.f - fresnel(ray, hit.p, hit.n, m.ir)) * im.specular * (1.f - fresnel(iray, ihit.p, ihit.n, im.ir))
298  * emission / distance2(ohit.p, light) * om.diffuse * shadow(ohit.p, ohit.n, light) * cos_theta;
299  }
300  }
301  }
302  }
303  }
304 
305  else
306  {
307  // diffus
308  float cos_theta= std::max( 0.f, dot(normalize(make_vector(hit.p, light)), hit.n));
309  color= emission / distance2(hit.p, light) * m.diffuse * shadow(hit.p, hit.n, light) * cos_theta;
310  }
311 
312  pixel= pixel + color;
313  }
314  }
315 
316  image(x, y)= Color(pixel / (float) samples, 1);
317  }
318 
319  write_image(image, "render.png");
320  return 0;
321 }
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet...
Definition: orbiter.h:16
Point p
position
Definition: ray.h:37
Vector normalize(const Vector &v)
renvoie un vecteur unitaire / longueur == 1.
Definition: vec.cpp:79
float kd
ks * diffuse + ks * speculaire, kd + ks == 1
Definition: ray_tuto3.cpp:21
bool reflect
specualr reflect
Definition: ray_tuto3.cpp:23
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:13
Color color
couleur de la surface au point d'intersection
Definition: ray.h:39
representation d'une matiere
Definition: ray_tuto3.cpp:15
representation d'un vecteur 3d.
Definition: vec.h:42
float dot(const Vector &u, const Vector &v)
renvoie le produit scalaire de 2 vecteurs.
Definition: vec.cpp:93
float t
abscisse : p= o + t.d
Definition: ray.h:40
representation d'un point d'intersection.
Definition: ray.h:33
Vector n
normale de la surface au point d'intersection
Definition: ray.h:38
bool refract
specualr refract
Definition: ray_tuto3.cpp:24
representation d'une transformation, une matrice 4x4, organisee par ligne / row major.
Definition: mat.h:20
int write_image(const Image &image, const char *filename)
enregistre une image dans un fichier png.
Definition: image_io.cpp:88
representation d'un rayon.
Definition: ray.h:12
representation d'une image.
Definition: image.h:18
float distance(const Point &a, const Point &b)
renvoie la distance etre 2 points.
Definition: vec.cpp:7
representation d'un point 3d.
Definition: vec.h:19
float ns
exposant blinn phong
Definition: ray_tuto3.cpp:20
Point center(const Point &a, const Point &b)
renvoie le milieu du segment ab.
Definition: vec.cpp:17
representation d'une sphere.
Definition: ray_tuto3.cpp:66
float ir
indice de refraction
Definition: ray_tuto3.cpp:19
float distance2(const Point &a, const Point &b)
renvoie le carre de la distance etre 2 points.
Definition: vec.cpp:12
representation d'un plan. point + normale.
Definition: ray_tuto3.cpp:125