QuÕest ce que lÕInformatique Graphique ? Exemples ...

49
Introduction à l’infographie Stéphane Conversy ENAC/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 University of Maryland, 2002

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