Guide débutant pour WebGL : introduction aux graphiques 3D dans le navigateur

Salut à toi, futur magicien des graphiques 3D ! Je suis ravi de devenir ton guide sur ce voyage passionnant dans le monde de WebGL. En tant que quelqu'un qui enseigne la graphique informatique depuis des années, je peux te dire que WebGL est comme une baguette magique pour ton navigateur web. Il te permet de créer des graphiques et des animations 3D époustouflants directement dans tes pages web. Ça ne fkkte pas ? C'est parti !

WebGL - Home

Qu'est-ce que WebGL ?

WebGL, abréviation de Web Graphics Library, est une API JavaScript qui permet de rendre des graphiques interactifs 2D et 3D dans n'importe quel navigateur compatible sans avoir besoin de plugins. C'est comme donner à ton navigateur des super-pouvoirs pour créer des expériences visuelles incroyables !

Une brève histoire

WebGL a été introduit pour la première fois en 2011, et depuis lors, il a révolutionné la manière dont nous pensons aux graphiques sur le web. Avant WebGL, si tu voulais créer des graphiques 3D dans un navigateur, tu devais compter sur des plugins comme Flash ou des applets Java. Maintenant, avec WebGL, nous pouvons faire tout cela nativement dans le navigateur. C'est comme passer d'un vélo à une voiture de sport !

Prérequis

Avant de commencer notre aventure WebGL, assurons-nous d'avoir les bons outils dans notre sac à dos :

  1. Un navigateur web moderne (Chrome, Firefox, Safari ou Edge)
  2. Un éditeur de texte (je recommande Visual Studio Code, mais n'importe lequel fera l'affaire)
  3. Des connaissances de base en HTML et JavaScript (ne t'inquiète pas si tu es un peu rouillé, nous reverrons les choses au fur et à mesure)

Premiers pas avec WebGL

Créons notre premier programme WebGL ! Nous allons commencer par un exemple simple "Hello, WebGL !" qui affiche un triangle coloré à l'écran.

Étape 1 : Configuration du HTML

Tout d'abord, nous devons créer un fichier HTML avec un élément canvas. C'est là que notre magie WebGL se produira.

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Hello, WebGL!</title>
<style>
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="glCanvas" width="640" height="480"></canvas>
<script src="webgl-demo.js"></script>
</body>
</html>

Dans ce HTML, nous avons créé un élément canvas avec un ID de "glCanvas" et réglé ses dimensions à 640x480 pixels. Nous avons également lié un fichier JavaScript nommé "webgl-demo.js" où nous écrirons notre code WebGL.

Étape 2 : Initialisation de WebGL

Maintenant, créons notre fichier "webgl-demo.js" et commençons à écrire un peu de JavaScript pour initialiser WebGL :

function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("Impossible d'initialiser WebGL. Votre navigateur ou machine pourrait ne pas le supporter.");
return;
}

// Définir la couleur de fond à noir, opaque
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// Effacer le tampon de couleur avec la couleur spécifiée
gl.clear(gl.COLOR_BUFFER_BIT);
}

window.onload = main;

Explication :

  1. Nous obtenons une référence à notre élément canvas.
  2. Nous essayons d'obtenir un contexte WebGL à partir du canvas. Si cela échoue, cela signifie que WebGL n'est pas supporté, et nous affichons un message d'erreur.
  3. Si cela réussit, nous définissons la couleur de fond (le fond d'écran) en noir et effaçons le tampon de couleur.

Étape 3 : Création des Shaders

Les shaders sont des programmes spéciaux qui s'exécutent sur le GPU. Ils sont écrits dans un langage appelé GLSL (OpenGL Shading Language). Nous avons besoin de deux types de shaders : les shaders de sommets et les shaders de fragments.

// Programme du shader de sommet
const vsSource = `
attribute vec4 aVertexPosition;

void main() {
gl_Position = aVertexPosition;
}
`;

// Programme du shader de fragment
const fsSource = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

Le shader de sommet positionne nos sommets, tandis que le shader de fragment colore nos pixels (dans ce cas, en rouge).

Étape 4 : Initialisation d'un Programme de Shader

Maintenant, nous devons compiler et lier ces shaders en un programme de shader :

function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Impossible d\'initialiser le programme de shader : ' + gl.getProgramInfoLog(shaderProgram));
return null;
}

