La programmation graphique fait appel à de nombreuses techniques
dont la finalité est de permettre de visualiser des scènes 3D ou 2D.
Elle réunit plusieurs phases aussi fastidieuses qu'essentielles :
vs.
Les deux principales bibliothèques ont longtemps été :
WebGL 2.0 est issu
d'OpenGL ES 3.0
(embedded systems = systèmes embarqués),
lui-même dérivé d'OpenGL 3.3
et 4.2.
Dédié à HTML5, il fait office d'interface entre JavaScript et les drivers OpenGL ES.
(Windows + ANGLE : la couche OpenGL ES est émulée via Direct3D)
<canvas>
de HTML5var canvas = document.getElementById (id);
var gl = canvas.getContext ('webgl2');
if (gl) gl.clear (gl.COLOR_BUFFER_BIT);
else alert ('Navigateur incompatible !');
Standard de facto du web 3D.
1 | Arranger les éléments de la scène à capturer | Composer une scène virtuelle | Transformation de modélisation |
---|---|---|---|
2 | Positionner l'appareil photo | Positionner la caméra virtuelle | Transformation de vision |
3 | Régler la focale de l'appareil photo | Configurer une projection | Transformation de projection |
4 | Choisir la taille des tirages photographiques | Choisir les dimensions de l’image video | Transformation de cadrage |
\[\begin{pmatrix} 1 & 0 & 0 & x \\ 0 & 1 & 0 & y \\ 0 & 0 & 1 & z \\ 0 & 0 & 0 & 1 \end{pmatrix}\] |
THREE.Object3D.position
\[\begin{pmatrix} x^2(1-c)+c & x y(1-c)-zs & x z(1-c)+ys & 0 \\ x y(1-c)+zs & y^2(1-c)+c & y z(1-c)-xs & 0 \\ x z(1-c)-ys & y z(1-c)+xs & z^2(1-c)+c & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\] \[c = \cos\theta \qquad s = \sin\theta \qquad \sqrt{x^2+y^2+z^2} = 1\] |
THREE.Object3D.rotation
\[\begin{pmatrix} x & 0 & 0 & 0 \\ 0 & y & 0 & 0 \\ 0 & 0 & z & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\] |
THREE.Object3D.scale
\(\mathbf{T} \times \mathbf{R} \times \:\) \(\qquad \neq \qquad\) \(\mathbf{R} \times \mathbf{T} \times \:\)
var camera = …;
camera.position.set (px, py, pz);
var cible = new THREE.Vector3 (cx, cy, cz);
camera.lookAt (cible);
new THREE.TrackballControls (camera);
new THREE.FirstPersonControls (camera);
↓
Deux types de projection pour modéliser l'optique des caméras :
new THREE.OrthographicCamera (xl, xr, yt, yb, zn, zf);
où \(f = \cot\frac{fov_y}{2}\).
new THREE.PerspectiveCamera (fov, aspect, zn, zf);
gl.viewport (x, y, w, h);
<canvas>
gl.scissor (x, y, w, h);
// Création du VBO.
var vbo = gl.createBuffer ();
// Activation du VBO.
gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
// Initialisation des données (avec copie).
var VERTICES = new Float32Array ([…]);
gl.bufferData (gl.ARRAY_BUFFER, VERTICES, gl.STATIC_DRAW);
// Désactivation du VBO.
gl.bindBuffer (gl.ARRAY_BUFFER, null);
gl.enableVertexAttribArray (index);
Activation d'un attribut identifié par son indice
gl.vertexAttribPointer (index, size, type, normalized, stride, offset);
// Activation du VBO.
gl.bindBuffer (gl.ARRAY_BUFFER, vbo);
// Activation de l'attribut nº 0.
gl.enableVertexAttribArray (0);
// Déclaration de la structure du tableau.
gl.vertexAttribPointer (0, 3, gl.FLOAT, false, 16, 0);
// Activation de l'attribut nº 1.
gl.enableVertexAttribArray (1);
// Déclaration de la structure du tableau.
gl.vertexAttribPointer (1, 3, gl.UNSIGNED_BYTE, true, 16, 12);
gl.POINTS
(cliquez pour redémarrer l'animation)
gl.LINES
/ gl.LINE_STRIP
/ gl.LINE_LOOP
(cliquez pour redémarrer l'animation)
gl.TRIANGLES
/ gl.TRIANGLE_STRIP
/ gl.TRIANGLE_FAN
(clic : redémarrer ; double clic : redistribuer les points)
gl.drawArrays (mode, first, count);
gl.TRIANGLE_STRIP
et gl.TRIANGLE_FAN
pas toujours adaptés
// Création du VBO.
var indices = gl.createBuffer ();
// Activation du VBO.
gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, indices);
// Initialisation des données (avec copie).
var INDICES = new Uint16Array ([…]);
gl.bufferData (gl.ELEMENT_ARRAY_BUFFER, INDICES, gl.STATIC_DRAW);
// Désactivation du VBO.
gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, null);
gl.drawElements (mode, count, type, offset);
new THREE.Mesh (geometry, material);
// Création d'un cube.
var geometry = new THREE.BoxGeometry (1, 1, 1);
// Création d'un matériau rouge uni.
var material = new THREE.MeshBasicMaterial ({color: 'red'});
// Création d'un maillage associant géométrie et matériau.
var mesh = new THREE.Mesh (geometry, material);
// Ajout du maillage à la scène.
scene.add (mesh);
// Création d'une géométrie vide.
var geometry = new THREE.Geometry ();
// Création des quatre sommets.
geometry.vertices.push (
new THREE.Vector3 (-0.5, -0.5, 0),
new THREE.Vector3 (+0.5, -0.5, 0),
new THREE.Vector3 (-0.5, +0.5, 0),
new THREE.Vector3 (+0.5, +0.5, 0)
);
// Création des deux faces.
geometry.faces.push (
new THREE.Face3 (0, 1, 2),
new THREE.Face3 (2, 1, 3)
);
var geometry = new THREE.BufferGeometry ();
geometry.addAttribute ('position',
new THREE.BufferAttribute (
new Float32Array ([
-0.5, -0.5, 0,
+0.5, -0.5, 0,
-0.5, +0.5, 0,
+0.5, +0.5, 0
]), 3));
geometry.setIndex (
new THREE.BufferAttribute (
new Uint16Array ([
0, 1, 2,
2, 1, 3
]), 1));
Chargement asynchrone d'un maillage JSON
// Gestionnaire de chargement.
var loader = new THREE.BufferGeometryLoader ();
// Déclenchement d'un chargement.
loader.load ('00/teapot.json',
function (geometry) {
var m = new THREE.MeshBasicMaterial ();
scene.add (new THREE.Mesh (geometry, m));
});
// Activation du test de profondeur.
gl.enable (gl.DEPTH_TEST);
// Mode de filtrage : fragments les plus proches.
gl.depthFunc (gl.LESS);
// Effacement simultané des deux buffers.
gl.clear (gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
// Activation du culling.
gl.enable (gl.CULL_FACE);
// Élimination des faces arrières :
// gl.FRONT, gl.BACK ou gl.FRONT_AND_BACK.
gl.cullFace (gl.BACK);
// Activation du blending.
gl.enable (gl.BLEND);
// Définition des facteurs de blending.
gl.blendFunc (src, dst);
T. Porter & T. Duff. Compositing Digital Images. Computer Graphics 18(3):253-259, July 1984.
src | dst | R | G | B | A |
---|
Scalaires | float | int | uint | bool |
---|---|---|---|---|
Vecteurs | vec2 | ivec2 | uvec2 | bvec2 |
vec3 | ivec3 | uvec3 | bvec3 |
|
vec4 | ivec4 | uvec4 | bvec4 |
|
Matrices | mat2 | mat3x2 | mat4x2 |
|
mat2x3 | mat3 | mat4x3 |
||
mat2x4 | mat3x4 | mat4 |
const
uniform
#version 100
attribute
varying
#version 300 es
in
out
x
y
z
w
/
r
g
b
a
/
s
t
p
q
vec4 v1;
float f = v1.x + v1.y;
vec2 v2 = vec2 (1, 2);
vec4 v3 = v2.xyxx; // 1 2 1 1
vec3 v4 = v3.zyy; // 1 2 2
vec4 v5;
v5.wzyx = vec4 (1, 2, 3, 4); // 4 3 2 1
v5.zx = vec2 (5, 6); // 6 3 5 1
varying
:gl_Position
#version 300 es
precision mediump float;
in vec2 position;
void main ()
{
gl_Position = vec4 (position, 0.0, 1.0);
}
varying
(interpolation bilinéaire)gl_FragColor
#version 100
precision mediump float;
uniform vec4 color;
// out vec4 gl_FragColor
void main ()
{
gl_FragColor = color;
}
#version 300 es
precision mediump float;
uniform vec4 color;
out vec4 fragment;
void main ()
{
fragment = color;
}
// Crée un objet texture.
var texture = gl.createTexture ();
// Associe la texture à l'unité 2D.
gl.bindTexture (gl.TEXTURE_2D, texture);
// Transfère les pixels dans la texture 2D actuelle.
var pixels = new Uint8Array ([…]);
gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGB,
w, h, 0,
gl.RGB, gl.UNSIGNED_BYTE, pixels);
// Libère l'objet texture.
gl.deleteTexture (texture);
// Élément <img>
var image = document.getElementById ('huey');
gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA,
gl.RGBA, gl.UNSIGNED_BYTE, image);
// Élément <canvas>
var canvas = document.getElementById ('dewey');
gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA,
gl.RGBA, gl.UNSIGNED_BYTE, canvas);
// Élément <video>
var video = document.getElementById ('louie');
gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA,
gl.RGBA, gl.UNSIGNED_BYTE, video);
gl.texParameteri (gl.TEXTURE_2D, param, value);
Deux paramètres à configurer pour le filtrage :
gl.TEXTURE_WRAP_S | abscisses dans l'espace texture |
gl.TEXTURE_WRAP_T | ordonnées dans l'espace texture |
Trois modes possibles :
gl.CLAMP_TO_EDGE | coordonnée bornée entre 0 et 1 |
gl.REPEAT | répétition de la texture |
gl.MIRRORED_REPEAT | répétition avec réflexion |
gl.CLAMP_TO_EDGE |
gl.REPEAT |
gl.MIRRORED_REPEAT |
gl.texParameteri (gl.TEXTURE_2D, param, value);
Deux paramètres à configurer pour le filtrage :
gl.TEXTURE_MIN_FILTER | la texture est réduite à l'écran |
gl.TEXTURE_MAG_FILTER | la texture est agrandie à l'écran |
Deux modes possibles (pour l’instant) :
gl.NEAREST | couleur du pixel le plus proche |
gl.LINEAR | couleur interpolée linéairement |
gl.NEAREST |
gl.LINEAR |
32×32 | 16×16 | 8×8 | 4×4 | 2×2 | 1×1 |
gl.generateMipmap (gl.TEXTURE_2D);
gl.TEXTURE_MIN_FILTER
gl.NEAREST_MIPMAP_NEAREST |
mipmap le plus proche |
gl.LINEAR_MIPMAP_NEAREST |
|
gl.NEAREST_MIPMAP_LINEAR |
interpolation mipmaps |
gl.LINEAR_MIPMAP_LINEAR |
// EXT_texture_filter_anisotropic.
if (e = gl.getExtension ('EXT_texture_filter_anisotropic'))
{
// Valeur maximale supportée par l'implémentation.
var m = gl.getParameter (e.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
// Application à la texture courante.
gl.texParameterf (gl.TEXTURE_2D, e.TEXTURE_MAX_ANISOTROPY_EXT, m);
}
OpenGL s'est longtemps limité aux textures
dont chaque dimension était une puissance de deux.
Cette contrainte affecte toujours OpenGL ES 2.0
et l'usage de textures « NPOT » reste limité :
Déterminent la couleur en chaque point de la surface
en fonction de propriétés optiques ou empiriques.
Comportement vis-à-vis de la lumière qui l'atteint.
Ensemble de caractéristiques propre à chaque objet :
Ombrage plat | Ombrage de Gouraud | Ombrage de Phong |
---|---|---|
1 normale pour 1 facette | 1 normale pour 1 sommet | 1 normale pour 1 fragment |
couleur uniforme | interpolation de la couleur | interpolation de la normale |