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 ​