Skip to content

Fundamentos de WebGL para desenvolvedores de jogos

O WebGL oferece acesso direto à GPU no navegador. Ele é a base dos jogos web 3D (e 2D de alto desempenho). Este tutorial aborda os conceitos essenciais.

1) Obtendo um 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')
}

Prefira webgl2 quando estiver disponível — ele é amplamente compatível e oferece recursos melhores.

2) O pipeline de renderização (simplificado)

  1. O shader de vértice é executado uma vez por vértice. Ele posiciona sua geometria.
  2. O shader de fragmento é executado uma vez por pixel. Ele colore a saída.
  3. Os buffers armazenam dados (posições, UVs, cores).
  4. As texturas são imagens amostradas pelos shaders.

3) Um par mínimo de shaders

Shader de vértice:

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

Shader de fragmento:

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

4) Compilando e vinculando 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) Criando buffers

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) Conectando buffers aos shaders

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

7) O loop do jogo

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) Carregando 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, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img)
    gl.generateMipmap(gl.TEXTURE_2D)
  }
  img.src = url
  return texture
}

9) Armadilhas comuns

  • Texturas com dimensões em potências de dois não são estritamente obrigatórias no WebGL 2, mas os mipmaps funcionam melhor com elas.
  • Perda de contexto: trate os eventos webglcontextlost — navegadores móveis descartam contextos quando há pressão sobre a memória.
  • Texturas de ponto flutuante exigem a verificação de extensões (EXT_color_buffer_float).

10) Quando usar uma biblioteca

O WebGL puro é verboso. Para a maioria dos jogos, considere:

  • Three.js — 3D completo
  • PixiJS — renderização 2D rápida
  • PlayCanvas — engine de jogos com editor

Use WebGL puro quando precisar de:

  • controle máximo
  • um renderizador personalizado
  • aprender como as coisas realmente funcionam

Uma observação para 2026: o WebGPU agora vem ativado por padrão em todos os principais navegadores (Chrome e Edge desde a versão 113, Firefox 141 no Windows e 145 no macOS, e Safari no iOS 26, iPadOS 26 e macOS Tahoe 26). Os fundamentos apresentados aqui ainda se aplicam, pois bibliotecas como Three.js executam seu renderizador WebGPU com fallback automático para WebGL 2, então o WebGL 2 continua sendo uma base confiável. Se você está começando hoje um novo renderizador do zero, leia o tutorial de WebGPU junto com este antes de escolher uma API.

Conteúdo relacionado

Recursos externos