Capítulo 33
Fragment shader mínimo
2 min de leitura 363 palavras 1 gravura
Demo WebGL própria. Um fragment shader pinta cada pixel com uv e tempo. Não é republicação de livro.
Trabalhe sobre uma cópia da pasta inicio do exemplo correspondente. Leia, digite, mude uma coisa, preveja, recarregue e confira. A referência completa fica na raiz da pasta do exemplo, no pacote anexo.
O que você pratica
- uv é?
- u_time anima?
- TRIANGLE_STRIP cobre?

Tela viva
Cores mudam com o tempo.
Erro comum: WebGL indisponível — navegador antigo; use um atual.
Animar
No início falta sin(u_time…). Inclua.
float v = 0.5 + 0.5 * sin(u_time + uv.x * 8.0);
gl_FragColor = vec4(uv.x, v * 0.6, 0.35 + uv.y * 0.4, 1.0);
Pare e experimente. Preveja oscilação no canal verde.
Pipeline mínimo
VS passa canto; FS pinta.
Não publique exercícios com dados reais. Conteúdo fictício de Recife.
Como o exemplo desta etapa funciona
A referência desta etapa reúne app.js, index.html, styles.css. Abra o resultado pronto, localize o trecho que produz fragment shader minimo e só então compare com inicio. Os dois diretórios são independentes: você pode errar, restaurar e repetir sem buscar arquivos de outro capítulo.
Leitura do resultado
Observe primeiro o que permanece parado e o que responde a uma ação. Depois altere um único número, cor, coordenada ou condição. Antes de recarregar, escreva o efeito esperado. Essa previsão separa uma mudança compreendida de uma tentativa ao acaso.
Diagnóstico guiado
Se a cena sumir, confira a primeira mensagem do Console e o caminho dos arquivos. Em SVG, revise viewBox, atributos e ordem das formas. Em p5.js, confirme a biblioteca local e se setup e draw foram escritos corretamente. Em Canvas ou WebGL, verifique o contexto e os limites numéricos antes de mudar outra coisa.
Critério de avanço
Avance quando conseguir descrever a cena, modificar um parâmetro com previsão e restaurar a referência sem copiar arquivos de uma etapa posterior.
Atividades
- precision mediump?
- uniform vem do JS?
- Copiar livro de shaders?
Respostas comentadas
Só abra depois de tentar.
Atividade 1. Precisão no ES 2.0.
Atividade 2. Sim, u_res e u_time.
Atividade 3. Não — demos próprias.
Exemplo deste capítulo: pacote de exemplos/33-shader-minimo/.
O arquivo completo
Referência do exemplo 33-shader-minimo, reproduzida aqui para que você possa conferir sem sair da página.
index.html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Shader mínimo — Laboratório da Luz</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<a class="skip" href="#conteudo">Ir ao conteúdo</a>
<header>
<p class="tag">Laboratório da Luz · Recife</p>
<h1>Shader mínimo</h1>
</header>
<main id="conteudo">
<p class="dica">Shader mínimo — demo WebGL própria deste curso (não é cópia de livro).</p>
<div class="stage"><canvas id="gl" width="480" height="280" aria-label="Shader"></canvas></div>
</main>
<footer>
<p>Conteúdo fictício para estudo local. Não publique dados reais.</p>
</footer>
<script src="app.js"></script>
</body>
</html>
app.js
const canvas = document.getElementById("gl");
const gl = canvas.getContext("webgl");
const vsSource = `attribute vec2 a_pos; void main(){ gl_Position = vec4(a_pos,0.0,1.0); }`;
const fsSource = `precision mediump float;
uniform vec2 u_res;
uniform float u_time;
void main(){
vec2 uv = gl_FragCoord.xy / u_res;
float v = 0.5 + 0.5 * sin(u_time + uv.x * 8.0);
gl_FragColor = vec4(uv.x, v * 0.6, 0.35 + uv.y * 0.4, 1.0);
}`;
function compile(type, src){
const s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) console.error(gl.getShaderInfoLog(s));
return s;
}
const prog = gl.createProgram();
gl.attachShader(prog, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(prog); gl.useProgram(prog);
const buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);
const loc = gl.getAttribLocation(prog, "a_pos");
gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
const uRes = gl.getUniformLocation(prog, "u_res");
const uTime = gl.getUniformLocation(prog, "u_time");
const t0 = performance.now();
function frame(now){
gl.viewport(0,0,canvas.width,canvas.height);
gl.uniform2f(uRes, canvas.width, canvas.height);
gl.uniform1f(uTime, (now - t0) / 1000);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);