L'objectif du tp est de savoir afficher plusieurs objets, placés
dans une scène, de les manipuler et de les observer.
remarque : toute la doc
est la
Pour dessiner un objet, un pipeline graphique, comme openGL, à
besoin de quelques informations : les coordonnées des sommets des
triangles de l'objet, sa position et son orientation dans le
monde, la position et l'orientation de la camera dans le monde et
les 2 shaders qui projettent les sommets, et calculent une couleur
pour chaque pixel sur lequel se dessine chaque triangle.
Dans un premier temps, la première difficulté est de comprendre
comment manipuler les transformations pour placer et orienter les
objets, ainsi que comment placer et orienter une camera.
L'objet peut etre décrit "à la main" en construisant un objet
Mesh triangle par triangle, ou en chargeant directement un fichier
.obj exporté par blender, par exemple.
Comment ca marche ? il suffit de fournir les coordonnées des
sommets de chaque triangle. Par exemple, pour un triangle abc,
avec les sommets :
Point a= Point(0, 0, 0);
Point b= Point(1, 0, 0);
Point c= Point(0, 1, 0);
créer un objet Mesh :
Mesh objet(GL_TRIANGLES);
objet.vertex(a);
objet.vertex(b);
objet.vertex(c);
Pour afficher cet objet, il faut créer
une application openGL, une camera, des shaders, etc. Pour
démarrer rapidement, le plus simple est de modifier tuto7_camera.cpp.
La création des objets à afficher est faite dans la méthode
init().
Il est aussi direct de charger un objet .obj exporté par blender,
par exemple le résultat du premier tp :
objet= read_mesh( "..." );
L'affichage de l'objet est réalisé dans la méthode render( ), 60
fois par seconde :
draw(objet, Identity(), camera());
Cette fonction crée tous les objets openGL nécessaires pour dessiner cet objet avec des shaders de base / par défaut. Ses paramètres sont :
draw( const Mesh& objet, const Transform& model, Orbiter& camera );
l'objet à dessiner, ou le placer dans le monde, cf model, et quel
point de vue / camera utiliser, cf camera.
Pour dessiner l'objet à un autre endroit dans le monde, il faut
modifier la transformation model. Pour le déplacer : Translation(
x, y, z ) par exemple, pour le faire tourner : cf RotationX(),
RotationY(), RotationZ(), etc.
Ces fonctions qui renvoient une matrice de transformation sont
documentées dans mat.h.
Affichez plusieurs objets (ou plusieurs fois le même objet...) à
des endroits différents du monde.
Vous pouvez animer leur transformation en fonction du temps, global_time()
renvoie le temps écoulé, en millisecondes, depuis le démarrage de
l'application.
Commnent placer un objet dans le monde puis le faire tourner sur lui meme ? Il faut composer 2 transformations : une translation et une rotation :
Comment placer un objet par rapport à un autre ? par exemple, placer un cube à droite d'un objet, faites tourner l'objet, le cube doit tourner autour de l'objet ? C'est encore une composition de transformations. Le cube est placé par rapport au repère de l'objet, si le repère de l'objet change, la position du cube dans le monde change, mais pas par rapport à l'objet. Il suffit de représenter la position du cube par rapport à l'objet par une Transform, et la position de l'objet dans le monde par une autre transform. On obtient la position du cube dans le monde en composant les 2 transformations.Transform t1= Translation(x, y, z) * RotationY(angle);
Transform t2= RotationY(angle) * Translation(x, y, z);
Placez un petit cube par rapport au personnage / objet de la
partie précédente, en arrière et au dessus qui "regarde" l'objet.
On souhaite utiliser la position de ce petit cube comme camera,
comment faire ?
indication : transformations standards : model permet de
placer un objet dans le monde, view permet de placer le même objet
dans le repere camera. Donc Inverse(view) permet de placer un
objet dans le monde connaissant sa position dans le repere camera.
Autrement dit, view est l'inverse de la transformation qui permet
de placer une camera dans le monde... vous savez placer un objet
dans le monde, donc vous savez utiliser cet objet comme camera.
Utilisez une autre version de draw pour dessiner les objets :
La camera renvoie les transformations view et projection, cf Orbiter::view() et Orbiter::projection().
draw( const Mesh& objet, const Transform& model, const Transform& view, const Transform& projection );
Draw( objet, model, camera )
est équivalent à :La projection perspective classique est renvoyée par Perspective(), cf mat.h :Transform view= camera.view();
Transform projetion= cmaera.projection();
draw(objet, model, view, projection);
Transform projection = Perspective(45, float(window_width()) / float(window_height()), 0.01, 100);
Avant de modifier l'application pour utiliser des shaders, il est plus simple de les écrire et de les tester avec shader_kit. Mais il faut respecter 3 conventions :
un passage par shader
et GLSL, est probablement nécéssaire...
Le pipeline openGL utilise un vertex shader et un fragment
shader, shader_kit les regroupe dans un seul fichier .glsl :
#version 330
#ifdef VERTEX_SHADER
layout(location= 0) in vec3 position;
//!! attention layout(location= 0) obligatoire !!
uniform mat4 mvpMatrix; //!! attention mat4 mvpMatrix obligatoire !!
void main( )
{
gl_Position= mvpMatrix * vec4(position, 1);
}
#endif
#ifdef FRAGMENT_SHADER
out vec4 fragment_color;
void main( )
{
fragment_color= vec4(1, 0.6, 0, 1);
}
#endif
Une fois que les shaders fonctionnent dans shader_kit, que
faut-il faire pour les utiliser dans l'application ? cf tuto9
et éventuellement tuto10...