Article original▲
Le blog KDAB est rédigé par les ingénieurs de KDAB s'occupant des formations, de la consultance ainsi que du développement (de Qt et de produits additionnels). Vous pouvez trouver les versions originales.
Cet article est une traduction de l'article original écrit par Sean Harmer paru le 15 mars 2013.
Cet article est une traduction de l'un des articles en anglais écrits par KDAB. Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à KDAB.
I. Les tableaux de coordonnées▲
Qt propose la classe QOpenGLBuffer (anciennement nommée QGLBuffer) pour faciliter la manipulation des différents types de tampons tels que les attributs de sommets ou les tampons d'indices. OpenGL possède aussi un conteneur appelé Vertex Array Object (VAO) pour faciliter la manipulation de ce type de données.
À partir de Qt 5.1, les VAO sont encapsulés dans la classe QOpenGLVertexArrayObject. Lors de la liaison d'une instance de cette classe, OpenGL se « souvient » de la configuration des sommets déjà en place. Il sera plus tard possible de restaurer, très rapidement, l’état de ces sommets en se contentant de réactiver le VAO. Cela permet de rapidement changer l'état des sommets des objets à afficher :
void
Scene::
initialize()
{
// Création d'un QOpenGLContext
// m_shaderProgram est un QOpenGLShaderProgram
// Création d'un VAO pour le premier objet à afficher
m_vao1 =
new
QOpenGLVertexArrayObject
( this
);
m_vao1->
create();
m_vao1->
bind();
// Initialisation des VBO et IBO (un QOpenGLBuffer sert de tampon pour les données,
// spécification du format, etc.). Ils seront mémorisés par le VAO lié à ce moment-là
m_positionBuffer.create();
m_positionBuffer.setUsagePattern( QOpenGLBuffer
::
StreamDraw );
m_positionBuffer.bind();
m_positionBuffer.allocate( positionData,
vertexCount *
3
*
sizeof
( float
) );
m_shaderProgram.enableAttributeArray( "vertexPosition"
);
m_shaderProgram.setAttributeBuffer( "vertexPosition"
, GL_FLOAT, 0
, 3
);
m_colorBuffer.create();
m_colorBuffer.setUsagePattern( QOpenGLBuffer
::
StaticDraw );
m_colorBuffer.bind();
m_colorBuffer.allocate( colorData,
vertexCount *
3
*
sizeof
( float
) );
m_shaderProgram.enableAttributeArray( "vertexColor"
);
m_shaderProgram.setAttributeBuffer( "vertexColor"
, GL_FLOAT, 0
, 3
);
// Répétition des opérations pour les tampons de normales, de coordonnées de textures, de tangentes…
…
// Crée le VAO du second objet
m_vao2 =
new
QOpenGLVertexArrayObject
( this
);
m_vao2->
create();
m_vao2->
bind();
// Préparation des VBO et des IBO pour les objets suivants
…
// Nettoyage et on recommence pour les autres objets
m_skyBoxVAO =
new
QOpenGLVertexArrayObject
( this
);
…
}
void
Scene::
render()
{
// Vidage de la mémoire tampon
m_funcs->
glClear( GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT );
// Liaison du shader, texture pour le premier ensemble d'objets
m_phongShaderProgram->
bind();
…
// Basculement sur les données des sommets pour les premiers objets et rendu de ces derniers
m_vao1->
bind();
m_funcs->
glDrawElements(…);
// Basculement sur les données du second objet puis affichage de ce dernier
m_vao2->
bind();
m_funcs->
glDrawElements(…);
// Changement éventuel du shader, des textures ou d'autres objets…
m_skyboxShaderProgram->
bind();
…
m_skyboxVAO->
bind();
m_funcs->
glDrawElements(…);
…
}
Les VAO, introduits avec OpenGL 3, sont maintenant nécessaires pour OpenGL 3.1 et pour OpenGL >=3.2 avec le core profile. En plus de cela, les VAO sont disponibles au travers des extensions GL_ARB_vertex_array_object et via GL_OES_vertex_array_object pour OpenGL2 et OpenGL ES 2 respectivement. La classe QOpenGLVertexArrayObject utilisera les fonctions standard si disponibles et se rabattra sur l'extension appropriée, si possible, le cas échéant.
L'utilisation des VAO peut réellement simplifier le code de rendu et l’accélérer, étant donné que les pilotes graphiques ont moins de contrôles d’intégrité à faire. Cela s'explique par la réduction du nombre d'opérations sur les tampons.
II. Remerciements▲
Au nom de toute l'équipe Qt, j'aimerais adresser le plus grand remerciement à KDAB pour nous avoir autorisés à traduire cet article !
Je tiens à remercier Thibaut Cuvelier et Alexandre Laurent pour leurs conseils ainsi que Philippe Duval pour sa relecture.