return shaderProgram;
}

function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('Une erreur s'est produite lors de la compilation des shaders : ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}

return shader;
}

Ce code compile nos shaders, les lie en un programme, et vérifie pour toute erreur.

Étape 5 : Création du Triangle

Maintenant, créons les données pour notre triangle :

function initBuffers(gl) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

const positions = [
-1.0,  1.0,
1.0,  1.0,
-1.0, -1.0,
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

return {
position: positionBuffer,
};
}

Cela crée un tampon et le remplit avec les positions de nos sommets de triangle.

Étape 6 : Dessiner la Scène

Enfin, mettons tout cela ensemble et dessinons notre triangle :

function drawScene(gl, programInfo, buffers) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.useProgram(programInfo.program);

gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
2,        // 2 composants par itération
gl.FLOAT, // les données sont des flottants 32 bits
false,    // ne pas normaliser
0,        // pas (0 = automatique)
0         // décalage dans le tampon
);

gl.drawArrays(gl.TRIANGLES, 0, 3);
}

Cette fonction efface le canevas, configure notre programme de shader, connecte nos données de tampon, et finally dessine notre triangle.

Mettre Tout Ensemble

Maintenant, mettons à jour notre fonction main pour utiliser tous ces éléments :

function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("Impossible d'initialiser WebGL. Votre navigateur ou machine pourrait ne pas le supporter.");
return;
}

const shaderProgram = initShaderProgram(gl, vsSource, fsSource);

const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
},
};

const buffers = initBuffers(gl);

drawScene(gl, programInfo, buffers);
}

window.onload = main;

Et voilà ! Ton premier programme WebGL. Lorsque tu ouvres ton fichier HTML dans un navigateur, tu devrais voir un triangle rouge sur fond noir. Félicitations !

Méthodes Communes de WebGL

Voici un tableau de quelques méthodes WebGL courantes que nous avons utilisées et de leurs objectifs :

Méthode Objectif
gl.createBuffer() Crée un nouvel objet de tampon
gl.bindBuffer() lie un objet de tampon à une cible
gl.bufferData() Initialise et crée le magasin de données de l'objet de tampon
gl.createShader() Crée un objet de shader
gl.shaderSource() Définit le code source d'un objet de shader
gl.compileShader() Compile un objet de shader
gl.createProgram() Crée un objet de programme
gl.attachShader() Attache un objet de shader à un objet de programme
gl.linkProgram() Lie un objet de programme
gl.useProgram() Définit l'objet de programme comme faisant partie de l'état de rendu actuel
gl.getAttribLocation() Retourne l'emplacement d'une variable d'attribut
gl.enableVertexAttribArray() Active un tableau d'attributs
gl.vertexAttribPointer() Spécifie la disposition des données d'attribut
gl.drawArrays() Rend des primitives à partir de données de tableau

Conclusion

Wouah, nous avons couvert beaucoup de terrain aujourd'hui ! Nous avons appris ce qu'est WebGL, configuré notre environnement de développement, et créé notre premier programme WebGL. Souviens-toi, apprendre WebGL est comme apprendre à rouler un vélo - cela pourrait sembler un peu wobbly au début, mais avec de la pratique, tu seras bientôt en train de zigzaguer en un clin d'œil !

Dans les leçons futures, nous explorerons des formes plus complexes, ajouterons de l'interactivité, et même plongerons dans les graphiques 3D. Le monde de WebGL est immense et passionnant, et je suis impatient de l'explorer davantage avec toi. Jusqu'à la prochaine fois, bon codage !

Credits: Image by storyset