Skip to content

Fundamentos de WebGL para desarrolladores de juegos

WebGL te da acceso directo a la GPU desde el navegador. Es la base de los juegos web 3D (y de los juegos 2D de alto rendimiento). Este tutorial cubre los conceptos esenciales.

1) Obtener un contexto WebGL

js
const canvas = document.getElementById('game')
const gl = canvas.getContext('webgl2') || canvas.getContext('webgl')

if (!gl) {
  // Fallback or error message
  console.error('WebGL not supported')
}

Prefiere webgl2 cuando esté disponible: es ampliamente compatible y ofrece mejores prestaciones.

2) El pipeline de renderizado (simplificado)

  1. El shader de vértices se ejecuta una vez por vértice. Posiciona la geometría.
  2. El shader de fragmentos se ejecuta una vez por píxel. Colorea el resultado.
  3. Los búferes almacenan datos (posiciones, coordenadas UV y colores).
  4. Las texturas son imágenes que los shaders muestrean.

3) Un par mínimo de shaders

Shader de vértices:

glsl
#version 300 es
in vec2 a_position;
void main() {
  gl_Position = vec4(a_position, 0.0, 1.0);
}

Shader de fragmentos:

glsl
#version 300 es
precision mediump float;
out vec4 fragColor;
void main() {
  fragColor = vec4(1.0, 0.5, 0.2, 1.0); // orange
}

4) Compilar y enlazar shaders

js
function createShader(gl, type, source) {
  const shader = gl.createShader(type)
  gl.shaderSource(shader, source)
  gl.compileShader(shader)
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    console.error(gl.getShaderInfoLog(shader))
    gl.deleteShader(shader)
    return null
  }
  return shader
}

function createProgram(gl, vs, fs) {
  const program = gl.createProgram()
  gl.attachShader(program, vs)
  gl.attachShader(program, fs)
  gl.linkProgram(program)
  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.error(gl.getProgramInfoLog(program))
    return null
  }
  return program
}

5) Crear búferes

js
const positions = new Float32Array([
  -0.5, -0.5,
   0.5, -0.5,
   0.0,  0.5,
])

const buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)

6) Conectar los búferes con los shaders

js
const positionLoc = gl.getAttribLocation(program, 'a_position')
gl.enableVertexAttribArray(positionLoc)
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0)

7) El bucle del juego

js
function render() {
  gl.viewport(0, 0, canvas.width, canvas.height)
  gl.clearColor(0, 0, 0, 1)
  gl.clear(gl.COLOR_BUFFER_BIT)

  gl.useProgram(program)
  gl.drawArrays(gl.TRIANGLES, 0, 3)

  requestAnimationFrame(render)
}
render()

8) Cargar texturas

js
function loadTexture(gl, url) {
  const texture = gl.createTexture()
  gl.bindTexture(gl.TEXTURE_2D, texture)

  // Placeholder pixel until image loads
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
    new Uint8Array([255, 0, 255, 255]))

  const img = new Image()
  img.onload = () => {
    gl.bindTexture(gl.TEXTURE_2D, texture)
    gl.texImage2D(gl.TEXTURE_2D, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img)
    gl.generateMipmap(gl.TEXTURE_2D)
  }
  img.src = url
  return texture
}

9) Errores habituales

  • Las texturas con dimensiones que son potencias de dos no son estrictamente necesarias en WebGL 2, pero los mipmaps funcionan mejor con ellas.
  • Pérdida del contexto: gestiona los eventos webglcontextlost; los navegadores móviles liberan contextos cuando hay presión sobre la memoria.
  • Las texturas de coma flotante requieren comprobar la extensión (EXT_color_buffer_float).

10) Cuándo usar una biblioteca

WebGL puro requiere mucho código. Para la mayoría de los juegos, considera:

  • Three.js — 3D con todas las funciones
  • PixiJS — renderizado 2D rápido
  • PlayCanvas — motor de juegos con editor

Usa WebGL puro cuando necesites:

  • control máximo
  • un renderizador personalizado
  • aprender cómo funcionan realmente las cosas

Una nota para 2026: WebGPU ya viene activado de forma predeterminada en todos los navegadores principales (Chrome y Edge desde la versión 113, Firefox 141 en Windows y 145 en macOS, y Safari en iOS 26, iPadOS 26 y macOS Tahoe 26). Los fundamentos explicados aquí siguen siendo aplicables, ya que bibliotecas como Three.js ejecutan su renderizador WebGPU con WebGL 2 como alternativa automática, por lo que WebGL 2 continúa siendo la base más fiable. Si hoy vas a crear un renderizador nuevo desde cero, lee el tutorial de WebGPU junto con este antes de comprometerte con una API.

Contenido relacionado

Recursos externos