gKit2 light
Loading...
Searching...
No Matches
tuto_is.cpp
1
2#include <cfloat>
3#include <cmath>
4
5#include "app.h"
6
7#include "vec.h"
8#include "color.h"
9#include "mat.h"
10
11#include "mesh.h"
12#include "wavefront.h"
13#include "draw.h"
14
15#include "image.h"
16#include "image_io.h"
17#include "image_hdr.h"
18
19#include "program.h"
20#include "uniforms.h"
21#include "texture.h"
22
23#include "orbiter.h"
24
25#define EPSILON 0.00001f
26
27
28struct Ray
29{
30 Point o;
31 Vector d;
32 float tmax;
33
34 Ray( const Point origine, const Point extremite ) : o(origine), d(Vector(origine, extremite)), tmax(1) {}
35 Ray( const Point origine, const Vector direction ) : o(origine), d(direction), tmax(FLT_MAX) {}
36
37 Point operator( ) ( const float t ) const { return o + t * d; }
38};
39
40struct Hit
41{
42 Point p;
43 Vector n;
44 float t, u, v;
45 int object_id;
46
47 Hit( ) : p(), n(), t(FLT_MAX), u(0), v(0), object_id(-1) {}
48};
49
50struct Triangle : public TriangleData
51{
52 Triangle( ) : TriangleData() {}
53 Triangle( const TriangleData& data ) : TriangleData(data) {}
54
55 /* calcule l'intersection ray/triangle
56 cf "fast, minimum storage ray-triangle intersection"
57 http://www.graphics.cornell.edu/pubs/1997/MT97.pdf
58
59 renvoie faux s'il n'y a pas d'intersection valide, une intersection peut exister mais peut ne pas se trouver dans l'intervalle [0 htmax] du rayon. \n
60 renvoie vrai + les coordonnees barycentriques (ru, rv) du point d'intersection + sa position le long du rayon (rt). \n
61 convention barycentrique : t(u, v)= (1 - u - v) * a + u * b + v * c \n
62 */
63 bool intersect( const Ray &ray, const float htmax, float &rt, float &ru, float&rv ) const
64 {
65 /* begin calculating determinant - also used to calculate U parameter */
66 Vector ac= Vector(Point(a), Point(c));
67 Vector pvec= cross(ray.d, ac);
68
69 /* if determinant is near zero, ray lies in plane of triangle */
70 Vector ab= Vector(Point(a), Point(b));
71 float det= dot(ab, pvec);
72 if(det > -EPSILON && det < EPSILON)
73 return false;
74
75 float inv_det= 1.0f / det;
76
77 /* calculate distance from vert0 to ray origin */
78 Vector tvec(Point(a), ray.o);
79
80 /* calculate U parameter and test bounds */
81 float u= dot(tvec, pvec) * inv_det;
82 if(u < 0.0f || u > 1.0f)
83 return false;
84
85 /* prepare to test V parameter */
86 Vector qvec= cross(tvec, ab);
87
88 /* calculate V parameter and test bounds */
89 float v= dot(ray.d, qvec) * inv_det;
90 if(v < 0.0f || u + v > 1.0f)
91 return false;
92
93 /* calculate t, ray intersects triangle */
94 rt= dot(ac, qvec) * inv_det;
95 ru= u;
96 rv= v;
97
98 // ne renvoie vrai que si l'intersection est valide (comprise entre tmin et tmax du rayon)
99 return (rt < htmax && rt > EPSILON);
100 }
101
104 Point point( const float u, const float v ) const
105 {
106 float w= 1.f - u - v;
107 return Point(Vector(a) * w + Vector(b) * u + Vector(c) * v);
108 }
109
112 Vector normal( const float u, const float v ) const
113 {
114 float w= 1.f - u - v;
115 return Vector(na) * w + Vector(nb) * u + Vector(nc) * v;
116 }
117};
118
119
120//
121struct Source : public Triangle
122{
123 Color emission;
124
125 Source( ) : Triangle(), emission() {}
126 Source( const TriangleData& data, const Color& color ) : Triangle(data), emission(color) {}
127};
128
129
130// construit un repere ortho tbn, a partir d'un seul vecteur...
131// cf "generating a consistently oriented tangent space"
132// http://people.compute.dtu.dk/jerf/papers/abstracts/onb.html
133struct World
134{
135 World( const Vector& _n ) : n(_n)
136 {
137 if(n.z < -0.9999999f)
138 {
139 t= Vector(0, -1, 0);
140 b= Vector(-1, 0, 0);
141 }
142 else
143 {
144 float a= 1.f / (1.f + n.z);
145 float d= -n.x * n.y * a;
146 t= Vector(1.f - n.x * n.x * a, d, -n.x);
147 b= Vector(d, 1.f - n.y * n.y * a, -n.y);
148 }
149 }
150
151 Vector operator( ) ( const Vector& local ) const
152 {
153 return local.x * t + local.y * b + local.z * n;
154 }
155
156 Vector t;
157 Vector b;
158 Vector n;
159};
160
161
162GLuint make_texture( const int unit, const int width, const int height )
163{
164 GLuint texture;
165 glGenTextures(1, &texture);
166 glActiveTexture(GL_TEXTURE0 + unit);
167 glBindTexture(GL_TEXTURE_2D, texture);
168
169 glTexImage2D(GL_TEXTURE_2D, 0,
170 GL_RGB32F, width, height, 0,
171 GL_RGBA, GL_FLOAT, NULL);
172
173 // fixe les parametres de filtrage par defaut
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
175 glGenerateMipmap(GL_TEXTURE_2D);
176 return texture;
177}
178
179
180struct IS : public App
181{
182 // constructeur : donner les dimensions de l'image, et eventuellement la version d'openGL.
183 IS( const char *filename ) : App(1024, 640)
184 {
185 m_mesh= read_mesh(filename);
186 if(m_mesh.vertex_count() == 0)
187 return;
188
189 build_sources();
190 build_triangles();
191
192 if(m_camera.read_orbiter("orbiter.txt") < 0)
193 {
194 Point pmin, pmax;
195 m_mesh.bounds(pmin, pmax);
196 m_camera.lookat(pmin, pmax);
197 }
198 }
199
200 int init( )
201 {
202 if(m_mesh.vertex_count() == 0)
203 return -1;
204
205 m_ptexture= make_texture(0, window_width(), window_height());
206 m_ntexture= make_texture(1, window_width(), window_height());
207 m_vtexture= make_texture(2, window_width(), window_height());
208
209 m_hitp= Image(window_width(), window_height());
210 m_hitn= Image(window_width(), window_height());
211 m_hitv= Image(window_width(), window_height());
212
213 glGenVertexArrays(1, &m_vao);
214 glBindVertexArray(m_vao);
215
216 m_program= read_program("gkit2_tutos/M2/is.glsl");
217 program_print_errors(m_program);
218
219 // etat openGL par defaut
220 glClearColor(0.2f, 0.2f, 0.2f, 1.f); // couleur par defaut de la fenetre
221
222 glClearDepth(1.f); // profondeur par defaut
223 glDepthFunc(GL_LESS); // ztest, conserver l'intersection la plus proche de la camera
224 glEnable(GL_DEPTH_TEST); // activer le ztest
225
226 return 0;
227 }
228
229 int render( )
230 {
231 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
232
233 if(key_state('r'))
234 {
235 clear_key_state('r');
236 reload_program(m_program, "gkit2_tutos/M2/is.glsl");
237 program_print_errors(m_program);
238 }
239
240 if(key_state('f'))
241 {
242 clear_key_state('f');
243 Point pmin, pmax;
244 m_mesh.bounds(pmin, pmax);
245 m_camera.lookat(pmin, pmax);
246 }
247
248 // deplace la camera
249 int mx, my;
250 unsigned int mb= SDL_GetRelativeMouseState(&mx, &my);
251 if(mb & SDL_BUTTON(1)) // le bouton gauche est enfonce
252 m_camera.rotation(mx, my);
253 else if(mb & SDL_BUTTON(3)) // le bouton droit est enfonce
254 m_camera.move(mx);
255 else if(mb & SDL_BUTTON(2)) // le bouton du milieu est enfonce
256 m_camera.translation((float) mx / (float) window_width(), (float) my / (float) window_height());
257
258 m_camera.projection(window_width(), window_height(), 45);
259
260 static int mode= 0;
261 static vec2 texcoord= vec2(0, 0);
262 if(key_state(' '))
263 {
264 clear_key_state(' ');
265 mode= (mode +1) % 2;
266
267 if(mode == 1)
268 {
269 int mx, my;
270 SDL_GetMouseState(&mx, &my);
271 vec2 pixel= vec2(mx, window_height() - my -1);
272 texcoord= vec2(pixel.x / m_hitp.width(), pixel.y / m_hitp.height());
273 printf("pixel %f %f\n", pixel.x, pixel.y);
274
275 // go
276 Point d0;
277 Vector dx0, dy0;
278 m_camera.frame(0, d0, dx0, dy0);
279
280 Point d1;
281 Vector dx1, dy1;
282 m_camera.frame(1, d1, dx1, dy1);
283
284 // pixel
285 Point o= d0 + pixel.x*dx0 + pixel.y*dy0;
286 Point e= d1 + pixel.x*dx1 + pixel.y*dy1;
287
288 Point point;
289 Vector normal;
290
291 Ray ray(o, e);
292 Hit hit;
293 if(intersect(ray, hit))
294 {
295 point= hit.p;
296 normal= hit.n;
297
298 // frame
299 #pragma omp parallel for schedule(dynamic, 16)
300 for(unsigned y= 0; y < m_hitp.height(); y++)
301 for(unsigned x= 0; x < m_hitp.width(); x++)
302 {
303 // clear
304 m_hitp(x, y)= Black();
305 m_hitn(x, y)= Black();
306 m_hitv(x, y)= Black();
307
308 Point o= d0 + x*dx0 + y*dy0;
309 Point e= d1 + x*dx1 + y*dy1;
310
311 Ray ray(o, e);
312 Hit hit;
313 if(intersect(ray, hit))
314 {
315 m_hitp(x, y)= Color(hit.p.x, hit.p.y, hit.p.z);
316 m_hitn(x, y)= Color(hit.n.x, hit.n.y, hit.n.z);
317
318 Ray shadow(hit.p + hit.n * 0.001f, point + normal * 0.001f);
319 Hit shadow_hit;
320 int v= 1;
321 if(intersect(shadow, shadow_hit))
322 v= 0;
323
324 m_hitv(x, y)= Color(v, v, v);
325 }
326 }
327
328 // transferre les donnees
329 glActiveTexture(GL_TEXTURE0);
330 glBindTexture(GL_TEXTURE_2D, m_ptexture);
331 glTexSubImage2D(GL_TEXTURE_2D, 0,
332 0, 0, m_hitp.width(), m_hitp.height(),
333 GL_RGBA, GL_FLOAT, m_hitp.data());
334
335 glActiveTexture(GL_TEXTURE0 +1);
336 glBindTexture(GL_TEXTURE_2D, m_ntexture);
337 glTexSubImage2D(GL_TEXTURE_2D, 0,
338 0, 0, m_hitn.width(), m_hitn.height(),
339 GL_RGBA, GL_FLOAT, m_hitn.data());
340
341 glActiveTexture(GL_TEXTURE0 +2);
342 glBindTexture(GL_TEXTURE_2D, m_vtexture);
343 glTexSubImage2D(GL_TEXTURE_2D, 0,
344 0, 0, m_hitv.width(), m_hitv.height(),
345 GL_RGBA, GL_FLOAT, m_hitv.data());
346 }
347 }
348 }
349
350 if(mode == 1)
351 {
352 glBindVertexArray(m_vao);
353 glUseProgram(m_program);
354
355 program_uniform(m_program, "ptexture", 0);
356 program_uniform(m_program, "ntexture", 1);
357 program_uniform(m_program, "vtexture", 2);
358 program_uniform(m_program, "pixel", texcoord);
359 program_uniform(m_program, "mode", mode);
360
361 glActiveTexture(GL_TEXTURE0);
362 glBindTexture(GL_TEXTURE_2D, m_ptexture);
363 glActiveTexture(GL_TEXTURE0 +1);
364 glBindTexture(GL_TEXTURE_2D, m_ntexture);
365 glActiveTexture(GL_TEXTURE0 +2);
366 glBindTexture(GL_TEXTURE_2D, m_vtexture);
367
368 glDrawArrays(GL_TRIANGLES, 0, 3);
369 }
370
371 else if(mode == 0)
372 draw(m_mesh, m_camera);
373
374 //
375 if(key_state('s'))
376 {
377 clear_key_state('s');
378
379 static int n= 1;
380 char tmp[1024];
381 sprintf(tmp, "screenshot%02d.png", n++);
382 printf("writing %s...\n", tmp);
383 screenshot(tmp);
384 }
385
386 return 1;
387 }
388
389 int quit( )
390 {
391 m_mesh.release();
392 return 0;
393 }
394
395
396 // recuperer les sources de lumiere du mesh : triangles associee a une matiere qui emet de la lumiere, material.emission != 0
397 int build_sources( )
398 {
399 for(int i= 0; i < m_mesh.triangle_count(); i++)
400 {
401 // recupere la matiere associee a chaque triangle de l'objet
402 Material material= m_mesh.triangle_material(i);
403
404 if((material.emission.r + material.emission.g + material.emission.b) > 0)
405 // inserer la source de lumiere dans l'ensemble.
406 m_sources.push_back( Source(m_mesh.triangle(i), material.emission) );
407 }
408
409 printf("%d sources.\n", (int) m_sources.size());
410 return (int) m_sources.size();
411 }
412
413 bool direct( const Ray& ray )
414 {
415 for(size_t i= 0; i < m_sources.size(); i++)
416 {
417 float t, u, v;
418 if(m_sources[i].intersect(ray, ray.tmax, t, u, v))
419 return true;
420 }
421
422 return false;
423 }
424
425
426 // recuperer les triangles du mesh
427 int build_triangles( )
428 {
429 for(int i= 0; i < m_mesh.triangle_count(); i++)
430 m_triangles.push_back( Triangle(m_mesh.triangle(i)) );
431
432 printf("%d triangles.\n", (int) m_triangles.size());
433 return (int) m_triangles.size();
434 }
435
436
437 // calcule l'intersection d'un rayon et de tous les triangles
438 bool intersect( const Ray& ray, Hit& hit )
439 {
440 hit.t= ray.tmax;
441 for(size_t i= 0; i < m_triangles.size(); i++)
442 {
443 float t, u, v;
444 if(m_triangles[i].intersect(ray, hit.t, t, u, v))
445 {
446 hit.t= t;
447 hit.u= u;
448 hit.v= v;
449
450 hit.p= ray(t); // evalue la positon du point d'intersection sur le rayon
451 hit.n= m_triangles[i].normal(u, v);
452
453 hit.object_id= i; // permet de retrouver toutes les infos associees au triangle
454 }
455 }
456
457 return (hit.object_id != -1);
458 }
459
460protected:
461 Mesh m_mesh;
462 Orbiter m_camera;
463
464 std::vector<Triangle> m_triangles;
465 std::vector<Source> m_sources;
466
467 Image m_hitp;
468 Image m_hitn;
469 Image m_hitv;
470
471 GLuint m_vao;
472 GLuint m_program;
473
474 GLuint m_ptexture;
475 GLuint m_ntexture;
476 GLuint m_vtexture;
477};
478
479
480int main( int argc, char **argv )
481{
482 const char *filename= "data/cornell.obj";
483 if(argc > 1)
484 filename= argv[1];
485
486 IS app(filename);
487 app.run();
488
489 return 0;
490}
App(const int width, const int height, const int major=3, const int minor=3, const int samples=0)
constructeur, dimensions de la fenetre et version d'openGL.
Definition app.cpp:11
representation d'une image.
Definition image.h:21
Mesh & triangle(const unsigned int a, const unsigned int b, const unsigned int c)
Definition mesh.cpp:178
int triangle_count() const
renvoie le nombre de triangles.
Definition mesh.cpp:421
const Material & triangle_material(const unsigned int id) const
renvoie la matiere d'un triangle.
Definition mesh.cpp:284
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition window.cpp:27
void clear_key_state(const SDL_Keycode key)
desactive une touche du clavier.
Definition window.cpp:46
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().
Definition text.cpp:140
int key_state(const SDL_Keycode key)
renvoie l'etat d'une touche du clavier. cf la doc SDL2 pour les codes.
Definition window.cpp:40
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition window.cpp:23
Color Black()
utilitaire. renvoie une couleur noire.
Definition color.cpp:18
float dot(const Vector &u, const Vector &v)
renvoie le produit scalaire de 2 vecteurs.
Definition vec.cpp:181
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
Definition vec.cpp:173
Mesh read_mesh(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes....
Definition wavefront.cpp:14
GLuint make_texture(const int unit, const int width, const int height, const GLenum texel_type, const GLenum data_format, const GLenum data_type)
creation de textures filtrables / mipmaps
Definition texture.cpp:10
int screenshot(const char *filename)
enregistre le contenu de la fenetre dans un fichier. doit etre de type .png / .bmp
Definition texture.cpp:178
GLuint read_program(const char *filename, const char *definitions)
Definition program.cpp:218
int program_print_errors(const GLuint program)
affiche les erreurs de compilation.
Definition program.cpp:446
representation d'une couleur (rgba) transparente ou opaque.
Definition color.h:14
intersection avec un triangle.
Definition tuto_bvh2.cpp:33
int render()
a deriver pour afficher les objets. renvoie 1 pour continuer, 0 pour fermer l'application.
Definition tuto_is.cpp:229
int init()
a deriver pour creer les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
Definition tuto_is.cpp:200
int quit()
a deriver pour detruire les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
Definition tuto_is.cpp:389
Color emission
pour une source de lumiere.
Definition materials.h:19
representation d'un point 3d.
Definition vec.h:21
rayon.
Definition tuto_bvh2.cpp:20
representation d'un triangle.
Definition mesh.h:95
vec3 c
positions
Definition mesh.h:96
vec3 nc
normales
Definition mesh.h:97
triangle pour le bvh, cf fonction bounds() et intersect().
Definition tuto_bvh.cpp:84
Point point(const float u, const float v) const
Definition tuto_is.cpp:104
Vector normal(const float u, const float v) const
Definition tuto_is.cpp:112
representation d'un vecteur 3d.
Definition vec.h:67
vecteur generique, utilitaire.
Definition vec.h:152