Les tampons

Introduction


Une fois que le contexte a été établi on va enfin pouvoir commencer à dessiner sur l'écran !
Euh... Enfin pas tout à fait. Il va falloir déjà envoyer des données au GPU. Pour cela on va utiliser des tampons (comme ceux vu en le cours d'OS de début d'année).
Mais qu'est-ce qu'on met dedans exactement ?

Quoi envoyer ?


Dans OpenGL, les rendus se font principalement avec des triangles. Si par exemple on veut dessiner un cube on enverra l'information pour en dessiner douze, (deux triangles par côté pour chacune des six faces).
On voit bien sur les modèles 3D des premiers jeux ces triangles parailleurs
Pour dessiner nos triangles on aura qu'à passer la position de leurs sommets sous la forme de nombres flottants (x, y, z).

Dessiner un carré.


Dans notre exemple on ne s'interessera qu'au rendu d'un carré à l'intérieur de l'écran pour cela on doit d'abord ce poser quelques questions :
Quelle est la taille de l'écran ?
 Le canvas de dessin openGL est toujours un carré de centre (0,0) avec comme sommet S = [(-1,-1), (-1, 1), (1, -1), (1, 1)]. Il faudra envoyer des coordonées comprises dans ces intervales pour voir notre forme se dessiner.
On pourrait envoyer quoi d'autres ?
 Dans le cadre d'une application 3D on pourrait aussi envoyer une matrice de transformation pour dire où regarde la caméra ou encore la position UV de notre sommet sur une texture, ou encore une simple couleur, ...
Sera-ce suffisant pour rendre une forme ?
 On a simplement ici envoyé des données au GPU et spécifier ce que c'était, mais on ne lui a pas dit quoi faire avec, pour cela on aura besoin des nuanceurs vu dans le chapitre suivant.

Implémentation


On peu enfin comprendre ce qui a été écrit ici :


//Les données que l'on va écrire dans le buffer
const vertices = [
// Premier triangle
//     x     y
    -0.5, -0.5,
    -0.5, +0.5,
    +0.5, +0.5,
// Second triangle
//     x     y
    +0.5, +0.5,
    +0.5, -0.5,
    -0.5, -0.5,
]


function makeVertexBuffer(vertices) {
    const vertexBuffer = gl.createBuffer();
    // bindBuffer sert à charger le buffer (pour l'écriture et / ou la lecture)
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    // Ce que l'on écrit sur le buffer:
    //  - On utilise Float32Array car les objets en javascript n'ont pas de type de base
    //    Ça permet de « certifier » ce que contient le tableau de sommet (des flottants)
    //  - STATIC_DRAW dit que ces données ne sont (presque) jamais modifiées.
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)

    return vertexBuffer;
}

/**
* « Envoie » les sommets de notre carré à la carte graphique 
*/
function bindVertexBufferAndAttributeLocation(vertexBuffer, aPositionLocation, dimension) {
    // Active l'attribut que l'on va lier
    gl.enableVertexAttribArray(aPositionLocation)
    // De même pour le buffer
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
    let normalize = false;
    // stride indique le pas entre deux données, 
    // -- c'est pratique si par exemple on spécifie 
    // -- dans le même buffer une position et une couleur
    let stride = 0;
    // offset indique le décalage initiale, même utilité que stride
    let offset = 0;
    // Indique comment les données du vertexBuffer doivent être lu
    // On attache nos données en tan que tableau de vecteur 2D (x, y)
    // sur l'attribut position de notre future shader (voir le tutoriel suivant)
    gl.vertexAttribPointer(
        aPositionLocation, dimension, gl.FLOAT, normalize, stride, offset
    )
}

function start() {
    // Initialisation des shaders + openGL
    // [...]
    const vertexBuffer = makeVertexBuffer(vertices);
    //Ici on récupèrera un attribut dans le shader qui manipulera nos données.
    let aPositionLocation = ...;
    //Écrit les données du vertex buffer dans l'attribut
    bindVertexBufferAndAttributeLocation(vertexBuffer, aPositionLocation, 2);
}
function update() {
    // [...] On pourrait ici mettre à jour notre buffer pour l'animer.
}
            
eof