Techniques de points de contrôle en OpenGL : formes de Bézier
Prend en compte les courbes et les surfaces de Bézier, celles de Hermite, toute spline ou surface polynomiale ou polynomiale rationnelle de n’importe quel degré, les B-splines, les B-splines rationnelles non uniformes (NURBS). Courbes de Bézier Définition de la courbe Il s’agit d’abord de construire un tableau des coordonnées des points de contrôle de la courbe. GLfloat points_de_controle[4][3] = { {-4.0, -4.0, 1.0}, {-2.0, -1.0, 0.0}, {0.0, 0.0, -1.0}, {4.0, 4.0, 1.0}}; On peut alors définir une courbe de Bézier comme suit : void glMap1{fd}(GLenum Mode, TYPE u1, TYPE u2, GLint n, GLint m, const TYPE *P); Mode de représentation des points de contrôle Pointe vers la 1ière coordonnée du 1er point de contrôle : &points_de_controle[0][0] Plage de la variable u # de coordonnées d’un point # de points de contrôle
Mode de représentation des points de contrôle : - GL_MAP1_VERTEX_3 : coordonnées des sommets x, y, z - GL_MAP1_VERTEX_4 : coordonnées des sommets x, y, z, w - GL_MAP1_INDEX : index couleur - GL_MAP1_COLOR_4 : R, V, B, A - GL_MAP1_NORMAL : coordonnées de la normale - GL_MAP1_TEXTURE_COORD_1 : coordonnées de texture s - GL_MAP1_TEXTURE_COORD_2 : coordonnées de texture s, t - GL_MAP1_TEXTURE_COORD_3 : coordonnées de texture s, t, r - GL_MAP1_TEXTURE_COORD_4 : coordonnées de texture s, t, r, q. Afin de pouvoir activer ce mode et permettre l’évaluation de points sur la courbe, on utilise la primitive glEnable() comme par exemple : glEnable(GL_MAP1_VERTEX_3); On peut alors évaluer la courbe de Bézier en un sommet : void glEvalCoord1{fd}(TYPE u); void glEvalCoord1{fd}(TYPE * u); Note : Cela n’utilise pas les coordonnées des valeurs actives des couleurs, des index couleurs, des vecteurs normaux et des textures.
On peut aussi évaluer la courbe de Bézier en des points espacés régulièrement : Au lieu de faire appel à glEvalCoord1() avec n’importe quelle valeur de u, on définit d’abord une grille de points sur la courbe : void glMapGrid1{fd}(GLint n, TYPE u1, TYPE u2); Une grille de n points sur la courbe également espacés entre u1 et u2 est définie. puis, on évalue des points de cette grille pour affichage de la courbe : void glEvalMesh1(GLenum mode, GLint p1, GLint p2); GL_POINT ou GL_LINE 0 p1, p2 n Cela est équivalent à : glBegin(GL_POINTS); // ou glBegin(GL_LINE_STRIP); for (i = p1; i <= p2; i++) glEvalCoord1(u1 + i * (u2 – u1) / n); glEnd();
Exemple : Affichage d’une courbe de Bézier de degré 3. GLfloat points_de_controle[4][3] = { {-4.0, -4.0, 1.0}, {-2.0, -1.0, 0.0}, {0.0, 0.0, -1.0}, {4.0, 4.0, 1.0}}; void Initialisation(void) { glClearColor(0.0, 0.0, 0.0, 0.0); /* Permet de fixer les 3 composantes réelles de la couleur d'affichage. Elle demeure inchangée tant que ses attributs ne sont pas modifiés. */ glShadeModel(GL_FLAT); glColor3f(1.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &points_de_controle[0][0]); glEnable(GL_MAP1_VERTEX_3); }
void affichage( void ) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); // Affichage de la courbe de Bézier. glBegin(GL_LINE_STRIP); for (int i = 0; i <= 30; i++) glEvalCoord1f((GLfloat) i / 30.0); glEnd(); // Affichage des points de contrôle sous forme de points. glPointSize(5.0); glColor3f(1.0, 1.0, 0.0); glBegin(GL_POINTS); for(i = 0; i < 4; i++) glVertex3fv(&points_de_controle[i][0]); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(1.0, 0.0, 0.0, -10.0, -10.0, 0.0, 0.0, 1.0, 0.0); glFlush(); }
Surfaces de Bézier Définition de la surface Il s’agit d’abord de construire un tableau des coordonnées des points de contrôle de la surface. GLfloat points_de_controle[4][4][3] = { { {-1.5, -1.5, 4.0}, {-0.5, -1.5, 2.0}, {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}}, { {-1.5, -0.5, 1.0}, {-0.5, -0.5, 3.0}, {0.5, -0.5, 0.0}, {1.5, -0.5, -1.0}}, { {-1.5, 0.5, 4.0}, {-0.5, 0.5, 0.0}, {0.5, 0.5, 3.0}, {1.5, 0.5, 4.0}}, { {-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0}, {0.5, 1.5, 0.0}, {1.5, 1.5, -1.0}}, };
Surfaces de Bézier On peut alors définir une surface de Bézier comme suit : Mode de représentation des points de contrôle (idem au tableau précédent sauf que MAP1 est remplacé par MAP2. Plage de la variable u # de coordonnées d’un point void glMap2{fd}( GLenum Mode, TYPE u1, TYPE u2, GLint n, GLint m, TYPE v1, TYPE v2, GLint h, GLint k, TYPE * P); Pointe vers la 1ière coordonnée du 1er point de contrôle : &points_de_controle[0][0] Plage de la variable v # de coordonnées sur une ligne # de points de contrôle dans les directions u et v Afin de pouvoir activer ce mode et permettre l’évaluation de points sur la surface, on utilise la primitive glEnable() comme par exemple : glEnable(GL_MAP2_VERTEX_3);
Surfaces de Bézier On peut alors évaluer la surface de Bézier en un sommet : void glEvalCoord2{fd}(TYPE u, TYPE v); void glEvalCoord2{fd}v(TYPE * valeurs); On peut aussi évaluer la surface de Bézier en des points espacés régulièrement : void glMapGrid2{fd}(GLint nu, TYPE u1, TYPE u2, GLint nv, TYPE v1, TYPE v2); Une grille de nu x nv points sur la surface également espacés entre u1 et u2 et entre v1 et v2 resp. est définie. puis, on évalue des points de cette grille pour affichage de la surface : void glEvalMesh2(GLenum mode, GLint i1, GLint i2 , GLint j1, GLint j2); GL_POINT ou GL_LINE GL_FILL 0 i1, i2 nu 0 j1, j2 nv
Surfaces de Bézier Cela est équivalent à : glBegin(GL_POINTS); for (i = i1; i <= i2; i++) for (j = j1; j <= j2; j++) glEvalCoord2( u1 + i *(u2 – u1) / nu, v1 + j *(v2 – v1) / nv); glEnd(); ou { glBegin(GL_LINES); }
Surfaces de Bézier ou for (i = i1; i < i2; i++) { glBegin(GL_QUAD_STRIP); for (j = j1; j <= j2; j++) glEvalCoord2( u1 + i *(u2 – u1) / nu, v1 + j *(v2 – v1) / nv); glEvalCoord2( u1 + (i+1) *(u2 – u1) / nu, v1 + j *(v2 – v1) / nv); } glEnd();
Exemple : Affichage d’une surface de Bézier de degré 3 x 3 en fil de fer. GLfloat points_de_controle[4][4][3] = { { {-1.5, -1.5, 4.0}, {-0.5, -1.5, 2.0}, {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}}, { {-1.5, -0.5, 1.0}, {-0.5, -0.5, 3.0}, {0.5, -0.5, 0.0}, {1.5, -0.5, -1.0}}, { {-1.5, 0.5, 4.0}, {-0.5, 0.5, 0.0}, {0.5, 0.5, 3.0}, {1.5, 0.5, 4.0}}, { {-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0}, {0.5, 1.5, 0.0}, {1.5, 1.5, -1.0}}, }; void Initialisation(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glMap2f(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, &points_de_controle[0][0][0]); glEnable(GL_MAP2_VERTEX_3); }
void affichage( void ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); glRotatef(85.0, 1.0, 1.0, 1.0); // Affichage d'un réseau de courbes de Bézier sur la surface. for (GLint j = 0; j <= 8; j++) glBegin(GL_LINE_STRIP); for (GLint i = 0; i <= 30; i++) glEvalCoord2f((GLfloat) i / 30.0, (GLfloat) j / 8.0); glEnd(); for (i = 0; i <= 30; i++) glEvalCoord2f((GLfloat) j / 8.0, (GLfloat) i / 30.0); };
// Affichage des points de contrôle sous forme de points. glPointSize(5.0); glColor3f(1.0, 1.0, 0.0); glBegin(GL_POINTS); for(GLint i = 0; i < 4; i++) for (int j = 0; j < 4; j++) glVertex3fv(&points_de_controle[i][j][0]); glEnd(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(1.0, 0.0, 0.0, -10.0, -10.0, 0.0, 0.0, 1.0, 0.0); glFlush(); }
Exemple : Affichage d’une surface de Bézier de degré 3 x 3 en considérant des points espacés régulièrement à l’aide de polygones pleins. void Initialisation(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); glMap2f(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, &points_de_controle[0][0][0]); glEnable(GL_MAP2_VERTEX_3); glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0); }
void affichage( void ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); glRotatef(85.0, 1.0, 1.0, 1.0); glEvalMesh2(GL_FILL, 0, 20, 0, 20); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(1.0, 0.0, 0.0, -10.0, -10.0, 0.0, 0.0, 1.0, 0.0); glFlush(); }