Pular para o conteúdo
murad.guide

Programação Criativa

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

Fragment shader mínimo

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

  1. precision mediump?
  2. uniform vem do JS?
  3. 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);