M2 - Images
TP 1 - Affichage efficace
mise à jour gKit b69 17/12/2010
- nouvelle version des classes GLxShaderProgram, plus simples et
plus
souples, et debuggées surtout,
- shadercc : un compilateur de
shaders pour vérifier que
les shaders compilent avant de lancer l'application +
intégration a scite, par exemple, ou gedit.
Prise en main
installez gKit et parcourez la doc.
Ce qu'il faut retenir : la classe gk::App
permet de construire une application openGL, elle crée une
fenetre et un contexte de rendu openGL et permet également de
gérer les évènements claviers, souris, joysticks,
etc facilement.
Pour construire une application, il faut dériver la classe
gk::App et redéfinir les méthodes suivantes :
- int init( ) : pour
charger et initialiser les objets, les vertex buffers, les shaders, etc.
init( ) doit renvoyer 0 si tout c'est bien passé, ou -1 en cas
d'erreur.
- int quit( ) : pour
libérer les ressources allouées dans init( ).
- int draw( ) : cette
fonction est appelée régulièrement pour dessiner.
draw( ) peut renvoyer 0 pour terminer l'application, ou 1 pour
continuer à être appelée.
L'application minimale que vous pouvez modifier pour réaliser le
tp se trouve dans glmain.cpp.
Contrôle au clavier, souris, joystick :
La fonction key( code )
renvoie l'état d'une touche : 1 si la touche est appuyée,
0 si la touche est relachée.
Cette fonction renvoie une référence sur la valeur, ce
qui permet de la modifier, par exemple, key('a')= 0.
Pour tester l'état d'une touche comme les fléches de
directions, il suffit d'utiliser les codes SDLK_xxx
correspondants. Il est également possible de connaître
l'état des touches spéciales : shift, control, etc : SDL_GetModState(
), les codes SDLK_xxx associés sont en bas de la page des
codes SDLK_xxx.
Il
est
également
possible de modifier l'état de ces
touches spéciales avec SDL_SetModState(
).
La gestion de la souris se fait directement en utilisant les fonctions
de libSDL : SDL_GetMouseState(
), SDL_GetRelativeMouseState(
).
Le manuel de programmation complet de libSDL est également disponible.
Partie 1 : Affichage avec vertex buffer / index buffer.
Les vertex et index buffers seront donc crées et
initialisés dans la méthode init( ).
Quelques méthodes utiles de gk::Mesh
:
- positions des sommets d'un objet : gk::Mesh::positionCount( ) et
gk::Mesh::positions( ),
- indices : gk::Mesh::indiceCount( ) et gk::Mesh::indices( ),
- normales : gk::Mesh::normalCount( ) et gk::Mesh::normals( ).
Si les normales ne sont pas disponibles, il est possible de les
calculer avec la méthode gk::Mesh::buildNormals( ).
En résumé, pour charger un objet et
récupérer ses normales :
gk::Mesh *mesh= gk:MeshIO::read("xxx.obj");
if(mesh->normalCount() != mesh->positionCount())
mesh->buildNormals();
Autre remarque : utilisation de gk::Transform
pour construire les matrices de transformation openGL.
Utilisez la méthode gk::Transform::matrix( ) pour obtenir la
matrice directe et gk::Transform::inverseMatrix( ) pour la matrice
inverse. Ne pas oublier qu' openGL utilise une convention
différente pour représenter ses matrices, il faut
impérativement utiliser glLoadTransposeMatrixf( ), et
glMultTransposeMatrixf( ).
exemple :
glMatrixMode(GL_PROJECTION);
glLoadTransposeMatrixf( gk::Perspective(50.f, 1.f, 1.f,
1000.f).matrix() );
exercice :
Chargez un objet et affichez-le en utilisant un vertex buffer et un
index buffer.
Structurez correctement votre code, en utilisant les methodes init( ),
quit( ) et draw( ).
La méthode draw( ) commence par redimensionner et effacer le
buffer de dessin. Ensuite, décrire la projection de la
caméra, puis pour chaque objet à afficher :
décrire la matrice local vers camera (modelview), et affichez
l'objet.
Derniere remarque : pensez à désactiver tous les
états openGL modifiés.
Partie 2 : Afficher plusieurs objets.
exercice 1 : description hiérarchique de scène.
Utilisez directement la classe gk::Scene
et dérivez gk::ISceneObject
pour afficher un ensemble d'objets.
exercice 2 : visibilité.
Testez la visibilité de la boite englobante d'un objet avant de
l'afficher.
exercice 3 : visibilité hiérarchique.
Construisez une scène étendue composée d'un grand
nombre d'objets : une grille de bigguy, par exemple.
Dans ce cas, la
camera ne peut observer qu'un nombre limité d'objets, comment
les identifier rapidement ?
Proposez une solution simple utilisant la classe gk::Scene.
Proposez
une solution plus efficace, a priori basée sur une
hiérarchie, pourquoi la classe gk::Scene n'est elle pas
vraiment adaptée ? existe-t-il une modification simple ?
exercice 4 : minimiser les changements d'états ==
économiser openGL.
Lisez la présentation gdc 2003 : "batch,
batch,
batch"
Quelle conclusion peut on en tirer ?
Quelles conséquences sur la manière de représenter
un objet et d'afficher un groupe d'objets ?
Proposez une solution simple mais plus efficace que la version actuelle.
Annexe : shadercc
Dans l'archive gKit_b69 se trouve un programme
shdercc, compilez-le et copiez le à la racine de votre compte,
ou dans un repértoire local/bin.
Pour compiler vos shaders et vérifier
qu'il
n'y a pas d'erreurs de syntaxe et de casts avant
d'éxécuter votre programme complet :
~/repertoire/shadercc -c shader.vsl
Pensez à ajouter #version 120 (pour
opengl2) ou #version 330
(pour opengl 3.3) au
début du
source des shaders pour détecter le maximum d'erreurs /
warnings. shadercc
affiche également la ligne du source correspondant à
l'erreur détectée en utilisant un format
d'erreur standard,
résultat, il s'intègre facilement à un
éditeur ...
Démonstration :
Intégration de shadercc dans SciTE
Ouvrez les propriétés utilisateur :
menu 'Options', option 'Open User Options File', copiez -
collez les lignes suivantes :
# extensions de fichiers
reconnues
file.patterns.cpp=*.c;*.cpp;*.cs;*.h;*.hpp;*.fsl;*.vsl;*.gsl;*.esl;*.csl
# compilation des shaders glsl
shadercc=shadercc -c
$(FileNameExt)
command.compile.*.vsl=$(shadercc)
command.compile.*.gsl=$(shadercc)
command.compile.*.csl=$(shadercc)
command.compile.*.esl=$(shadercc)
command.compile.*.fsl=$(shadercc)
Enregistrez le fichier, fermez SciTE, rouvrez-le et
éditez un shader (utilisez une extension .v?? pour un vertex
shader et .f?? pour un fragment shader). Dans le menu Tools,
l'option Compile est
maintenant disponible (Ctrl-F7). Appuyez ensuite sur F4 pour visualiser
les différentes erreurs (éventuelles, bien sur !).
Intégration de shadercc dans Gedit
ajoutez le plug-in "external tools" à gedit,
menu edit, preferences, plugins.
ouvrez le menu Tools / External Tools, option Manage
external tool.
creez un
nouvel outil (bouton +), appelez-le shadercc, il ne reste plus
qu'à le
configurer.
copiez-collez le script suivant dans la zone
commande :
#!/bin/sh
$HOME/repertoire/shadercc -c
$GEDIT_CURRENT_DOCUMENT_NAME
et sélectionnez les options d'exécution :
input : current
document,
ouput : display in bottom pane,
applicability : all documents
lorsqu'une erreur est affichée dans la
console ou s'exécute shadercc, cliquez-dessus pour éditer
la ligne correspondante dans vos sources.