vous pouvez utiliser robot_studio.obj
ou robot_studio.gltf comme
scène de test pour cette partie du tp, ce sera plus simple que de
manipuler une scène gltf complète...
réponse directe : ca ne marche pas, lorsque l'on dessine
un triangle, on a pas d'information sur les autres triangles qui
pourraient faire de l'ombre...
ah ? comment on fait alors ?
facile, mais il va falloir dessiner 2 fois la scène,
mais on "garde" les triangles visibles par la source de lumière,
on sait qu'ils sont éclairés, c'est le résultat de la 1ere étape.
pour chaque pixel de l'image dessinée pour le point de vue de la
source on connait la distance entre la source de lumière et le
triangle visible.
ensuite, lorsque l'on dessine la scène pour le point de vue de la
camera, on transforme le point visible pour la camera dans le
repère / le point de vue de la source. il ne reste plus qu'à
comparer la distance entre le point transformé et la source avec
la distance de la 1ere étape, qui correspond au triangle le plus
proche de la source, ie celui qui est éclairé. si le point est à
la bonne distance / sur le triangle éclairé, il est lui aussi
éclairé, sinon sa distance est plus grande et il est à l'ombre.
euh ? et sinon ?
on fait le tp...
exercice 1 : dessinez la scène pour le point de vue de la source de lumière.
on commence par construire les transformations qui permettent d'observer la scène depuis la position de la source de lumière. il faut, comme d'habitude, définir les transformations model, view, projection et image.
le plus direct est d'utiliser une projection ortographique, cf Ortho()
qui "projette" un cube [left .. right] x [bottom .. top] x
[znear .. zfar]
du repère camera vers le repère
projectif.
des exemples complets sont dans la doc en ligne, cf "decals
et projection de textures"
exercice 2 : création du framebuffer et des textures
étape suivante, il faut conserver les triangles visibles par la
source de lumière, ils seront éclairés. ces triangles sont aussi
les plus proches de la source de lumière (par construction), on
veut conserver au minimum le zbuffer, ie la distance entre la
source de lumière et le triangle visible / éclairé.
la création / configuration d'un framebuffer est assez directe,
mais il y a bien sur quelques détails techniques à régler, cf "rendu
multi-passes". vous pouvez utiliser les utilitaires de texture.h
pour créer simplement les textures nécessaires, cf
make_depth_texture() ou make_vec3_texture(), etc. elles sont
faites exactement pour ça !
au final, votre code ressemblera à :
GLuint shadow_map=
make_depth_texture( /* unit */ 0, /* width */ 256, /* height */
256 );
GLuint framebuffer= 0;
glGenFramebuffers(1,
&framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, /* attachment */
GL_DEPTH_ATTACHMENT, shadow_map, /* mipmap */ 0);
// verification de la
configuration du framebuffer
if(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) !=
GL_FRAMEBUFFER_COMPLETE)
return
"error";
// nettoyage...
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
pour dessiner dans le framebuffer, il ne reste plus qu'à le
sélectionner (avant de dessiner la scene), mais attention aux
paramètres implicites du draw() !
(par exemple les dimensions de l'image... cf glViewport())
exercice 3 : et maintenant les ombres !!
et voila, tout est pret !! il ne reste plus qu'à dessiner la
scène depuis le point de vue de la camera et à écrire le test qui
vérifie qu'un point (vu par la camera) est plus près ou plus loin
que le triangle éclairé par la source de lumière. les détails de
la projection et des transformations sont dans "decals
et projection de textures" / section "finir le calcul :
projetter le décal"
attention : dans le shader, la fonction texture(shadow_map,
uv)
renvoie un vec4, la distance stockée dans la texture
se trouve dans la composante .x ou .r (et pas .z qui sera
toujours 0...)
exercice 4 : et maintenant ? des ombres propres !!
et voila ça marche !
ou pas, c'est quand même moche, non ?
argh, mais pourquoi ??
le zbuffer stocke une distance par pixel :
mais cette profondeur est constante : tous les points du triangle
qui se projettent sur le même pixel ont la même distance, et le
triangle n'est plus vraiment une surface, mais une approximation :
et lorsque l'on dessine la scène depuis un autre point de vue, on
utilise la distance d'un autre point du triangle, et ces distances
ne sont pas tout à fait identiques... donc il va falloir modifier
le test...