Parte: 12 — Juegos web y HTML5 · Fuente: MDN Web Docs — WebGL API y Khronos WebGL2 ⏱️ Duración estimada: 80 min · Nivel: Intermedio
Three.js y PixiJS son cómodos porque esconden WebGL, la API de bajo nivel que habla directamente con la GPU. En esta clase levantarás el capó: WebGL/WebGL2 es OpenGL ES dentro del navegador, y para dibujar cualquier cosa necesitas darle datos (buffers de vértices), un programa de sombreado en GLSL (un vertex shader y un fragment shader) y una orden de dibujo (draw call).
El laboratorio es el clásico rito de iniciación gráfica: dibujar un triángulo con WebGL2 puro. Escribirás shaders, subirás vértices a un buffer, los conectarás a un atributo y ejecutarás drawArrays. Al terminar entenderás exactamente qué hacen Three y Pixi por debajo cada cuadro, y tendrás el modelo mental del pipeline gráfico.
Al finalizar, el alumno podrá:
webgl2 desde un canvas.vertexAttribPointer.| # | Tema | Por qué importa |
|---|---|---|
| 1 | Contexto WebGL2 | La puerta a la GPU desde el canvas. |
| 2 | Pipeline gráfico | Modelo mental de cómo se dibuja. |
| 3 | Vertex shader | Coloca cada vértice en pantalla. |
| 4 | Fragment shader | Decide el color de cada píxel. |
| 5 | Programa (link) | Une ambos shaders en algo ejecutable. |
| 6 | Buffers y atributos | Cómo llegan los datos a la GPU. |
| 7 | Draw calls | La orden que dispara el dibujo. |
| 8 | Qué hacen Three/Pixi | Automatizan todo este proceso por ti. |
gl con todas las funciones y constantes. Clave: se obtiene con getContext('webgl2').#version 300 es.gl_Position. Clave: transforma coordenadas al espacio de recorte.out. Clave: define el aspecto de la superficie.bufferData.drawArrays/drawElements que dibuja. Clave: cada una tiene coste; menos es más rápido.Solo necesitas un navegador con soporte WebGL2 (todos los modernos) y un editor. Sirve por HTTP con python -m http.server por consistencia, aunque este ejemplo también funciona en local simple. Abre la consola con F12 para ver errores de compilación de shaders, que son frecuentes al aprender. La referencia es el tutorial de WebGL de MDN (https://developer.mozilla.org/es/docs/Web/API/WebGL_API/Tutorial).
Crea webgl-triangulo/ con index.html y juego.js. El código GLSL irá como cadenas de texto dentro del JS.
Dibujarás un triángulo de colores con WebGL2 puro.
index.html con un canvas y el script:<!DOCTYPE html>
<html lang="es">
<head><meta charset="UTF-8"><title>Triángulo WebGL2</title></head>
<body>
<canvas id="lienzo" width="500" height="500"></canvas>
<script src="juego.js"></script>
</body>
</html>
juego.js, obtén el contexto WebGL2 y define los dos shaders como cadenas GLSL:const canvas = document.getElementById('lienzo');
const gl = canvas.getContext('webgl2');
if (!gl) throw new Error('WebGL2 no está disponible en este navegador.');
// Vertex shader: recibe posición y color por vértice; fija gl_Position.
const vsFuente = `#version 300 es
in vec2 aPos;
in vec3 aColor;
out vec3 vColor;
void main() {
vColor = aColor;
gl_Position = vec4(aPos, 0.0, 1.0);
}`;
// Fragment shader: pinta con el color interpolado entre vértices.
const fsFuente = `#version 300 es
precision mediump float;
in vec3 vColor;
out vec4 color;
void main() {
color = vec4(vColor, 1.0);
}`;
function compilar(tipo, fuente) {
const sh = gl.createShader(tipo);
gl.shaderSource(sh, fuente);
gl.compileShader(sh);
if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
throw new Error('Error de shader: ' + gl.getShaderInfoLog(sh));
}
return sh;
}
const programa = gl.createProgram();
gl.attachShader(programa, compilar(gl.VERTEX_SHADER, vsFuente));
gl.attachShader(programa, compilar(gl.FRAGMENT_SHADER, fsFuente));
gl.linkProgram(programa);
if (!gl.getProgramParameter(programa, gl.LINK_STATUS)) {
throw new Error('Error al enlazar: ' + gl.getProgramInfoLog(programa));
}
gl.useProgram(programa);
// Tres vértices: cada uno con 2 de posición y 3 de color.
const vertices = new Float32Array([
// x, y, r, g, b
0.0, 0.6, 1, 0, 0, // arriba, rojo
-0.6, -0.6, 0, 1, 0, // izquierda, verde
0.6, -0.6, 0, 0, 1, // derecha, azul
]);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
aPos y aColor describiendo cómo leer el buffer (stride de 5 floats):const bytes = 5 * 4; // 5 floats por vértice, 4 bytes cada float.
const locPos = gl.getAttribLocation(programa, 'aPos');
gl.enableVertexAttribArray(locPos);
gl.vertexAttribPointer(locPos, 2, gl.FLOAT, false, bytes, 0);
const locColor = gl.getAttribLocation(programa, 'aColor');
gl.enableVertexAttribArray(locColor);
gl.vertexAttribPointer(locColor, 3, gl.FLOAT, false, bytes, 2 * 4);
gl.clearColor(0.06, 0.09, 0.16, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3); // Dibuja 3 vértices como un triángulo.
Acabas de recorrer a mano el pipeline que Three.js y PixiJS ejecutan por debajo miles de veces por segundo.
requestAnimationFrame.uniform de tiempo al vertex shader para hacer latir el triángulo.getShaderInfoLog.gl.TRIANGLES por gl.LINE_LOOP y describe el resultado.Dibuja un cuadrado (dos triángulos) de colores en las cuatro esquinas que rote de forma continua usando un uniform de ángulo actualizado en un bucle con requestAnimationFrame, aplicando la rotación dentro del vertex shader.
Criterio de aceptación: al abrir la página se ve un cuadrado con degradado de color girando suavemente, la rotación se calcula en el vertex shader mediante un uniform, y la consola no muestra errores de compilación ni de enlace.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| Canvas negro sin triángulo | Faltó clear/drawArrays o el atributo no está enlazado. Revisa el orden de los pasos. |
| "ERROR: version directive must be first" | El #version 300 es no está en la primera línea de la cadena. Quita espacios/saltos antes. |
| Atributo siempre en 0 | No llamaste a enableVertexAttribArray o el nombre no coincide. Verifica getAttribLocation. |
| Colores planos, sin degradado | Declaraste mal in/out entre shaders. El out del vertex debe coincidir con el in del fragment. |
| "gl is null" | El navegador no dio contexto WebGL2. Comprueba soporte y que el id del canvas sea correcto. |
❓ ¿Qué relación hay entre WebGL y OpenGL? WebGL2 es esencialmente OpenGL ES 3.0 expuesto a JavaScript; los conceptos (shaders, buffers, draw calls) son los mismos.
❓ ¿Por qué necesito dos shaders? El vertex shader coloca los vértices y el fragment shader colorea los píxeles resultantes; son etapas obligatorias distintas del pipeline.
❓ ¿Por qué el color se degrada si solo di tres colores? La GPU interpola linealmente los valores out del vertex shader entre vértices antes de pasarlos al fragment shader.
❓ ¿Debo escribir siempre este código? No en producción: Three.js y PixiJS lo generan por ti. Hacerlo a mano una vez te da el modelo mental para depurar rendimiento y efectos.
Clase 219 - Three.js: 3D en el navegador