IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Découvrez OpenGL 1.1 en VB6/VBA

Image non disponible

Découvrez OpenGL 1.1 en VB6/VBA

Image non disponible


précédentsommairesuivant

VII. Découverte d'OpenGL

VII-A. Version ciblée et extensions

Le module ModOpenGL_1_1 contient les déclarations de la version 1.1 d'OpenGL.
Il existe des versions plus récentes d'OpenGL (jusqu'à la version 3.1 à ce jour) et également des extensions.
Nous nous contenterons, pour ce tutoriel de découverte, de la version 1.1 qui permet déjà de réaliser de nombreuses opérations 3D.

Les fonctions des versions supérieures à la version 1.1 sont considérées comme des extensions, nous ne les utiliserons pas au cours de ce tutoriel.

De nombreuses fonctions utilisées dans cet article sont dépréciées dans la version 3 d'OpenGL.
Il est cependant toujours possible de les utiliser, toutes les cartes graphiques n'offrent pas encore à ce jour de driver compatible OpengGL 3.
Vous pouvez consultez les spécifications OpenGL 3 pour une liste des fonctions dépréciées.

Pour l'utilisation des extensions, consultez le tutoriel suivant : Les extensions OpenGL en VBA et VB6

VII-B. La programmation par états

La programmation en OpenGL est basée sur des états.
C'est-à-dire que l'on définit un état (une couleur, une épaisseur de trait, ...), et il est alors utilisé par toutes les opérations de dessin qui suivent.
Par exemple si on définit la couleur rouge, tous les points dessinés ensuite seront de couleur rouge tant qu'on ne fait pas appel à une autre couleur.

VII-C. Les procédures et constantes

Les fonctions et constantes OpengGL commencent par le préfixe gl.
Elles sont déclarées dans le module ModOpenGL_1_1.

Celles de Glu commencent par le préfixe glu.
Les fonctions préfixées par wgl sont spécifiques à Windows.
Ces fonctions sont déclarées dans le module ModOpenGLTools.

Les fonctions et constantes freeglut commencent par le préfixe glut.
Elles sont toutes déclarées dans le module ModOpenGLFreeGlut.

Quelques fonctions gdi32 sont également utiles pour créer une fenêtre et un contexte openGL sans freeglut.
Ces fonctions sont déclarées dans le module ModOpenGLTools.

VII-D. Les types de données

Le suffixe des procédures est fonction du type de données attendu.

suffixe type de données type de données VB
b Byte Byte
s Short Integer
i Integer Long
f Float Single
d Double Double
ub Unassigned Byte Byte
us Unassigned Short Integer
ui Unassigned Integer Long


Image non disponible   On peut également trouver un suffixe v qui désigne un paramètre attendu sous forme de tableau.

Par exemple :
- glNormal3d attend 3 paramètres de type Double
- glNormal3i attend 3 paramètres de type Long
- glNormal3iv attend 1 paramètre de type tableau de Long

VII-E. Les buffers

OpenGL utilise plusieurs Tampons (ou Buffers).
Ces buffers contiennent des informations relatives à la scène que nous dessinons.

VII-E-1. Le tampon de couleurs

Egalement appelé tampon chromatique, il contient la couleur de chaque pixel de la scène.
Le paramètre GLUT_RGBA que nous avons utilisé pour initialiser freeglut demande l'utilisation d'un tampon de couleurs contenant 4 composantes par pixels : R pour rouge, G pour vert, B pour bleu, et A pour le canal Alpha qui détermine la transparence.

C'est sur ce tampon que nous dessinons.
Ce tampon est vidé en utilisant le paramètre GL_COLOR_BUFFER_BIT de la fonction glClear.

VII-E-2. Le tampon de profondeur

Appelé également Z-Buffer, ce tampon contient la distance des pixels par rapport à l'observateur.

La couleur utilisée dans le tampon de couleur est la couleur qui a la plus faible valeur dans le tampon de profondeur.
En cas de transparence, c'est un peu plus complexe : la couleur affichée est définie par le mode de mélange de couleurs choisi.

Ceci est géré par OpenGL :
- si on a défini l'utilisation de ce tampon par l'utilisation de GLUT_DEPTH lors de l'initialisation du mode d'affichage de freeglut.
- et si on active les tests de profondeur avec l'appel à la fonction : glEnable GL_DEPTH_TEST.

Ce tampon est vidé en utilisant le paramètre GL_DEPTH_BUFFER_BIT de la fonction glClear.

VII-E-3. Le tampon d'accumulation

Ce tampon peut cumuler plusieurs images.
On ne dessine pas directement sur ce tampon.
On transfère les pixels depuis ou vers le tampon de couleurs.

