Interface de programmation en JavaScript pour le rendu 2D/3D adaptée aux accélérateurs graphiques (GPU)
Expose OpenGL ES 2.0 / 3.0 via un contexte de rendu associé à un élément HTML canvas
Historique:
Point de départ: récupérer un contexte WebGL (HTML5 Canvas)
Code HTML
Code JavaScript
var canvas = document.getElementById('canvas');
var gl = canvas.getContext('webgl');
if (!gl)
return;
// Call WebGL methods gl.*
Géométrie stockée dans des vertex buffers
(tableaux de données résidant en mémoire du GPU)
var positions = [
// 2 triangles for +z face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// ...
];
var positionArray = new Float32Array(positions);
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positionArray, gl.STATIC_DRAW)
gl.bindBuffer(gl.ARRAY_BUFFER, null);
À rapprocher de beginShape()
/ endShape()
en Processing
Type de géométrie (triangles, bande de triangles, points, lines) spécifié lors de l'appel à la fonction de rendu DrawArrays()
var numVertices = positions.length / 3;
gl.DrawArrays(gl.TRIANGLES, 0, numVertices);
Shaders écrits avec un langage de programmation dédié: GLSL ES
Syntaxe dérivée du C
Additions majeures:
vec(2|3|4)
, mat(2|3|4)
vec3(1.0, 2.0, 3.0).zy
in
, out
, inout
sin
, cos
, ..., clamp
, mix
, smoothstep
) et autres (distance
, cross
, reflect
, ...)
attribute
(vertex), uniform
(globale) et varying
(interpolée)gl_Position
(vertex), gl_FragCoord
(fragment)main()
Limitations:
Exemple de vertex shader:
Transformation de position et copie de normale
Code GLSL
attribute vec3 aPosition;
attribute vec3 aNormal;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
varying vec3 vNormal;
void main() {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
vNormal = aNormal;
}
Exemple de fragment shader: modèle simplifié d'illumination
Code GLSL
precision highp float;
varying vec3 vNormal;
uniform vec3 uAmbient;
uniform vec3 uDiffuse;
uniform vec3 uLightVector;
void main() {
vec3 color = uAmbient;
color += uDiffuse * max(dot(vNormal, normalize(uLightVector)), 0.0);
gl_FragColor = vec4(color, 1.0);
}
Compiler un vertex shader à partir du code GLSL sous forme de chaîne de charactère (shaderSource
)
Code WebGL
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
// Use gl.FRAGMENT_SHADER for fragment shaders
gl.shaderSource(vertexShader, shaderSource);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(vertexShader));
// ...
}
Lier un vertex shader et un fragment shader
en un shader program utilisable avec le pipeline de rendu
Code WebGL
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.log(gl.getProgramInfoLog(program));
// ...
}
gl.useProgram(program);
Attributs de vertex
Code WebGL
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
var location = gl.getAttribLocation('aPosition');
gl.enableVertexAttribArray(location);
gl.vertexAttribPointer(location, 3, gl.FLOAT, false, 0, 0);
Variables uniformes
Code WebGL
var projectionMatrix = [ /* ... */ ];
var location = gl.getUniformLocation('uProjectionMatrix');
gl.uniformMatrix4fv(location, false, projectionMatrix);
Code JavaScript
function setup() {
// ...
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// ...
}
function draw() {
gl.viewport(0, 0, WIDTH, HEIGHT);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// ...
}
Gestion d'évènements et animation
Code JavaScript
window.addEventListener('mousemove', handleMouse, false);
// ...
window.requestAnimationFrame(canvas, animationLoop);
3D Gravity Well (Marvin K)
Portage simple WebGL:
Taille du code:
3D Gravity Well (Marvin K)
Améliorations possibles en WebGL:
Améliore la perception de la profondeur
`C_(p ixel)^' = (1 - t) C_(p ixel) + t C_(fog)`
`t = 1 - e^(-(rho d)^2)`
avec `d`: distance camera-oeil-origine / point de la scène,
et `rho`: densité de brouillard
Alternatives:
`t = (d - d_min) / (d_max - d_min)` ou `t = 1 - e^(-rho d)`