• Aucun résultat trouvé

Techniques exploitant le processeur graphique pour le rendu de

5.2 Optimisation du temps de rendu de courbes param´etriques

5.2.2 Techniques exploitant le processeur graphique pour le rendu de

Nous pr´esentons dans cette section les diff´erentes impl´ementations sur processeur gra-phique que nous avons exp´eriment´ees pour le rendu de courbes param´etriques. Le principe est de calculer l’ensemble des points interpolant une courbe sur le processeur graphique vu que ce dernier est particuli`erement adapt´e pour le calcul vectoriel. En utilisant l’API graphique de haut niveau OpenGL, nous pouvons encapsuler ces op´erations dans unvertex shader. Ce type de programme, ´ecrit dans un langage proche du C appel´e GLSL (OpenGL Shading Language), permet de customiser l’´etape de traitement des sommets en entr´ee du pipeline de rendu (voir Figure 1.21). L’objectif initial de cet ´etape est de transformer les coordonn´ees 3D des sommets vers des coordonn´ees ´ecran en 2D. Nous allons modifier cette ´etape afin de calculer les points interpolant une courbe. Le principal avantage de ces impl´ementations, outre la rapidit´e des calculs en points flottants, vient des capacit´es de calcul massivement parall`eles offerts par les processeurs graphiques contemporains. Ainsi, plusieurs instances du mˆeme vertex shader peuvent ˆetre ex´ecut´es en parall`eles. Sur les processeurs contemporains, il est possible de calculer une dizaine de points interpolant une courbe en parall`ele.

Le principe des diff´erentes impl´ementations que nous allons pr´esenter est le mˆeme pour toutes. Pour chaque courbe `a rendre, les points de contrˆole la d´efinissant sont accessibles depuis le vertex shader. Le param`etre t d´efinissant quel point de la courbe `a calculer est transmis dans la composante x des sommets en entr´ee du pipeline de rendu. Le vertex shader va alors interpoler le point de la courbe correspondant puis le transmettre `a la prochaine ´etape du pipeline de rendu. La principale diff´erence entre nos impl´ementations provient de la mani`ere dont les points de contrˆole sont transmis au shader. Nous avons ainsi test´e trois techniques pour le stockage de ces points :

1. stockage des points dans un tableau uniforme : Il est possible de d´eclarer des variables uniformes de type tableau dans unshader. Avant de rendre une courbe, les points de contrˆole sont transmis au shader et stock´es dans ce tableau. L’avantage de cette technique est que le temps d’acc`es aux points est extrˆemement rapide car on acc`ede `a une m´emoire locale en lecture seule. L’inconv´enient est que le nombre de points de contrˆole pouvant ˆetre stock´es varie selon le mod`ele du processeur graphique et la quantit´e de m´emoire vid´eo disponible. Sur des processeurs graphiques perfor-mants, cette solution est tout `a fait viable. Par exemple, sur une NVDIA Quadro FX 1800M, il est possible de stocker un millier de points de contrˆole dans la m´emoire d’un vertex shader. Le d´etail de cette impl´ementation est pr´esent´e en annexeB.1.

est de stocker l’ensemble des points de contrˆole des courbes `a rendre dans une texture 2D. Ce type de texture correspond `a un tableau de pixels `a deux dimensions, chaque pixel ´etant d´efini par un vecteur `a 4 composantes. La majorit´e des processeurs gra-phiques g`erent les pixels d´efinis par des valeurs en points flottants. En fixant la taille de la texture et en transf´erant un index au vertex shader, il est alors possible de r´ecup´erer les bons points de contrˆole pour chaque courbe `a dessiner. Cette technique permet de passer un tr`es grand nombre de points de contrˆole au shader et devrait pouvoir fonctionner sur un grand nombre de processeurs graphiques. Cependant, le temps d’acc`es `a la m´emoire des textures est bien plus long que celui d’acc`es `a la m´emoire locale dushader. Le code source de cette solution est donn´e en annexeB.2.

3. stockage des points dans un texture buffer object : Cette derni`ere impl´emen-tation fait appel `a des extensions OpenGL disponibles sur les processeurs graphiques r´ecents. Les points de contrˆoles sont stock´es dans un texture buffer object, qui peut ˆetre vu comme un grand tableau `a une dimension indexable par des entiers. Un tr`es grand nombre de points de contrˆole peut y ˆetre stock´e et le temps d’acc`es `a cette m´emoire est significativement plus rapide que celui pour lire une texture 2D. Les courbes sont rendues en utilisant une technique d’instancing, permettant de rendre la mˆeme g´eom´etrie de multiples fois, en modifiant certains param`etres depuis le shader via un index g´en´er´e automatiquement. L’impl´ementation d´etaill´ee de cette solution est pr´esent´ee en annexe B.3.

