QuÕest ce que lÕInformatique Graphique ? Exemples ...
Transcript of QuÕest ce que lÕInformatique Graphique ? Exemples ...
Introduction à l’infographie
Stéphane ConversyENAC/CENA - [email protected]
Éléments:Nicolas Roussel, Projet InSitu, Université Paris-Sud
Introduction
Qu’est ce que l’Informatique Graphique ?
Modélisation– structures de données pour la représentations de scènes 2D ou 3D
Rendu– construction d’images 2D à partir de modèles 2D ou 3D
Animation– simulation de changements au cours du temps
Interaction– avec un ou plusieurs utilisateurs
Exemples d’applications
Affichage d’informations– cartographie
– données statistiques
– imagerie médicale
– visualisation scientifique (biologie, mécanique, etc.)
MillionVis, J-D Fekete & C. Plaisant, HCIL Universityof Maryland, 2002
Exemples d’applications
Conception– poignées de portes– voitures– architecture– VLSI
DataCADCATIA (Prost Grand Prix)
Exemples d’applications
Simulation et animation– simulateurs de conduite, de vol, d’assemblage– dessins animés, films– jeux (marché supérieur au cinéma)– œuvres d’art
"Impressions of San Francisco »P. Litwinowicz, Apple Computer, SIGGRAPH 97
"Toy Story 2", Disney / Pixar, 1999
"Star Wars Episode II", Lucasfilm, 2002
Flight simulator, Microsoft, 2002
Exemples d’applications
Interfaces graphiques (voir mon autre cours…)
Quels sont les problèmes que l’on se pose ?
Que veut-on afficher ?– Primitives graphiques
• Formes, transparence, transformation, style
Comment les afficher ?– Algorithmes
• Tracé, remplissage, transparence
Comment s’en servir ?– Outils, API
• Photoshop/Illustrator, opengl, svg…
Qu’est-on capable d’afficher pour l’interaction ?– Services pour l’interaction
– Performances
Overview
Description d’une scène– Scene-graph
– Attributs de haut-niveau
Librairie graphique
Algorithmes fondamentaux d’IG– Rasterisation
– Discrétisation
– Clipping
– masking
Photoshop,illustrator,3DStudio
SVG, Inventor
Java2D,GDI
OpenGL, DirectX
Exemples d’algorithmes fondamentaux
Algorithme de tracé de ligne par point médian
But: allumer les pixels les plus proches d’une ligne passant pardeux pixels donnés(rasterisation)
(x0,y0)
(x1,y1)
1er octant
Une première approche
y = ax+b
a = (y1-y0)/(x1-x0)
b = y0
Pour x = x0 à x1:
y = arrondi(ax+b)
allumerPixel(x,y)
À chaque itération– calculs en virgule flottante
– calculs d’arrondi
Point Médian
Points médians
Solution à base de point médian
Equation implicite de la droite:
F(x,y) = ax + by + c
a = (y1-y0)
b = (x0-x1)
c = y0
Propriétés:
F(xi,yi) > 0 : point (xi,yi) en dessous de la droite
F(xi,yi) = 0 : point (xi,yi) appartient à la droite
F(xi,yi) < 0 : point (xi,yi) au dessus de la droite
Algorithme du point médian
Après avoir choisi un pixel (xi,yi), calculer la position du point médiansuivant (xi+1, yi+ _), et décider du prochain pixel à allumer
(xi,yi)
(xi+1,yi+ _)
(xi,yi)
(xi+1,yi+ _)
(xi,yi)
(xi+1,yi+ _)
E
NE
Calculs préliminaires
Position du point médian correspondant à (xi,yi):di = F(xi+1,yi+_ ) : « valeur de décision »
Calcul incrémental :si choix E: di+1 = F(xi+2, yi+_) = di + a– incrE= a
si choix NE: di+1 = F(xi+2, yi+3/2) = di + a+b– incrNE=a+b
d0 = F(x0+1,y0+1/2) = F(x0,y0)+a+b/2 = a+b/2Choix E ou NE, test du signe
d>0 ? ! 2d>0On recalcule les incréments:
incrE = 2aincrNE = 2(a+b)
Algorithme du point médian
a = y1-y0
b = x0-x1
d = 2a+b
incrE = 2a
incrNE = 2(a+b)
x = x0
y = x1
Tant que x<=x1:
allumerPixel(x,y)
++x
si d <= 0: d += incrE
sinon: d+=incrNE; ++y
Calcul en entiers !Que des additions !
Courbe de bézier
Définie par 4 points:P0 et P3 extrémitésP1 et P2 définissent les tangentes aux extrémités
-1 3 -3 1 P0 3 -6 3 0 P1B(t) = [t3 t2 t 1] -3 3 0 0 P2 1 0 0 0 P3
x(t) = (-x0+3x1-3x2+x3) t3 + (3x0-6x1+3x2) t2 + (-3x0+3x1)t + x0ou
B(t) = (1- t3)P0 + 3t(1-t)2 P1 + 3t2(1-t) + t3
– Polynômes de Bernstein
P0
P1 P3
P2
Discrétisation d’une courbe de bézier
Par subdivision: P = Q + T
On subdivise jusqu’à une « précision suffisante »
P0
P1 P3
P2
G0
G1 D3
D2
G2
G3
D0
D1
Subdivision d’une courbe de Bezier
G0 8 0 0 0 P0
G1 4 4 0 0 P1
G2 = 1/8 2 4 2 0 P2
G3 1 3 3 1 P3
D0 1 3 3 1 P0
D1 0 2 4 2 P1
D2 = 1/8 0 0 4 4 P2
D3 0 0 0 8 P3
dessineBezier(courbe,e):
si rectiligne(courbe,e)
dessineSegment(courbe.P0,courbe.P3)
sinon
subdivise(courbe,gauche,droite)
dessineBezier(gauche,e)
dessineBezier(droite,e)
Avantage: indépendant de la forme de la courbe
Inconvénient: calcul du test de précision coûteux
Méthode itérative
Evaluation de x(t) et y(t) pour 0<=t<=1
Représentation de Horner d’un polynôme:
f(t) = at3+bt2+ct+d=(((at+b)t+c)t+d
3 mul et 3 add
Différence en avant avec dt constant:
f(t+dt) = f(t)+df(t)
df(t) = 3at2dt+t(3adt2+2bdt)+adt3+bdt2+cdt
Même technique avec df(t) et d2f(t):
d2f(t) = d(df(t)) = df(t+dt)-df(t) = 6adt2t+6adt3+2bdt2
d3f(t) = d(d2f(t)) =d2f(t+dt)-d2f(t) = 6adt3 = cte
Algo itératif
fn+1 = fn + dfndfn = dfn-1 + d2fn-1
d2fn-1 = d2fn-2+d3fn-2
Conditions initiales:
f0=d
df0=adt3+bdt2+cdt
d2f0=6adt3+2bdt2
d3f0=6adt3
dessineBezierIter(courbe,n):
x=courbe.P0.x
init()
pour i=0 à n:
x += dx
dx += d2x
d2x += d3x
tracerSegment(x,y)
6 add au lieu de 3 add et 3 mul
Résultat dépendant de la forme
API de plus haut-niveau pour le tracé de ligne
Avec OpenGL:– direct mode
glBegin(GL_LINES);
glVertex2i(x0,y0);
glVertex2i(x1,y1);
glEnd();
Avec SVG:
svgDoc.add(new SVGLine(x0,y0,x1,y1))– Retained mode
Images
Représentation des images
1000101001001010001110011111000011001010
gggggggggggggggggggggggggggggggggggg
rgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgbrgb
bitmapgrayscale
rgb packed
g sur 8,16,24 bits…
bbbbbbbbbbbbbbbbbbbbbbbb
gggggggggggggggggggggggg
rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
rgb planarrrrrrrrrrrrrrrrrrrrrrrrrggggggggggggggggggggggggbbbbbbbbbbbbbbbbbb
indexéiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
0: rgb1: rgb2: rgb3: rgb….
palette
rgbargbargbargbargbargbrgbargbargbargbargbargbrgbargbargbargbargbargbrgbargbargbargbargbargb
rgba
en mémoire...
Opérations sur les images
Filtres– Définition super générale: traitement mathématique des pixels
d’une image• Généralement, opération impliquant les pixels voisins d’un pixel
donné
fff
fff
fff
filtre
ggggggggg
ggggggggg
ggggggggg
ggggggggg
image
hhhhhhhhh
hhh
ggggggggg
ggggggggg
ggggggggg
ggggggggg
fff
fff
fff
hi,j = fk-1,l-1*gi-1,j-1+fk,l-1*gi,j-1+… ->convolution
Exemples de filtres
Box filter– Filtre passe-bas
– Blur
Filtre de Sebel– Filtre passe-haut
– Détection de contours
111
111
111
-1 -2 -1
0 0 0
1 2 1
1/9 x
Opérations sur les images
Histogramme– Occurrence d’une couleur dans une image
g
nb
g
nb
g
nb
g
nb
sombre claireg
nb
peu contrastéecontrastée
0 256
Format des images
Sans perte:– PNG
• format libre• Indexé, grayscale, rgba, entrelacé• Mng pour l’animation• Compressé à la zlib
– GIF• Indexé, un index pour l’opacité• Gif animé• Compressé à la zlib
Avec perte:– Jpeg– Transformée de Fourier et élimination des basses fréquences
OpenGL
Quelques références
Le rouge : OpenGL Programming Guide, 3rd Edition
Le bleu : OpenGL Reference Manual, 3rd Edition
E. Angel. OpenGL: a primer. Addison Wesley, 2002.
D. Shreiner, E. Angel & V. Shreiner. An interactive introduction to
OpenGL programming. Cours donné à la conférence ACMSIGGRAPH 2001.http://www.opengl.org/developers/code/s2001/
Quelques pointeurs
Le site Web d’OpenGLhttp://www.opengl.org/
Le site Web de Mesahttp://mesa3d.org/
Les tutors de Nate Robinshttp://www.cs.utah.edu/~narobins/opengl.html
Qu’est-ce qu’OpenGL ?
Une interface de programmation (API) graphique– indépendante du langage de programmation– indépendante du système d’exploitation– indépendante du système de fenêtrage
Caractéristiques– simplicité– performance et qualité du rendu
Implémentation– logicielle (ex : Mesa)– matérielle (ex : cartes NVIDIA ou ATI les plus récentes)– hybride…
Comment fonctionne OpenGL ?
OpenGL sait dessiner des points, des lignes, des polygones convexes etdes images
Ces primitives sont définies par des ensembles de vertex et renduesdans un framebuffer
Le rendu des primitives dépend de nombreuses variables d’état (matricede transformation, couleur, matériau, texture, éclairage, etc.)
OpenGL ne sait pas ce que c’est qu’une souris, un clavier, une fenêtreou même un écran…
3D et 2D
L’architecture pipeline d’OpenGL Quelques autres APIs utiles
Pour quelques fonctions de plus : GLU (OpenGL Utility Library)
– NURBS, tessellations, formes quadriques (cylindres, etc.)
– GLU fait partie d’OpenGL
Pour accéder au système de fenêtrage– AGL (Mac OS), GLX (X Window), WGL (Windows)
Pour se simplifier la vie : GLUT (OpenGL Utility Toolkit)
– accès au système de fenêtrage, au clavier, à la souris
Autres toolkits possibles: SDL, GTK, QT, Cocoa, etc.
Exemple : OpenGL et Mac OS X
rendu matériel rendu logiciel
Application
CGL GL GLU
AGL(Carbon)
GLUT(Cocoa)
Quelques remarques générales
Un certain nombre de types de données sont définisGLfloat, GLint, GLenum par exemple
Souvent, le nom de la fonction indique le type des paramètresattendus
Exemple : glVertex3fv3 : 3 coordonnées (2, 3 ou 4)f : données flotantes (byte, unsigned byte, short, unsigned short, int,
unsigned int, float ou double)v : données passées sous forme de tableau
Toute les fonctions sont correctement documentées…
Pour commencer
Inclure au minimum dans votre programme#include <GL/glut.h>
et éventuellement#include <GL/glu.h>#include <GL/glext.h>#include <GL/gl.h>
Structure générale d’une application GLUT– création d’au moins une fenêtre– initialisation de quelques variables d’états– enregistrement de quelques callbacks pour l’animation et/ou
l’interaction– entrée dans la boucle de gestion des événements
Exemple : mini.c
#include <GL/glut.h>
void display(void) {
glClear(GL_COLOR_BUFFER_BIT) ;
glRectf(-0.3,-0.3,0.3,0.3) ;
glutSwapBuffers() ;
}
void main(int argc, char **argv) {
glutInit(&argc, argv) ;
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE) ;
glutCreateWindow(argv[0]) ;
glClearColor(0.0,0.0,1.0,1.0) ;
glutDisplayFunc(display) ;
glutMainLoop() ;
}
Compiler mini.c sous Linux
Dans un terminalcc mini.c -o mini -lgl -lglu -lglut -lm -lX11
Pour les entêtes (*.h) et les librairies (libGL* et autres)– si ça ne marche pas, ajouter -I/usr/X11R6/include et
-L/usr/X11R6/lib
– sous Mac OS X, c’est un peu plus compliqué…
– sous Windows… je ne sais pas !
glxinfo vous dit quelle implémentation d’OpenGL vous utilisez
Un Makefile n’est pas inutile…
Exemple de Makefile pour Linux
TARGETS = mini
CFLAGS = -o3
CPPFLAGS = -I/usr/X11R6/include
LDFLAGS = -L/usr/X11R6/lib
LDLIBS = -lGL -lGLU -lglut -lm -lX11
all: $(TARGETS)
clean:
rm -f *~ *.o
distclean: clean
rm -f $(TARGETS)
Exemples d’utilisation de callback : timer
void display(void) {
glClear(GL_COLOR_BUFFER_BIT) ;
glLoadIdentity() ;
glRotatef(angle,0,0,1) ;
glRectf(-0.3,-0.3,0.3,0.3) ;
glutSwapBuffers() ;
}
void animate_timer(int theTimer) {
angle ++ ;
glutPostRedisplay() ;
glutTimerFunc(100, animate_timer, theTimer) ;
}
GLfloat angle = 0.0 ;
void main(int argc, char **argv) { glutInit(&argc, argv) ; glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE) ;
glutCreateWindow(argv[0]) ;
glClearColor(0.0,0.0,1.0,1.0) ;
glutDisplayFunc(display) ; glutTimerFunc(100, animate_timer, 0) ;
glutMainLoop() ;}
Primitives géométriques
Les primitives géométriques d’OpenGL
GL_QUAD_STRIP
GL_POLYGON
GL_TRIANGLE_STRIP GL_TRIANGLE_FAN
GL_POINTS GL_LINES GL_LINE_LOOPGL_LINE_STRIP
GL_TRIANGLES GL_QUADS
Dessin d’une primitive
Les primitives sont décrites par un bloc d’instructions délimité parglBegin et glEnd
Ce bloc contient généralement une liste de vertex
Exemple :glBegin(GL_LINE_LOOP) ;
glVertex2f(-0.5, -0.5) ;
glVertex2f(0.5, -0.5) ;glVertex2f(0.5, 0.5) ;
glVertex2f(-0.5, 0.5) ;
glEnd() ;
D’autres attributs peuvent être spécifiés en chaque sommet :couleur, normale, coordonnée de texture, etc.
Tutorial Shapes de Nate Robins OpenGL est une machine à états
De nombreuses variables d’états contrôlent l’éclairage, le placagede texture, le style de rendu des primitives, etc.
Ces variables peuvent être manipulées– glColor*, glNormal*, glTexCoord*
– glPointSize, glPolygonMode, glShadeModel
– glEnable, glDisable
– etc.
OpenGL est une machine à états
En modifiant les variables d’états, on peut changer le style derendu
Systèmes de coordonnées, transformations
L’analogie de la caméra
L’observateur regarde le monde à travers une caméra posée surun trépied
Il peut changer l’objectif ou ajuster le zoom de la caméra– définition de la projection (projection transformations)
Il peut déplacer et orienter le trépied– position et orientation de la vue (viewing transformations)
Il peut déplacer les objets observés (ou les faire déplacer)– transformation du modèle (modeling transformations)
Il voit les images dans le viseur ou sur un écran– agrandissement ou réduction de l’image affichée (viewport
transformations)
Systèmes de coordonnées et transformations
Différentes étapes menant à la formation d’une image– spécification de la géométrie des objets (world coordinates)
– spécification de la caméra (camera coordinates)
– projection (window coordinates)
– affichage dans un viewport (screen coordinates)
Chaque étape applique de nouvelles transformations
Chaque transformation correspond à un changement de systèmede coordonnées
Transformations affines
Les transformations affines préservent la géométrie– une ligne reste une ligne– un polygone reste un polygone– une quadrique reste… une quadrique
Exemples de transformations affines– translation– changement d’échelle (scale)– rotation– projection– glissement (shear)– toute composition de transformations affines
Programmation des transformations
OpenGL gère deux piles de matrices de transformation : l’une pour laprojection, l’autre pour la vue (et le modèle)
On passe d’une pile à une autre par l’instruction glMatrixMode enspécifiant GL_PROJECTION ou GL_MODELVIEW
La pile courante peut être manipulée par les instructions glPushMatrix etglPopMatrix
La matrice courante (i.e., le haut de la pile courante) peut être modifiéepar glLoadIdentity, glLoadMatrix*, glMultMatrix*
Des fonctions existent pour les translations, les changements d’échelleet les rotations (glTranslate*, glScale*, glRotate*)
Coordonnées homogènes
Un point en 3 dimensions est spécifié par 4 coordonnées
V = [x,y,z,w]
w=1 habituellement (sinon, diviser par w)seule la projection change w[x,y,z,0.0] définit une direction et non plus un point
Intérêt des coordonnées homogènes– les transformations s’expriment par des matrices 4x4– les compositions de transformations correspondent à des produits de
matrices
Attention à l’ordre des transformations…
sx 0 0
0 sy 0
0 0 1
1 0 tx
0 1 ty
0 0 1
cosa 0 0
0 sina 0
0 0 1
1 0 0
0 1 0
0 0 1
Projection et viewport
Projection en perspective– glFrustum(left, right, bottom, top, zNear, zFar)
– gluPerspective(fovy, aspect, zNear, zFar)
Projection parallèle orthographique– glOrtho(left, right, bottom, top, zNear, zFar)
– gluOrtho2D(left, right, bottom, top)
Viewport– défini par glViewport(x,y,width,height)
– sa taille correspond généralement à celle de la fenêtre
– attention : son aspect-ratio doit être identique à celui de latransformation de projection
Exemple 1 : projection orthogonale
void resize( int width, int height ) {
GLdouble aspect = (GLdouble) width / height;
GLdouble left = -2.5, right = 2.5;
GLdouble bottom = -2.5, top = 2.5;
glViewport( 0, 0, (GLsizei) w, (GLsizei) h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
if ( aspect < 1.0 ) {
left /= aspect;
right /= aspect;
} else {
bottom *= aspect;
top *= aspect;
}
glOrtho( left, right, bottom, top, near, far );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
Exemple 2 : projection perspective
void resize( int w, int h ) {
glViewport( 0, 0, (GLsizei) w, (GLsizei) h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60.0, (GLfloat) w / h, 1.0, 100.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( 0.0, 0.0, 5.0, /* œil */ 0.0, 0.0, 0.0, /* point observé */ 0.0, 1.0, 0.0 ); /* où est le ciel ? */
}
Exemple 3 : perspective et vue "polaire"
void resize( int w, int h ) {
glViewport( 0, 0, (GLsizei) w, (GLsizei) h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60.0, (GLfloat) w / h, 1.0, 100.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslated(0.0, 0.0, -distance);
glRotated(-twist, 0.0, 0.0, 1.0);
glRotated(-incidence, 1.0, 0.0, 0.0);
glRotated(azimuth, 0.0, 0.0, 1.0);
}
Exemple 4 : perspective et vue "pilote"
void resize( int w, int h ) {
glViewport( 0, 0, (GLsizei) w, (GLsizei) h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60.0, (GLfloat) w / h, 1.0, 100.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glRotated(roll, 0.0, 0.0, 1.0);
glRotated(pitch, 0.0, 1.0, 0.0);
glRotated(heading, 1.0, 0.0, 0.0);
glTranslated(-x, -y, -z);
}
Tutorial Projection de Nate Robins Tutorial Transformation de Nate Robins
Composition de transformation (1/2)
Problème : objet hiérarchique (ex : bras d’un robot)
Système de coordonnées local– chaque position dépend d’une position précédente
– chaque transformation déplace le système suivant
– post-multiplication des matrices ("à droite")
Solution– OpenGL fait ça naturellement !
Problème : déplacement par rapport à une origine absolue (ex : unsatellite autour d’une planète)
Système de coordonnées fixe– pré-multiplier les matrices… mais OpenGL post-multiplie
Solution– inverser l’ordre des transformations (ou modifier les matrices)
Composition de transformation (2/2)
Animation : le minimum à savoir
Dessiner avec un seul buffer
#include <GL/glut.h>
void display(void) {
glClear(GL_COLOR_BUFFER_BIT) ;
glRectf(-0.3,-0.3,0.3,0.3) ;
glFlush() ; // ou glFinish() ;
}
void main(int argc, char **argv) {
glutInit(&argc, argv) ;
glutInitDisplayMode(GLUT_RGB
| GLUT_SINGLE) ;
glutCreateWindow(argv[0]) ;
glClearColor(0.0,0.0,1.0,1.0) ;
glutDisplayFunc(display) ;
glutMainLoop() ;
}
image n affichée
image n+1 affichée
dessin de l’image n+1
dessin de l’image n+1 (suite)
Dessiner avec un double buffer
#include <GL/glut.h>
void display(void) {
glClear(GL_COLOR_BUFFER_BIT) ;
glRectf(-0.3,-0.3,0.3,0.3) ;
glutSwapBuffers() ;
}
void main(int argc, char **argv) {
glutInit(&argc, argv) ;
glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE) ;
glutCreateWindow(argv[0]) ;
glClearColor(0.0,0.0,1.0,1.0) ;
glutDisplayFunc(display) ;
glutMainLoop() ;
}
image n affichée
image n+1 affichée
dessin de l’image n+1
front back
Comment stopper une animation ?
Rappelvoid glutIdleFunc(void (*func)(void)) ;
void glutTimerFunc(unsigned int msecs, void (*func)(int value), int value) ;
Pour une animation basée sur glutIdleFunc– glutIdleFunc(NULL)– si la procédure associée traite plusieurs choses, utiliser des
variables d’état booléennes
Pour une animation basée sur glutTimerFunc– impossible d’annuler un timer enclenché– utiliser une variable d’état booléenne qui indique qu’au prochain
déclenchement, il ne faut pas le réenclencher
Exemple avec glutIdleFunc
void animate_idle(void) {
… // change la vue ou les objets
glutPostRedisplay() ;
}
void keyboard(unsigned char key, int x, int y) {
switch (key) {
case ‘a’:
glutIdleFunc(animate_idle) ;
break ;
case ’A':
glutIdleFunc(NULL) ;
break ;
}
}
void display(void) { …}
void main(int argc, char **argv) { glutInit(&argc, argv) ; glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE) ; glutCreateWindow(argv[0]) ;
glutDisplayFunc(display) ; glutKeyboardFunc(keyboard) ;
glutMainLoop() ;}
Exemple avec glutTimerFunc
void animate_timer(int theTimer) {
if (t_active) {
… // change la vue ou les objets
glutPostRedisplay() ;
glutTimerFunc(t_delay, animate_timer,
theTimer) ;
}
}
void keyboard(unsigned char key, int x, int y) {
switch (key) {
case ‘a’:
if (!t_active)
glutTimerFunc(t_delay, animate_timer, 0) ;
t_active = true ;
break ;
case ’A':
t_active = false ;
break ;
}
}
unsigned int t_delay = 100 ;bool t_active = false ;
void display(void) { …}
void main(int argc, char **argv) { glutInit(&argc, argv) ; glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE) ; glutCreateWindow(argv[0]) ;
glutDisplayFunc(display) ; glutKeyboardFunc(keyboard) ;
glutMainLoop() ;}
Idle ou timer ?
Avantage de glutTimerFunc– prévu pour pouvoir associer plusieurs timers à une même callback
(le dernier paramètre)
– on sait quand la callback sera exécutée
Inconvénient de glutIdleFunc– on ne sait pas quand la callback sera exécutée
– peut consommer tout le temps CPU…
Dernier point : si la fenêtre n’est pas visible, les animations nesont peut-être pas nécessaires (voir glutVisibilityFunc)
Couleur et opacité
Deux modes de gestion des couleurs
Mode indexé– (très) rarement utilisé
– de nombreuses choses ne marchent pas ou pas complètementdans ce mode (l’éclairage par exemple)
– ex : glutSetColor(0, 0,0,1) puis glIndexi(0) pour du bleu
Mode RGB ou RGBA– le plus courant
– rouge, vert, bleu et alpha sont spécifiés entre [0,1] ou [0,255]
– ex : glColor4f(0,0,1,1) pour du bleu
La composante alpha mesure l’opacité du fragment0.0 = transparent
1.0 = opaque
on a droit aux valeurs intermédiaires !
A quoi sert la composante alpha ?– simuler des objets transparents ou translucides
– composer des images
– faire de l’antialiasing
Remarque : l’alpha est ignorée si le blending est désactivé
Alpha : opacité/transparence
Suppression des parties cachées
Suppression des parties cachées
Problème : on veut éviter le résultat du milieu
Solutions– l’algorithme du peintre
– le test de profondeur
Solution 1 : l’algorithme du peintre
Dessiner les objets du plus éloigné au plus proche– solution très utilisé en 2D (la distance est facile à calculer)
– plus difficile en 3D
– quelques cas pathologiques
Solution 2 : le test de profondeur
Utilisation d’un deuxième buffer : le Z buffer (ou depth buffer)
Principe de fonctionnementif (pixel.z < depthBuffer(x,y).z) {
depthBuffer(x,y).z = pixel.z ;colorBuffer(x,y).color = pixel.color ;
}
Les valeurs sont comprises entre [0,1] (1=infiniment loin)
Le depth buffer doit être créé lors de la création de la fenêtre et ildoit être effacé de temps en temps…
Utilisation du depth buffer avec OpenGL
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
… // dessine ce qu’il faut
glutSwapBuffers() ;
}
void main(int argc, char **argv) {
glutInit(&argc, argv) ;
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH) ;
glutCreateWindow(argv[0]) ;
glClearColor(0.0,0.0,1.0,1.0) ;
glEnable(GL_DEPTH_TEST) ;
glutDisplayFunc(display) ;
glutMainLoop() ;
}
Vertex et fragments
Vertexnormales, coordonnées de texture
transformations, projection, clipping
éclairage
Fragmentsplacage de texture
brouillard, antialiasing
tests (scissor, alpha, stencil, depth)
blending, dithering, opérations logiques
rastérisation
Placage de textures
Placage de texture : pourquoi ?
Modèle d’éclairement de Phong et ombrage de Gouraud– assez limité en terme de rendu (canette de soda ?)– produit des objets très ennuyeux
Comment rendre les choses plus intéressantes ?– en créant des objets plus complexes– en utilisant des textures
Intérêt du placage de texture– permet de simuler des matériau ou des phénomènes naturels (eau, feu,
etc.) ou optiques– permet d’alléger la géométrie des objets– facile, pas cher– le résultat est souvent aussi bon !
Texture : définition
L’apparence et le toucher (feel) d’une surface
Une image utilisée pour définir les caractéristiques d’une surface
Une image multi-dimensionnelle qui est plaquée sur un espacemulti-dimensionnel
Exemple : Honda Hippo (3dRender.com)
Principe de base du placage de texture 2D
Un texel est un couple (s,t) de coordonnées ! [0,1] identifiant unpoint de la texture
Problème : comment trouver le(s) texel(s) correspondant à unfragment xs, ys ?
Solution : couples vertex/texel et interpolation
Ttw Tws
objet : x,y,ztexture : s,t écran : xs, ys
Interpolation de coordonnées
(x1, y1), (s1, t1)(x2, y2), (s2, t2)
(x3, y3), (s3, t3)
3
13
1
1
13
11 s
yy
yys
yy
yysR !!
"
#$$%
&
'
'+!!
"
#$$%
&
'
''=
3
23
2
2
23
21 s
yy
yys
yy
yysL !!
"
#$$%
&
'
'+!!
"
#$$%
&
'
''=
R
LR
L
L
LR
Ls
xx
xxs
xx
xxs !!
"
#$$%
&
'
'+!!
"
#$$%
&
'
''= 1
Problème…
Le placage de texture est effectué une fois que le polygone a étérastérisé
Si on utilise une projection en perspective, la taille des segmentsest réduite en fonction de la distance (sauf pour les lignesparallèles au plan image)
L’interpolation correcte est possible, mais plus coûteuse
Le problème ne se pose pas avec une projection orthographique
Placage de textures et aliasing
Le placage de texture repose sur un échantillonnage discret
Si l’objet à texturer est éloigné, un pixel peut correspondre àplusieurs texels
Question : comment combiner ces texels ?
Le problème est similaire à celui du redimensionnement d’uneimage, excepté le fait que les rapports ne sont pas constants
Deux approches pour résoudre ce problème– pré-filtrage : les textures sont filtrées avant le placage– post-filtrage : plusieurs texels sont utilisés pour le calcul de
chaque pixel
Pré-filtrage
Technique du mipmapping– construction d’un ensemble d’images de taille t/2, t/4, …, 1
– au moment du placage, l’image choisie est telle que un fragmentcorresponde au plus à 4 texels
Inconvénient : l’ensemble des mipmaps occupe deux fois plus deplace que l’image originale
Intérêt : les images utilisées peuvent être différentes
Post-filtrage
Principe : description de ce qui doit se passer quand l’image est agrandieou rétrécie
En gros, deux possibilités– choisir le texel le plus proche
– interpoler entre les n texels les plus proches (4 pour OpenGL)
Si on utilise le mipmapping, il faut aussi choisir le mipmap (ou interpolerentre deux)
Autre technique : le filtrage anisotropique– jusqu’à 16 texels pris en compte
– une "sensibilité" différente en X et en Y spécialement conçue pour les castordus…
Exemple de filtrage anisotropique Placage de texture 2D avec OpenGL
1. spécifier les données de la texture– lire les données ou les générer
– associer les données à un texture object
2. spécifier les paramètres du placage– correction de la perspective
– comportement au niveau des bords
– post-filtrage
– combinaison avec le fragment
3. dessiner la (les) primitive(s)– activer la texture
– associer des coordonnées de textures à chaque vertex(manuellement ou automatiquement)
Texture targets et texture objects
Le texture target définit le type de texture : 1D, 2D, 3D ou autrestypes, utilisés par des extensions
Les texture objects permettent de basculer rapidement entreplusieurs textures créées précédemment
Exemple : création d’un texture object pour une texture 2D
GLuint texture ;
glGenTextures(1, &texture) ;
glBindTexture(GL_TEXTURE_2D, texture) ;
Spécification des données d’une texture 2D
A partir de données en mémoireglTexImage2D(target, mipmaplevel, internalformat,
width, height, border, format, type, texels)
glTexSubImage2D(...)
A partir d’une partie du frame bufferglCopyTexImage2D(...)
glCopyTexSubImage2D(...)
Les dimensions de l’image doivent être des puissances de 2
Pour créer automatiquement les mipmapsgluBuild2DMipmaps(target, internalFormat, width, height, format, type, data)
Exemple
// on suppose que les données retournées sont au format RGB
unsigned char *data = loadImage(filename,
&width, &height) ;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, data) ;
delete [] data ;
Paramétrage : correction de la perspective
Deux modes d’interpolation– Linéaire
– utilisant les informations de profondeur/perspective (lent)
Choix du mode parglHint(GL_PERSPECTIVE_CORRECTION_HINT, hint) ;
où hint est GL_DONT_CARE, GL_NICEST ou GL_FASTEST
Paramétrage : bords de texture
Pour chaque dimension (s et t), il est possible de répéter la textureou de la prolonger avec la dernière valeur
Une bordure peut également être spécifiée
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, R,G,B,A)
Paramétrage : post-filtrage
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, type)glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, type)
Pour la réduction :– GL_NEAREST : point le plus proche dans la texture– GL_LINEAR : interpole entre les 4 points les plus proches– GL_NEAREST_MIPMAP_LINEAR : interpolation des 4 points les plus
proches du mipmap le plus proche– GL_LINEAR_MIPMAP_LINEAR : interpolation des 4 points les plus
proches dans l’interpolation des deux mipmaps les plus proches
Pour l’agrandissement : GL_NEAREST ou GL_LINEAR
Paramétrage : combinaison avec le fragment
glTexEnv permet de contrôler la façon dont la texture estappliquée sur le fragement
glTexEnv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode) ;
Les modes les plus utilisés sont– GL_MODULATE : multiplie la couleur du fragment par celle du texel– GL_BLEND : mélange la couleur du fragment et celle du texel– GL_REPLACE : remplace le fragment par le texel
Il existe aussi un mode GL_DECAL similaire à GL_REPLACE pourRGB
Exemple de dessin d’un rectangle texturé
glEnable(GL_TEXTURE_2D) ;
glBegin(GL_QUADS) ;
glTexCoord2f(0,0) ;
glVertex2f(x1,y1) ;
glTexCoord2f(1,0) ;
glVertex2f(x2,y1) ;
glTexCoord2f(1,1) ;
glVertex2f(x2,y2) ;
glTexCoord2f(0,1) ;
glVertex2f(x1,y2) ;
glEnd() ;
x2,y2
x1,y1
0,0
x2,y1
x1,y2
0,1
0,0
1,1
1,0
texture
Attention !
Pour OpenGL, le premier point d’une image est en bas àgauche… mais en général, les données sont organisées detelle sorte que le premier point est en haut à gauche
0,0
width, height 0,0
1,1
1,0
0,1 x2,y2
x1,y1
0,0
x2,y1
x1,y2
Image d’origine Texture Objet
0,1
1,0
1,1
0,0x1,y1 " 0,1 et non 0,0
x2,y1 " 1,1 et non 1,0
x2,y2 " 1,0 et non 1,1
x1,y2 " 0,0 et non 0,1
Génération automatique des coordonnées
Génération à l’aide de la fonction glTexGen* selon 3 modes– GL_OBJECT_LINEAR
– GL_EYE_LINEAR
– GL_SPHERE_MAP
Les deux premiers peuvent être utilisés pour dessiner descontours, le troisième pour l’environment mapping
Tutorial Texture de Nate Robins Quelques détails pratiques
Toutes les coordonnées de texture sont transformées par unematrice à part (GL_TEXTURE_MATRIX)
Les textures peuvent être 1D, 2D ou 3DLes données peuvent être stockées en L, A, RGB, RGBA, …
Plusieurs fonctions permettent de spécifier l’organisation desdonnées de la texture (e.g. glPixelStorei(GL_UNPACK_ALIGNMENT,a))
Sur la plupart des architectures, la quantité de mémoire de textureest fixe… mais on peut souvent mettre plusieurs textures dansune image… et on n’est pas obligé d’utiliser toute la place
Quelques détails pratiques (suite)
Il est possible de demander si une texture particulière peut êtrechargée en mémoire
glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
GLint allocwidth;
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &allocwidth);
// si tout va bien, width==allocwidth
Quelques détails pratiques (suite)
Un certain nombre de textures sont résidentes, ce qui signifie quel’accès à leur données est accéléré par le matériel
Pour savoir si une ou plusieurs textures sont résidentes, utiliserglGetTexParameteri (avec GL_TEXTURE_RESIDENT) ouglAreTexturesResident
Il est possible d’affecter une priorité entre 0.0 et 1.0 à une ouplusieurs textures avec les commandes glTexParameterf (avecGL_TEXTURE_PRIORITY) ou glPrioritizeTextures
Quelques détails pratiques (suite)
Plusieurs extensions récentes permettent d’éviter une copie dedonnées
Exemple sur MacOSglPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, v) ;
Attention : dans ce cas, la zone mémoire contenant les donnéesdoit rester allouée tant que la texture peut être utilisée…
Du fragment au pixel
Du fragment au pixel
scissor test
alpha test
stencil test
depth test
blending
dithering
logical operations
Fragment
Pixel (frame buffer)
Scissor test
Un test de clipping additionnel (en plus du viewport et des plansde clipping déjà mentionnés)
UtilisationglScissor(x,y,w,h) ;glEnable(GL_SCISSOR_TEST) ;
Les coordonnées et dimensions sont en pixels (comme pourglViewport)
Utilisé généralement pour effacer ou mettre à jour une partie de lafenêtre
Alpha test
Permet de rejeter certains fragments en fonction de la valeur deleur composante alpha
UtilisationglAlphaFunc(GL_GREATER, 0.5) ;
glEnable(GL_ALPHA_TEST) ;
Très pratique pour réduire le nombre de fragments dessinéslorsqu’on a des objets transparents
Stencil test
Permet de faire du clipping non rectangulaire en utilisant un bufferadditionnel : le stencil buffer
Généralement utilisé avec une approche multi-passes
UtilisationglStencilFunc définit le test à effectuerglStencilOp décrit comment le stencil buffer est mis à jour en fonction
du résultat du test et éventuellement du test de profondeur suivantglStencilMask détermine si l’on peut écrire dans le stencil bufferglEnable(GL_STENCIL_TEST) ;
Stencil test : exemple
glInitDisplayMode(…|GLUT_STENCIL|…) ;
…
glEnable(GL_STENCIL_TEST) ;
glClearStencil(0) ; // glClear initialisera à 0
…
glStencilFunc(GL_ALWAYS, 0x1, 0x1) ;
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE) ;
… // dessine le masque
glStencilFunc(GL_EQUAL, 0x1, 0x1) ;
… // les objets suivants seront dessinés qu’à l’intérieur du// masque
Depth test
Test de profondeur utilisant le depth buffer
UtilisationglDepthFunc définit la fonction de comparaison
glDepthMask détermine si l’on peut écrire dans le depth buffer
glDepthRange pour un contrôle sioux du avec les coordonnéesécran…
glEnable(GL_DEPTH_TEST) ;
Blending
Permet de combiner les composantes du fragment avec lesvaleurs courantes du framebuffer
UtilisationglBlendFunc définit la fonction de mélange
glEnable(GL_BLEND) ;
ExempleglBlendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA) ;
d = a*s + (1-a)*d
Dithering
Permet de simuler un nombre de couleurs plus grand que celuique le matériel peut effectivement afficher
UtilisationglEnable(GL_DITHER) ;
Remarque : le dithering est actif par défaut… et généralementinutile
Opérations logiques
Permet de combiner les fragments avec des opérateurs logiques(and, or, xor, not, etc.)
UtilisationglLogicOp(mode) ;
Imaging subset
Extension ARB pour faire du traitement d’image sur les pixels(mais pas sur le résultat de la rastérisation…)
Exemples de traitements– convolution
– histogrammes
– fonctions avancées de mélange
Antialiasing
Antialiasing des points, lignes et polygones
Pour les points et les lignesglEnable(GL_POINT_SMOOTH) ;
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST) ;
glEnable(GL_LINE_SMOOTH) ;
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST) ;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
Pour les polygonesglEnable(GL_POLYGON_SMOOTH) ;
glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST) ;
glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE) ;
Les polygones doivent être triés front-to-back et le contexte doit être RGBA(spécifié lors de la création de la fenêtre)
ARB Multisampling
Technique utilisée pour l’antialiasing de toute la scène
Principe : la couleur, la profondeur et les valeurs de stencil sontcalculées avec une précision inférieure au pixel et ensuitecombinées pour obtenir la valeur des pixels Affichage de texte avec GLUT
glutBitmapCharacter
Affiche un caractère en mode bitmap
UtilisationglutBitmapCharacter(font, character) ;
Les fontes sont prédéfinies : 9_BY_15, 8_BY_13, TIMES_ROMAN_10,TIMES_ROMAN_24, HELVETICA_10, HELVETICA_12, HELVETICA_18
La position du caractère est déterminée par glRasterPos*
La taille du caractère est exprimée en points/pixels
La boîte englobante est difficile à calculer…
glutStrokeCharacter
Affiche un caractère à l’aide d’un ensemble de segments (utiliseGL_LINE_STRIP)
Les fontes sont toujours prédéfinies : ROMAN ou MONO_ROMAN
L’affichage est plus lent qu’avec les fontes bitmap
Les dimensions des caractères sont exprimées en unités de lavue modèle (pour MONO_ROMAN, -33,33<h<119,05 etw=104,76)
La boîte englobante est facile à calculer
Quelques remarques
Ce qu’on attend de l’affichage du texte (au minimum)– qu’il soit rapide
– que l’on puisse transformer le texte (translations, rotations,changements d’échelle)
– que l’on puisse connaître la boîte englobante
GLUT ne répond pas vraiment à ces critères– peu de fontes (2*1 pour stroke, 2+2*1+3*1 pour bitmap)
– choix nécessaire entre vitesse (bitmap) et souplesse (stroke)
On peut faire de l’OpenGL sans GLUT…
Affichage de texte sans GLUT
Affichage de texte sans GLUT (avec OpenGL)
Il existe quelques librairiesvoir http://opengl.org/developers/code/features/fontsurvey/
Deux façon de dessiner le texte– dessiner les polygones correspondant à un caractère
– utiliser une texture
En plus des services de base (large choix de fontes, calcul de laboîte englobante, transformations), on trouve d’autres services
Exemple : extrusion
Affichage de glyph
Glyph : dessin d’un caractère
Certaines parties d’un glyph sont plus importantes que d’autre :
– les espaces entre les pattes d’un m sont plus importants que lespieds des pattes
– la barre d’un I et d’un T doivent être de même épaisseur
Afin de maximiser la lisibilité, les glyphs ne doivent pas être lesmêmes à toutes les échelles
Un moteur de rendu spécialisé est donc nécessaire…
Exemple : glft
Principes de conception– descriptions vectorielles des polices (TrueType)
– moteur de rendu spécialisé de haute qualité (FreeType)
Deux modes d’affichage– textures
– polygones
glft : affichage d’une ligne de texte
Affichage vectoriel pour les caractères de grande taille et à l’aided’une texture pour ceux de petite taille
Intérêt : affichage rapide pour les petites tailles et économique enmémoire pour les grandes tailles
Affichage d’une ligne de textestd::string message = "informatique graphique" ;fontManager->getBoundingBox(&message, &x,&y,&w,&h) ;
glTranslated(-w/2.0, -h/2.0, 0.0) ;
fontManager->render (&message) ;
glft ne gère pas le formatage (justification, alignement)
glft : affichage à l’aide d’une texture
On suppose qu’il y a peu de changements de police dans le texteà afficher
Utilisation d’une seule texture pour plusieurs glyphs– la texture est au format GL_ALPHA8– les caractères sont affichés avec des quads avec les coordonnées
de texture appropriées
Remarque : l’antialiasing est réalisé par FreeType au moment dela génération de la texture, pas par OpenGL
glft : problèmes liés aux textures
Changements d’échelle : quelle taille de caractères utiliser ?– font size=20, scale=0.5 : la taille apparente est 10
– glft propose un mécanisme d’autoscale
Les coordonnées des quads affichés sont alignées sur les pixelspour éviter des déplacements non voulus
glft cache les textures générées pour pouvoir les réutiliserrapidement par la suite
Glft : affichage vectoriel
Les contours des caractères sont décrits par des droiteset des courbes de Bézier
Le tesselateur de GLU est utilisé pour le caractères "à trous »comme le 8 ou le A
Le programmeur peut utiliser des display lists pour accélérerl’affichage (une par caractère, par paragraphe ou par page parexemple)
Le dessin des caractères peut être anti-aliasé avec la méthodeGL_MULTISAMPLE_ARB
glft : exemples d’utilisation (svgl)
Feedback, selection et picking
Le mode feedback
Le mode feedback sert à savoir quelles primitives seront affichées aprèsles étapes de transformation et de clipping
UtilisationglFeedbackBuffer(max_size, type, buffer) ;
int size_used = glRenderMode(GL_FEEDBACK) ;
La nature des valeur retournées dans buffer dépend du typed’information demandé (coordonnées, couleur, texture)
Chaque ensemble de valeurs est délimité par un code indiquant le typede primitive : GL_POINT_TOKEN, GL_LINE_TOKEN, GL_POLYGON_TOKEN,GL_BITMAP_TOKEN, GL_DRAW_PIXELS_TOKEN, GL_PASS_THROUGH_TOKEN
Le mode selection
Comme le mode feedback, le mode selection permet de savoirquelles primitives seront affichées après les étapes detransformation et de clipping
Toutefois, au lieu de récupérer les données liées à la primitive(coordonnées, couleurs, etc.), seul un nom est renvoyé
Pour identifier une primitive, il suffit de la nommer– le nom est un entier (un pointeur est un entier…)
– les noms sont placés dans une pile (hiérarchies !)
Mode selection : gestion de la pile de noms
Pour vider la pileglInitNames() ;
Pour remplacer le nom au sommet de la pileglLoadName(name) ;
Pour ajouter un nom au-dessus de la pileglPushName(name) ;
Pour enlever de la pile le nom au sommetglPopName() ;
En mode selection, l’affichage de chaque primitive nomméegénère un hit contenant la liste des noms empilés au momentde l’affichage
Le picking
Le picking est une utilisation spéciale du mode selection quipermet de savoir quels objets sont dessinés en un point del’écran
Usage classique : savoir ce qu’il y a sous le curseur de la souris
Principe– on restreint la zone d’affichage à quelques pixels autour du centre
d’intérêt– on affiche la scène en mode selection– les primitives proches du centre d’intérêt génèrent des hits– on analyse les hits
Exemple de mise en œuvre du picking
int pickAll(int x, int y, GLuint *buffer, GLuint size) { glSelectBuffer(size, buffer) ;
GLint viewport[4] ; glGetIntegerv(GL_VIEWPORT, viewport) ;
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPickMatrix( (GLdouble) x, (GLdouble) (viewport[3] - y),
2.0, 2.0, viewport ) ; … // transformations de projection (e.g. glOrtho, gluPerspective)
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
… // transformations de vue
Exemple de mise en œuvre du picking (suite)
glRenderMode(GL_SELECT) ; glInitNames() ;
… // dessine la scene en ajoutant les noms sur la pile
return glRenderMode(GL_RENDER) ;
}
Analyse des résultats du picking
Pour chaque hit, le buffer contient– le nombre de noms dans la pile au moment du hit
– depth value minimale des vertex touchés
– depth value maximale des vertex touchés
– le contenu de la pile de noms
Voir la documentation de glSelectBuffer pour les détails…
Quelques remarques concernant le picking
Le rendu des primitives en mode selection peut être différent decelui effectué pour l’affichage
Exemples– suppression des textures
– simplification de la géométrie (e.g. boîte englobante)
D’autres techniques peuvent être utilisées à la place du picking(exemple : coder l’identité de l’objet dessiné dans sa couleur)
Quelques remarques concernant l’interaction
Programmation par événements (sans GLUT)
for (bool loop=true; loop; ) {
bool refresh = false ;
Event e = getNextEvent() ;
switch (e.type) {
… // refresh peut être modifié
}
if (refresh) {
glClear(…) ;
…
swapBuffers() ;
}
}
Quelques techniques d’interaction courantes
Translations (panning)– déplacement d’un ou plusieurs objets– contrôle en X et Y à la souris (en Z avec un modificateur)
Changements d’échelle (zoom)– agrandissement/réduction d’un ou plusieurs objets– contrôle à la souris (modificateur pour différencier du panning)
Et les rotations ?– elles sont difficiles à composer…– parce qu’elles ne sont pas commutatives
Angles d’Euler et quaternions
Angles d’Euler : trois angles– définissent des rotations autour des axes X, Y et Z
– faciles à décrire
– facile à programmer avec OpenGL
Quaternions– w +ix +jy+kz, i2 = j2 = k2 = -1, ij = k = -ji
– pas très intuitif…
– mais idéal pour une manipulation interactive !
Quaternions et rotations : ArcBall
Une rotation est interprétée comme le tracé d’un arc sur la surfaced’une sphère
Display lists, vertex arrays
Mode immédiat et display lists
Mode immédiat– les primitives sont envoyées dans le pipeline et affichées
immédiatement
– le pipeline n’a aucune mémoire de ce qui l’a traversé
Display lists– les commandes sont placées dans des listes
– les listes sont conservées par le serveur graphique
– une liste peut être exécuté dans un environnement différent(certaines variables d’état peuvent avoir été changées)
Display lists
Les display lists sont identifiées par des entiers
L’instructionGLint dlist = glGenLists(n) ;
crée n display lists [dlist .. dlist+n-1]
Pour compiler (ou recompiler) une listeglNewList(dlist, GL_COMPILE) ; // ou GL_COMPILE_AND_EXECUTE
… // instructions OpenGLglEndList() ;
Pour exécuter une liste : glCallList(dlist) ;Pour détruire une liste : glDeleteLists(dlist, 1) ;
Display lists (suite)
Certaines instructions ne sont pas valides lorsqu’on est en train decréer une display list (glGet et glIsEnabled par exemple)
On ne peut pas créer une display list si on est en train d’en créerune… mais une display list peut en appeler une autre
Les changements d’état provoqués par l’exécution d’une displaylist persistent après elle (effets de bord)
Display lists (suite)
Quand utiliser une display list ? Dès qu’une même séquenced’instructions va être exécutée plus de n fois
Il vaut mieux éviter– des listes trop petites
– des hiérarchies trop profondes
– trop de listes
L’utilisation des display lists est fortement liée à la structure dedonnées utilisée pour décrire la scène
Vertex arrays
Les vertex arrays permettent de spécifier les vertex et leursattributs par blocs
Exemple d’utilisation : n points décrits chacun par 3 coordonnéeset une couleur RGBAglVertexPointer(3, GL_FLOAT, 0, coords) ;glColorPointer(4, GL_FLOAT, 0, colors) ;glEnableClientState( GL_VERTEX_ARRAY) ;glEnableClientState(GL_COLOR_ARRAY) ;glDrawArrays(GL_TRIANGLE_STRIP, 0, n) ;
Variations sur le thème : glInterleavedArrays, glDrawElements,glArrayElement
Comment accélérer votre application ?
1. chercher et corriger les erreurs éventuelles (glGetError)
2. identifier le(s) goulot(s) d’étranglement (bottleneck)• au niveau de l’application : les données ne sont pas insérées
assez rapidement dans le pipeline d’OpenGL
• au niveau des transformations : OpenGL n’arrive pas àtransformer vos vertex assez vite (transform-limited)
• au niveau de la rastérisation : OpenGL n’arrive pas à dessiner lesprimitives assez vite (fill-limited)
Application
Transformations
Rastérisation
Framebuffer
Problèmes au niveau de la rastérisation
Diagnostic simple : réduire le nombre de pixels à afficher
Solutions faciles– réduire la taille du viewport
– accepter un frame-rate plus faible
Autres solutions– n’afficher qu’un seul côté des polygones
– désactiver le dithering
– trier les primitives pour rejeter un maximum de fragments avec ledepth test ou l’alpha test (économise une lecture liée à la phasede blending)
Modèles hiérarchiques et graphes descène
Relations d’interdépendance
Les objets à modéliser existent rarement de manière isolée– chaîne corps/épaule/bras/main/doigts– les roues d’un véhicule y sont attachées– la chaise est devant la table, le téléphone est posé dessus– les chaises et les tables sont alignées– icône composée d’objets graphiques plus simples
Une organisation hiérarchique permet d’exprimer les relations dedépendances entre les objets
On parle alors de modèle hiérarchique pour un objet (e.g. unevoiture) ou de graphe de scène pour un ensemble d’objets
Utilisation d’un arbre
Idée de base : les feuilles sont les objets à dessiner, les nœudsintermédiaires correspondent à des groupes ou à destransformations
Chaque nœud n'a qu'un seul ancêtre, la transformation courantes'obtient par composition des transformations sur le cheminmenant de la racine au nœud courant
Les coordonnées d’un objet sont relatives à la transformationcourante : le téléphone est positionné par rapport à la table
Utilisation d’un arbre : exemple
tête
œil G œil D
yeux bras etjambes
jambe G jambe D bras G bras D
Parcours de l’arbre : exemple
On suppose que chaque nœud comporte une transformation et/oudu dessin
En chaque nœud– on sauve la matrice de transformation courante– on transforme localement– on dessine chacun des nœuds fils– on restaure la matrice de transformation
Le dessin local peut se faire avant/pendant/après les fils
Il peut être utile de stocker la transformation globalementappliquée ou du moins d'être capable de la retrouverrapidement
Utilisation d’un graphe acyclique orienté
Un graphe acyclique orienté (DAG) permet de partager des objetsou des sous-scènes sans les redécrire
Dans l’exemple précédent, les deux bras, les deux yeux, les deuxjambes du personnage sont identiques
Des display lists peuvent être utilisées pour accélérer l’affichagedes éléments souvent réutilisés
Utilisation d’un DAG : exemple
tête
œil G œil D
yeux bras etjambes
jambe G jambe D bras G bras D
jambe brasœil
Exemples de graphes de scène
Il en existe beaucoup– Inventor/VRML
– Performer
– OpenSG
– OpenScenegraph
– Java3D
– etc.
Le problème est de choisir…
Exemple: un petit graphe de scène
D’après Nicolas Roussel, LRI, université Paris-Sud
Histoire : besoin d’un graphe de scène minimal pour les démos de laboite à outils videoSpace et quelques applications (ametista parexemple)
Etat actuel : trois classes C++– Node– OrthoViewpoint (hérite de Viewpoint)– PerspectiveViewpoint (hérite de Viewpoint)
Principe– on crée des classes dérivées de Node– on attache des instances de ces classes à un point de vue
Quelques détails
A chaque nœud est associée– une matrice de transformation
– une liste de dépendances (d’autres nœuds)
– une display list
Des méthodes publiques permettent– d’ajouter ou supprimer des dépendances
– de modifier la matrice de transformation (reset, rotate, scale,translate)
– de savoir si le nœud ou ses dépendances ont changé
– d’afficher le nœud et ses dépendances (mode display ou select)
– d’appliquer la transformation locale du noeud
Exemple d’utilisation
OrthoViewpoint viewpoint("point de vue") ;…Objet o1("objet 1") ;o1.rotate(15, 0,0,1) ;viewpoint.addDependency(&o1) ;…viewpoint.resize(0,e.width,0,e.height,-10,10) ;…GLuint sbuf[10] ;int n = viewpoint.pickClosest(e.x, e.y,sbuf,10) ;…if (viewpoint.graphChanged()) viewpoint.displayGraph() ;
Gestion des display lists
Une display list peut en appeler une autre, mais on ne peut pas encréer une si l’on est déjà en train d’en créer une…
Solution : construire les listes en remontant vers la racine
Mise en pratique : dirty bit et parcours du graphe en deux passes1. identification et/ou calcul montant des display lists
2. affichage descendant
Avantage : a l’issue du premier parcours, on sait si quelque chosea été modifié et donc si on doit redessiner
Gestion des display lists : première version
Première version : une liste par nœud, toujours active– la liste est compilée pendant la première passe (parcours
montant)– elle est ensuite exécutée au moment de l’affichage (parcours
descendant)
Questions, problèmes soulevés– est-ce qu’un nœud doit être considéré comme changé lorsqu’une
de ses dépendances change ?– comment éviter de perdre du temps à recalculer les listes des
objets qui bougent souvent ?– comment limiter le nombre de listes utilisées ? (exemple : une
forêt d’arbres)
Gestion des display lists : deuxième version
Deuxième version : au plus une liste par nœud
La liste n’est créée que si l’objet a été dessiné plus de n fois sanschangement (n est spécifié à la création de l’objet)
Trois modes d’affichage– sans display list (détruit les listes existantes)
– avec les listes existantes
– en autorisant la création de listes supplémentaires
La phase montante ne compile plus les listes
Elles sont compilées et exécutées dans la phase descendante
Gestion du picking
Chaque nœud dessiné ajoute son adresse à la pile de noms
Un hit renvoyé par l’affichage en mode picking retourne donc lechemin allant de la racine du DAG jusqu’à l’objet sous lepointeur
On peut parcourir ce chemin en appelant la méthodeapplyTransformations en chaque nœud pour connaître latransformation globale appliquée
Connaissant la transformation globale, il est alors possible desavoir où on a cliqué, exprimé en coordonnées locales
Problèmes liés aux graphes de scène
Limites de l’encapsulation
L’encapsulation d’objets graphiques dans un objet avec uneméthode display est pratique… mais rarement efficace
Ce qui se passe généralement– nombreux appels à glPushMatrix / glPopMatrix
– nombreux changements d’état inutiles (e.g. couleur rouge)
Comme on l’a vu, les changements d’état peuvent déclencher desmécanismes de validation très coûteux
Exemple de ce qui peut être fait : state sorting
Une bonne organisation des objets à dessiner est la clé
Problème : quelle est cette bonne organisation ?
Certains graphes de scène savent trier les objets en fonction de lacouleur, du matériau ou de la texture utilisée– au lieu de dessiner au moment du parcours du graphe, ajouter
les nœuds à dessiner dans une liste
– trier cette liste en fonction du type des objets et des ressourcesutilisées
Oui, mais…
L’ordre d’affichage ne peut pas toujours être n’importe lequel
Exemple : affichage d’objets semi-transparents– les objets opaques doivent être dessinés en premier
– ensuite seulement, les objets semi-transparents peuvent êtredessinés, dans l’ordre back-to-front
Si on utilise le depth test, l’ordre optimal est front-to-back pourfaire échouer un maximum de de tests
Mais si l’on sait trier les objets, est ce que le test est plus coûteuxque le dessin back-to-front ?
L’avenir des graphes de scène
Il n’y aura sans doute jamais une organisation unique desdonnées capable de répondre à tous les besoins
Il faudra sans doute avoir plusieurs structures de données enparallèle, optimisées pour tel ou tel aspect du rendu ou del’application
Voir http://www.realityprime.com/scenegraph.php pour un débutde discussion sur ce sujet
Boites englobantes
Alignée sur les axes
Alignée sur l’objet
SVG
SVG: introduction
Scalable Vector GraphicsFormat xml du w3c
– DAG: c’est un graphe de scène…Concepts importants :
– Objets graphiques stylisés transformables• rect,cercle,polygones,path, textes…• Styles « à plat » ou CSS• transformations : géométrie et style
– Symboles• Réutilisation d’entités externes
– Effets raster• Flou, ombres
– Fontes• Permet d’éviter la transformation du texte en objets graphiques
– AnimationIntérêt:
– Pratique pour le programmeur (scene-graph)– Rien de nouveau, mais bonne compilation de concepts IG2D
Exemple
<svg width=‘450’ height=‘450’>
<rect x=’10’ y=’10’ width=‘100’ height=‘100’ fill=‘red’/>
<text x=’10’ y=‘140’ font-style=‘italic’>coucou</text>
<circle cx=‘200’ cy=‘200’ r=’30’ fill=‘yellow’ stroke=‘black’/>
<rect x=‘200’ y=‘200’ width=’50’ height=’10’ fill=‘blue’ transform=‘rotate(45)’/>
</svg>
coucou
Structure
Affichage selon le modèle du peintre– Dessin selon l’ordre d’apparition dans le document
Groupes– <g>…</g>
– Permet de factoriser les transformations
Définitions– <svg><defs><rect id=‘toto’/></defs><use href=‘#toto’/></svg>
– Permet de réutiliser des éléments du document• Icones, multi-vues
Path
<path class="SamplePath" d="M100,200 C100,100 250,100 250,200 S400,300400,200" />
Commandes:– M,m moveto(x,y)
– z closepath
– L,l lineto(x,y)
– C,c,Q,q curveto (x1,y1,x2,y2…) courbes de bezier cubiques et quadratiques
– A,a arc elliptique
Textes
<svg width="12cm" height="3.6cm" >
<defs> <path id="MyPath" d="M 100 200 C 200 100 300 0 400 100 C 500 200 600 300700 200 C 800 100 900 100 900 100" />
</defs>
<use xlink:href="#MyPath" fill="none" stroke="red" />
<text font-family="Verdana" font-size="42.5" fill="blue" >
<textPath xlink:href="#MyPath"> We go <tspan dy="-30" fill="red">up</tspan><tspan dy="30"> , </tspan> then we go down, then up again </textPath>
</text>
</svg>
Textes
justifié
One of the characteristics of international text is that thereare different baselines (different alignment points) forglyphs in different scripts. For example, in horizontalwriting, ideographic scripts, such as Han Ideographs,Katakana, Hiragana, and Hangul, alignment occurs with abaseline near the bottoms of the glyphs; alphabetic basedscripts, such as Latin, Cyrillic, Hebrew, Arabic, align apoint that is the bottom of most glyphs, but some glyphsdescend below the baseline; and Indic based scripts arealigned at a point that is near the top of the glyphs.
One of the characteristics of international text is that thereare different baselines (different alignment points) for glyphs
in different scripts. For example, in horizontal writing,ideographic scripts, such as Han Ideographs, Katakana,Hiragana, and Hangul, alignment occurs with a baselinenear the bottoms of the glyphs; alphabetic based scripts,
such as Latin, Cyrillic, Hebrew, Arabic, align a point that isthe bottom of most glyphs, but some glyphs descend belowthe baseline; and Indic based scripts are aligned at a point
that is near the top of the glyphs.
One of the characteristics of international text is that thereare different baselines (different alignment points) for glyphs
in different scripts. For example, in horizontal writing,ideographic scripts, such as Han Ideographs, Katakana,Hiragana, and Hangul, alignment occurs with a baseline
near the bottoms of the glyphs; alphabetic based scripts,such as Latin, Cyrillic, Hebrew, Arabic, align a point that is
the bottom of most glyphs, but some glyphs descend belowthe baseline; and Indic based scripts are aligned at a point
that is near the top of the glyphs.
One of the characteristics of international text is that thereare different baselines (different alignment points) forglyphs in different scripts. For example, in horizontalwriting, ideographic scripts, such as Han Ideographs,Katakana, Hiragana, and Hangul, alignment occurs with abaseline near the bottoms of the glyphs; alphabetic basedscripts, such as Latin, Cyrillic, Hebrew, Arabic , align apoint that is the bottom of most glyphs, but some glyphsdescend below the baseline; and Indic based scripts arealigned at a point that is near the top of the glyphs.
à droiteà gauche au centre
gras italique souligné
nonzero evenodd
marker
Stroke, fill, opacity
Gradients et motifs
<defs>
<linearGradient id="MyGradient">
<stop offset="5%" stop-color="#F60" />
<stop offset="95%" stop-color="#FF6" />
</linearGradient>
<rect fill="url(#MyGradient)" stroke="black"
stroke-width="5" x="100" y="100" width="600" height="200"/>
</defs>
Clipping, masking, compositing
Filtres Composition de filtres
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="200" height="120"><desc>Produces a 3D lighting effect.</desc><feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/><feOffset in="blur" dx="4" dy="4" result="offsetBlur"/><feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75" specularExponent="20" lighting-color="#bbbbbb" result="specOut"><fePointLight x="-5000" y="-10000" z="20000"/> </feSpecularLighting><feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/><feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1"k4="0" result="litPaint"/><feMerge> <feMergeNode in="offsetBlur"/> <feMergeNode in="litPaint"/></feMerge>
</filter>
svgl
Toolkit de rendu pour nouvelles interactions– ZUI, see-through tools, marking menus
– Vectoriel, transparence, transformations, filtres
Graphisme 2D– Rapide: OpenGL
– Beau: SVG• La doc existe
• Format ouvert
– Simple: DOM API
Difficultés de traduction
Difficultés– SVG: haut-niveau, OpenGL: bas-niveau
• Épaisseur des traits
• Courbes, polygônes convexes ou à trou
• Gradients
– Performances• Pipeline
• Tout en mémoire graphique
– Qualité du rendu
Exemple de tesselation Transparence de groupe
if fill!=none and stroke!=none andopacity<1
if stroke_opacity=1 set OpenGL opacity to opacity
draw stroke in color and stencil buffer set OpenGL opacity to opacity X
fill_opacity
if fill recovers itself draw fill in color and stencil buffer
else draw fill in color buffer
get bounding box draw in stencil buffer to pop it
else apply two pass algorithm with stroke
and fill
else
if stroke!=none
set OpenGL opacity to opacity x stroke-opacity
if OpenGL opacity<1 and strokerecovers itself
draw stroke in color and stencil buffer
get stroke bounding box
draw stroke in stencil buxffer to pop it
else
draw stroke in color buffer
if fill!=none
set OpenGL opacity to opacity x fill-opacity
if OpenGL opacity<1 and fill recoversitself
draw fill in color and stencil buffer
get fill bounding box
draw fill in stencil buffer to pop it
else
draw fill in color buffer
Gradients Performances
Ne pas compter uniquement sur la puissance du GPU…– Ex: plein d’icônes dans une vue zoomée
Solutions:– Frustrum culling: ne pas afficher les dessins invisibles
– Level of Detail (LOD)
– Rendu caché en texture