mettez à jour gkit3, puis dans le répertoire de gKit3, clonez gKit3GL, la partie openGL de gKit :
cd gkit3
git pull
premake5 gmake
git clone https://forge.univ-lyon1.fr/JEAN-CLAUDE.IEHL/gkit3GL
cd gkit3GL
premake5 gmake
make tp1
bin/tp1
vous pouvez compiler l'exemple tp1 et vérifier que tout est correct.
pour windows, et linux, il faut installer les librairies openGL, les différentes étapes sont résumées sur le dépot.
pour dessiner un objet avec openGL, il faut créer une fenètre avec les bons paramètres pour qu'openGL puisse dessiner dedans. cettte étape n'est pas très interressante, mais surtout elle est différente d'un système à l'autre, ie X11 ne crée pas les fenêtres de la même manière que Wayland, ni que Windows et encore moins que Macos, ou Android ou WebGL, ou, etc...
on va donc utiliser une librairie pour faire ça de manière portable, par exemple : SDL.
l'utilisation de la librairie n'est pas très interressante non plus, il suffit de lire la doc sur la création des fenêtres et du contexte openGL et d'appeler les fonctions dans le bon ordre. et comme c'est toujours la même chose, il n'a pas été trop difficile de créer 2 fonctions utilitaires : create_window() et create_context() définies dans window.h
pour les curieux, il y a un résumé dans la doc en ligne, cf écrire une application openGL
maintenant que la fenêtre est créée, il suffit de dessiner dedans et de recommencer tant que l'application existe...
mais pour savoir que l'utilisateur veut fermer l'application, il faut le
tester explicitement. ca s'appelle la gestion des évènements...
c'est un peu barbare, mais ce n'est pas compliqué, par contre, il y a pleins d'évènements, cf la doc.
pour savoir si la souris vient de cliquer sur le bouton 'fermer' de
la fenêtre de l'application, il faut surveiller l'évènement
SDL_WindowEvent, on peut aussi surveiller le clavier, ie
SDL_KeyboardEvent, pour détecter que la touche 'echap' est enfoncée ou
que 'ctrl'+'w' / 'ctrl'+'q' est enfoncé. ie toutes les manières
classiques de fermer la fenêtre d'une application.
c'est SDL_PollEvent() qui permet de récupérer les évènements et de réagir, le code ressemblera à :
bool close= false;
// recuperer un evenement a la fois
// PollEvent() renvoie faux lorsque tous les evenements ont ete traite
SDL_Event event;
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
close= true; // sortir si click sur le bouton 'fermer' de la fenetre
else if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)
close= true; // sortir si la touche esc / echapp est enfoncee
}
projets/tp1.cpp
est un exemple complet et fonctionnel.projets/tp1.cpp
doit être un peu plus claire. Window window= create_window(1024, 576);
Context context= create_context(window);
std::vector<Point> positions;
std::vector<unsigned> indices;
// lit le fichier, et recupere un
tableau de positions de sommets et un tableau d'indice des sommets des
triangles de l'objet
if(!read_indexed_positions("../data/robot.obj", positions, indices))
return false; // erreur de lecture
count= indices.size();
// utilitaire. alloue de la memoire gpu e
t transfere les tableaux positions et indices sur le gpu.
necessaire pour dessiner...
vao= create_buffers(positions, indices);
bool close= false;
while(!close)
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
close= true; // sortir si click sur le bouton 'fermer' de la
fenetre
else if(event.type == SDL_KEYDOWN && event.key.keysym.sym ==
SDLK_ESCAPE)
close= true; // sortir si la touche esc / echapp est enfoncee
}
// dessiner
draw();
// presenter / montrer le resultat
SDL_GL_SwapWindow(window);
}
release_buffers(vao);
/* utilitaire. dessine des TRIANGLES avec count indices (ie indices/3 triangles...)
en appliquant les transformations model, view et projection aux coordonnées des sommets.
*/
draw(vao, GL_TRIANGLES, count, model, view, projection);
pour dessiner un objet, il faut le placer dans le monde, ainsi que
placer et définir une camera pour l'observer. il y a plusieurs solutions
pour décrire ces transformations / ces changements de repères, mais les
api 3d comme openGL, Vulkan, DirectX ou Metal imposent d'utiliser des
matrices 4x4 homogènes. c'est un outil qu'il faut apprendre à manipuler.
pour placer un objet dans le monde, on modifie la matrice model :
avec une translation, une rotation, un changement de taille, ou la
composition de plusieurs transformations. mat.h définit les transformations usuelles, cf Translation, Rotation, Scale...
pour décrire une camera, on utilise aussi une matrice pour représenter le passage entre le repère du monde et le repère de la camera. on construit ce changement de repère comme pour placer les objets dans le monde, ie avec des translations, rotations, etc. la projection réalisée par la camera est également décrite par une matrice de projection, cf Perspective, par exemple.
la suite de la lecture dans la doc en ligne : premiers objets et transformations, à partir de la section "placer un objet dans le monde". les parties précédentes ne sont pas adaptées à gkit3.
remarque : la doc et ses
exemples sont adaptés à gkit2light, il y a donc des différences. par
exemple, la classe Mesh n'existe plus dans gkit3, elle est remplacée par
la fonction create_buffers(). les paramètres de la fonction draw(), qui
affiche les objets, sont également différents.
voici comment adapter les exemples de la doc, par exemple le 1er :
key_state()
et clear_key_state()
, il faut utiliser la fonction utilitaire de gestion d'évènements events() définie dans window.h. projets/tp3.cpp
donne un exemple complet qui utilise key_state() pour déplacer un objet.que doit on calculer ?
\[
L_r(p, \vec{o}) = \frac{\mathrm{color}}{\pi} \cdot L_i(p, \vec{l}) \cdot \cos \theta
\]
il suffit de calculer le cosinus de l'angle entre la normale en p et la direction vers la lumière, et de se rappeler que les calculs sur les points et les vecteurs doivent se faire avec des coordonnées dans le même repère.
en résumé, il faut connaitre, dans le même repère :
quel shader fait le calcul ? et oui, il faudra probablement transformer certaines coordonnées.
solution 1 : vertex shadercomment récupérer toutes ces informations
dans le vertex shader ? une fois que les coordonnées de tous ces points
et vecteurs sont connues dans le même repère, il ne reste plus qu'à
faire le calcul...
dernière question, comment transmettre la couleur que l'on vient de calculer au fragment shader ? et pourquoi vouloir faire ça ? y-a-t-il une autre solution ?
solution 2 : fragment shaderle résultat est-il différent ? ou, pourquoi ça marche ?
quelle est la meilleure solution ?