Nous proposons ´egalement l’impl´ementation d’un geometry shader permettant d’ex-truder une courbe `a la vol´ee afin de lui donner une ´epaisseur. La courbe est alors rendue sous la forme d’un maillage de triangles. Un geometry shader permet de g´en´erer de nou-velles primitives `a partir de celles envoy´ees au pipeline de rendu. Il est par exemple possible `

a partir d’une ligne de g´en´erer un ensemble de triangles. L’avantage de cette technique est qu’elle permet d’´eviter de g´en´erer l’extrusion cˆot´e CPU, ´economisant ainsi du temps CPU et de la m´emoire. Le d´etail de l’impl´ementation de ce geometry shader est donn´e en annexeB.4.

D´etaillons maintenant comment sont calcul´es les points d’interpolation en fonction du type de courbe `a rendre :

• courbe de B´ezier: Pour calculer un point de ce type de courbe, notre impl´emen-tation se contente d’´evaluer le polynˆome P (t) de l’´equation (1). Cependant, l’une des astuces utilis´ees est le calcul des coefficients binomiaux `a la vol´ee, ´evitant ainsi de transmettre d’autres donn´ees au vertex shader. Pour une valeur de n fix´ee, les

coefficients sont calcul´es it´erativement via la formule de r´ecurrence suivante : v0= n 0 ! = 1 v0<i≤n= n i ! = vi−1 (n + 1) − i i  (8)

L’impl´ementation en GLSL est donn´ee en annexeB.5.1. Les tests effectu´es ont mon-tr´e que cette impl´ementation reste num´eriquement stable pour calculer des courbes de B´ezier ayant jusqu’`a 120 points de contrˆole. Des probl`emes de pr´ecision de calcul en point flottant peuvent apparaˆıtre au del`a. D’autres techniques ont ´et´e propos´ees pour rendre des courbes de B´ezier au GPU. Par exemple, Loop et Blinn [130] ont pr´esent´e une m´ethode pour rendre des chemins et des r´egions d´efinis par des courbes de B´ezier cubiques et quadratiques. Leur approche, principalement d´edi´ee pour le rendu de police de caract`eres, est bas´e sur l’utilisation d’un fragment shader. Un polygone dont les sommets correspondent aux points de contrˆole est rendu et le fragment shader va ´ecarter les pixels ne se trouvant pas dans le polygone d´efini par la courbe.

• courbe B-Spline : Pour calculer les points interpolant une courbe B-Spline, notre impl´ementation va ´evaluer le polynˆome P (t) introduit `a l’´equation(3). Le calcul des fonctions de base B-Spline est aussi effectu´e par le vertex shader en utilisant une version optimis´ee de l’algorithme de Cox-de Boor (voir [166] et Algorithme1). Nous avons d´evelopp´e deux versions de notre impl´ementation pour les courbes B-Spline : une optimis´ee pour les B-Splines uniformes (i.e. les nœuds internes de multiplicit´e 1 sont uniform´ement espac´es) et une autre g´en´erique o`u les valeurs des nœuds sont d´efinies par l’utilisateur. Les codes sources en GLSL sont pr´esent´es en annexe B.5.2.

• courbe de Catmull-Rom : Pour rendre ce type de courbe, notre impl´ementation va dans un premier temps d´eterminer les points de contrˆole influen¸cant la forme de la courbe pour le param`etre t. Les points de contrˆole du segment de B´ezier cubique associ´e sont ensuite calcul´es selon l’´equation(6). Enfin, le point de la courbe associ´e au param`etre t est calcul´e en ´evaluant le polynˆome d´efini `a l’´equation (7). A noter qu’un param`etre suppl´ementaire est transmis au vertex shader, `a savoir la somme des distances entre chaque point de contrˆole successif (voir d´enominateur dans l’´equation(5)). Ceci afin d’´eviter de la recalculer `a chaque fois qu’un point de la courbe doit ˆetre interpol´e. Le code source en GLSL est donn´e en annexeB.5.3.

Algorithme 1 Algorithme optimis´e de Cox-de Boor (voir [166]) Entr´ees:

- n : nombre de point de contrˆole - p : degr´e de la courbe

- m+ 1 noeuds dans [0, 1] : {t0, . . . , tm}

- t : le param`etre dans [0, 1] d´efinissant le point de la courbe `a interpoler Sorties: - les coefficients N0,p(t), N1,p(t), . . . , Nn−1,p(t) dans un tableau N

1: Pour ide 0 `a n − 1 faire 2: N[i] = 0 3: Fin Pour 4: Si t== t0 alors 5: N[0] = 1.0 Retourner 6: Sinon Si t == tm alors 7: N[n −1] = 1.0 Retourner 8: Fin Si

9: Soit t dans l’intervalle de nœuds [tk, tk+1[

10: N[k] = 1.0 11: Pour dde 1 `a p faire 12: N[k − d] = tk+1− t tk+1− t(k−d)+1 ∗ N[(k − d) + 1] 13: Pour i de k − d+ 1 `a k − 1 faire 14: N[i] = t − ti

ti+d− ti ∗ N[i] + ti+d+1− t

ti+d+1− ti+1 ∗ N[i+ 1]

15: Fin Pour

16: N[k] = t − tk

tk+d− tk ∗ N[k]

17: Fin Pour