Une utilisation courante de ce tampon est l'anti-aliasing (lissage), obtenu en cumulant plusieurs images légèrement décalées.

Pour utiliser ce tampon il faut, à l'initialisation du mode d'affichage de freeglut, préciser le paramètre GLUT_ACCUM.

Ce tampon est vidé en utilisant le paramètre GL_ACCUM_BUFFER_BIT de la fonction glClear.

VII-E-4. Le tampon pochoir

Plus souvent appelé tampon stencil.
Ce tampon permet de restreindre l'affichage à une zone réduite de l'image.

Les utilisations courantes de ce tampon sont :
- les effets d'ombre
- les effets mirroir
- l'affichage à travers un trou (serrure, fenêtre, ...)

Pour utiliser ce tampon il faut, à l'initialisation du mode d'affichage de freeglut, préciser le paramètre GLUT_STENCIL.

Ce tampon est vidé en utilisant le paramètre GL_STENCIL_BUFFER_BIT de la fonction glClear.

VII-E-5. Le double tampon

Vous avez sans doute remarqué l'utilisation du mode d'affichage GL_DOUBLE pour notre première fenêtre.

Ce paramètre définit l'utilisation du double tampon (ou double buffer).
C'est le tampon de couleurs qui est doublé.

C'est un paramètre très important car cela permet de réduire les scintillements à l'affichage.
En effet, au lieu de directement dessiner un par un les éléments sur la fenêtre, on va dessiner sur un tampon caché puis intervertir les deux tampons une fois tout le dessin réalisé.

Le changement de tampon se fait à l'aide de la fonction gluSwapBuffers.
L'affichage de la fenêtre est mis à jour au moment de l'appel à cette fonction.

VII-F. Les unités

L'unité n'est pas le cm, le mètre ou autre...
Tout est relatif, à vous de définir l'unité de votre scène.
Si par exemple vos créez une scène sur laquelle vous souhaitez déplacer un personnage, vous pouvez arbitrairement décider qu'une valeur de 1 correspondra à 1 mètre.
Ainsi se déplacer de 0,5 correspondra à un déplacement de 50 cm.
Pour créer un cube de 2 mètres de côté, vous créerez un cube de 2 de côté.
Toute la scène sera alors à l'échelle.

Il suffit de choisir une unité en fonction de la scène dessinée pour se simplifier les calculs.
Si vous créez un monde à l'échelle d'un insecte, vous prendrez peut-être plutôt 1cm pour une unité openGL.

VII-G. Les vertices

Un vertice est un point. Vous lirez également souvent le mot anglais vertex.

Les vertices sont la base du dessin en 3D avec OpenGL

Ces vertices sont regroupés en primitives géométriques (point, triangle, rectangle, ...)

VII-H. Les primitives géométriques

Pour dessiner une primitive géométrique, il faut d'abord appeler la fonction glBegin en précisant la primitive souhaitée.

Nom de la primitive Description Exemple
GL_POINTS Points : chaque vertice est traité comme un point indépendant. Image non disponible
GL_LINES Lignes : chaque paire de vertices forme un segment. Image non disponible
GL_LINE_STRIP Lignes connectées : chaque vertice (hormis le premier et le dernier) est utilisé deux fois.
Les vertices N et N+1 forment un segment.
Image non disponible
GL_LINE_LOOP Lignes connectées en boucle: même chose que GL_LINE_STRIP.
De plus le dernier et le premier vertice forment un segment qui referme le polygone.
Image non disponible
GL_TRIANGLES Triangles : chaque triplet de vertices forme un triangle. Image non disponible
GL_TRIANGLE_STRIP Triangles connectés :
- Pour un nombre de vertices pair : un triangle est formé des vertices N, N+1 et N+2.
- Pour un nombre de vertices impair : un triangle est formé des vertices N+1, N et N+2.
Image non disponible
GL_TRIANGLE_FAN Triangles connectés :
Chaque triangle est formé du vertice 1 et des vertices N+1 et N+2.
Image non disponible
GL_QUADS Rectangles :
Chaque groupe de 4 vertices forme un rectangle.
Image non disponible
GL_QUAD_STRIP Rectangles :
Chaque paire de vertices (hormis la première paire) forme un rectangle avec la paire de vertice précédente.
Image non disponible
GL_POLYGON Polygone :
Chaque vertice définit un point du polygone.
Le polygone doit être convexe.
Image non disponible


Chaque vertice est défini par ses coordonnées à l'aide d'une fonction glVertex*.

La primitive doit se terminer par un appel à glEnd.

On peut, entre glBegin et glEnd, cumuler plusieurs primitives géométriques de même type.

Image non disponible   Testons l'affichage d'un triangle :

Après le vidage des buffers (glClear) et avant l'échange de buffer (glutSwapBuffers), ajoutons le code de dessin d'un triangle.
Pour bien structurer le programme, nous allons ajouter une procédure Render dans laquelle nous déplaçons le code de vidage des tampons.

Appel de la fonction de rendu
Sélectionnez

Public Sub CallBackDraw()
' Appel de la fonction de rendu
Call Render
' Echange les buffers
glutSwapBuffers
End Sub


Tout le code de dessin est regroupé dans la fonction Render, qui pourra ainsi être appelée de divers endroits du code si besoin.

Dessin d'un triangle
Sélectionnez

Public Sub Render()
' Vide les buffers couleur et profondeur
glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT
' Début de la primitive
glBegin GL_TRIANGLES
    ' Ajoute les trois sommets
    glVertex2d 0, 0
    glVertex2d 1, 0
    glVertex2d 1, 1
' Fin de la primitive
glEnd
End Sub


Exécutez la fonction FonctionOpenGL pour visualiser le triangle.

Image non disponible
Vous l'avez sans doute remarqué, nous avons utilisé des coordonnées à deux dimensions pour dessiner notre triangle.
Malgré tout, on a bien un affichage en trois dimensions, le triangle a été placé avec une profondeur de 0 sur l'axe Z.
glVertex2d 1, 1 est équivalent à glVertex3d 1, 1,0.

VII-I. Les couleurs des vertices

Le triangle ainsi dessiné est blanc. C'est la couleur par défaut.
On peut affecter une couleur différente à chaque point du triangle.

Il suffit d'appeler une fonction glColor*.

On ne gère pas de transparence, on peut donc utiliser une fonction à 3 paramètres.

Ajoutez juste après l'appel à glBegin la fonction de changement de couleur :

Color le triangle en jaune
Sélectionnez

' Début de la primitive
glBegin GL_TRIANGLES
    ' Couleur jaune 
    glColor3d 1, 1, 0
[...]


Un seul appel à la fonction glColor* suffit à colorer tous les vertices.
En fait la couleur jaune reste la couleur de tous les vertices qui seront ensuite dessinés par le programme.
Si on souhaite réinitialiser la couleur, il faut redéfinir la valeur par défaut (couleur blanche) :

Réinitialise la couleur
Sélectionnez

    ' Couleur blanche par défaut
    glColor4d 1, 1, 1,1


En VB on utilise souvent un entier long pour définir la couleur, notamment les constantes vbWhite, vbRed, vbGreen, ...

Pour simplifier le choix des couleurs, j'ai ajouté au module ModOpengGLTools les fonctions glColor3VB et glColor4VB.
On peut leur donner en argument une couleur de type entier long.

Utilisons ces fonctions pour affecter à chaque point une couleur différente :

Affecter à chaque point une couleur différente
Sélectionnez

Public Sub Render()
' Vide les buffers couleur et profondeur
glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT
' Début de la primitive
glBegin GL_TRIANGLES
    ' Ajoute les trois sommets
    glColor3VB vbYellow ' Jaune
    glVertex2d 0, 0
    glColor3VB vbBlue ' Bleu
    glVertex2d 1, 0
    glColor3VB vbRed ' Rouge
    glVertex2d 1, 1
' Fin de la primitive
glEnd
End Sub


Nous remarquons que les couleurs s'appliquent en dégradé :

Image non disponible

VII-J. Orientation des faces

Chaque polygone a deux faces : une face avant et une face arrière.
Ces faces sont définies par l'ordre des vertices du polygone.
La face avant est, par défaut, celle qui est face à l'observateur lorsque les points sont définis dans le sens inverse des aiguilles d'une montre.

Appelez glFrontFace GL_CW pour inverser l'ordre des faces.
glFrontFace GL_CCW revient au comportement par défaut.

Notre triangle a donc été dessiné avec une face avant vers nous :

Image non disponible
Il est possible de masquer certaines faces, c'est ce qu'on appelle le culling.
Masquer les faces arrières des polygones peut accélérer le rendu.
Il faut cependant bien s'assurer que les faces soit créées avec la bonne orientation pour ne pas voir disparaître des polygones qui devraient être visibles.

Masquer les faces arrières
Sélectionnez

' D'abord activer le culling
glEnable GL_CULL_FACE
' Puis préciser les faces masquées
glCullFace GL_BACK

Ce code masque la face arrière (qui n'est pas visible sur notre dessin).
Si on utilise glCullFace GL_FRONT, le triangle disparaît.

VII-K. Les normales

On peut pour chaque point définir une normale avec une fonction glNormal*.
La normale est généralement définie perpendiculairement à la surface dessinée.
Pour un triangle, la normale est définie perpendiculairement à la face avant, dans la direction allant de la face arrière à la face avant.
Lorsqu'on utilise de la lumière, les normales deviennent importantes car elles déterminent l'éclairage du polygone.

On verra l'importance des normales dans le chapitre sur la lumière.

VII-L. Les modes d'affichage des polygones

Nous n'avons défini que des points, OpenGL a dessiné des polygones pleins.
C'est le mode d'affichage par défaut.
Ce mode d'affichage peut être modifié en utilisant la fonction glPolygonMode.
Inutile de redéfinir ce mode d'affichage à chaque fois que l'on dessine la scène, c'est un état qui peut être défini une seule fois à l'initialisation.

Ajoutons une procédure InitScene que nous appelons juste avant le lancement de la boucle glutMainLoop.

Appel de la fonction d'initialisation
Sélectionnez

[...]
' Appel de la fonction d'initialisation
InitScene
' Boucle principale
glutMainLoop
End Sub


VII-L-1. Affichage des points


Dans la fonction d'initialisation, définissez le mode d'affichage GL_POINT.
Ajoutez un appel à la fonction glPointSize pour agrandir la taille des points à 10 pixels.
Par défaut les points ne font qu'un pixel de large.

Initialisation en mode points
Sélectionnez

Public Sub InitScene()
' Mode d'affichage = Points 
glPolygonMode GL_FRONT_AND_BACK, GL_POINT
' Taille des points
glPointSize 10
End Sub


Les points sont représentés par des carrés de 10 pixels de côté.

Image non disponible
Pour lisser les points, activer l'anti-aliasing des points.

Lissage des points
Sélectionnez

Public Sub InitScene()
' Mode d'affichage = Points 
glPolygonMode GL_FRONT_AND_BACK, GL_POINT
' Taille des points
glPointSize 10
' Lissage des points
glEnable GL_POINT_SMOOTH
End Sub


Les points sont lissés :

Image non disponible

VII-L-2. Affichage des lignes


Dans la fonction d'initialisation, définissez le mode d'affichage GL_LINE.
Ajoutez un appel à la fonction glLineWidth pour agrandir la taille des lignes à 5 pixels.
Par défaut les lignes ne font qu'un pixel de large.

Initialisation en mode ligne
Sélectionnez

' Mode d'affichage = Lignes
glPolygonMode GL_FRONT_AND_BACK, GL_LINE
' Taille des lignes
glLineWidth 5


Les polygones sont représentés par des lignes de 5 pixels de large :

Image non disponible

On peut également afficher des lignes en pointillés.
Il faut utiliser la fonction glLineStipple, en ayant pris soin auparavant d'activer les motifs de lignes.

Initialisation en mode ligne et pointillé
Sélectionnez

' Mode d'affichage = Lignes
glPolygonMode GL_FRONT_AND_BACK, GL_LINE
' Taille des lignes
glLineWidth 5
' Active les motifs de lignes
glEnable GL_LINE_STIPPLE
' Définit le motif pointillé
glLineStipple 5, 43690


La fonction glLineStipple demande deux arguments :
- Le premier est le nombre de fois que chaque partie du motif se répète.
- Le deuxième est un entier long qui représente le motif (16 bits égaux à 0 ou 1).

Pour définir le nombre réprésentant le motif (43690 dans l'exemple), il faut convertir un binaire sur 16 bits en entier.

Le motif pointillé en binaire est : 1010101010101010.

Converti en base décimale, cela donne 43690.

Pour convertir un motif depuis une chaîne de caractères, on peut écrire une petite fonction :

Fonction de conversion de motif
Sélectionnez

Function BinToDec(pBin As String) As Long
Dim lDec As Long
Dim lCpt As Long
    lDec = 0
    For lCpt = 0 To Len(pBin) - 1
        lDec = lDec + Mid(pBin, Len(pBin) - lCpt, 1) * 2 ^ lCpt
    Next
    BinToDec = lDec
End Function

Puis pour définir le motif :

Définition du motif à partir d'une chaîne de caractères
Sélectionnez

' Définit le motif pointillé
glLineStipple 5, BinToDec("1010101010101010")

Le nombre 5 précise que chaque bit du motif est répété 5 fois.
Ce qui correspond à un motif : 111110000011111000001111100000....
Où chaque chiffre correspond à un pixel.

Image non disponible

VII-L-3. Remplissage des polygones

C'est le comportement par défaut : pour le réactiver, utilisez le mode d'affichage GL_FILL.

Initialisation en mode remplissage
Sélectionnez

' Mode d'affichage = remplissage
glPolygonMode GL_FRONT_AND_BACK, GL_FILL



précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2017 Thierry GASPERMENT. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.