Tutorial

Entendendo a Renderização Raymarching do WebGL 2.0

Um mergulho na tecnologia Raymarching do WebGL 2.0: aprenda a usar campos de distância assinada SDF para renderização volumétrica em tempo real e entenda como essa técnica leva a GPU ao limite.

🚀 volumeshadertest
3/12
10 min de leitura

Um mergulho profundo em raymarching WebGL 2.0, SDFs e renderização volumétrica em tempo real

O WebGL 2.0 desbloqueia um poderoso conjunto de recursos de GPU, permitindo técnicas avançadas de renderização que tradicionalmente exigiam APIs nativas. Entre essas, o raymarching se destaca como um dos métodos mais expressivos e matematicamente elegantes para renderizar cenas complexas com geometria mínima.

Este artigo explora os conceitos fundamentais por trás do raymarching WebGL 2.0, explica como os Campos de Distância Assinada (SDFs) permitem renderização eficiente e mostra como essa técnica pode extrair desempenho surpreendente da GPU.


1. O que é Raymarching?

Raymarching é um método de renderização onde, em vez de projetar geometria na tela, disparamos um raio da câmera por pixel, movemo-lo passo a passo através de uma cena virtual e avaliamos distâncias até que o raio atinja uma superfície ou alcance um alcance máximo.

1.1 Como o Raymarching Funciona (Diagrama Visual)

Câmera
  |
  | raio
  v
  +--------------------------------- Pixel da Tela
  |
  | passo de marcha 1      (distância d1)
  |
  |---------> passo de marcha 2      (distância d2)
  |
  |-----------------------> passo de marcha 3 ...
  |
Superfície atingida quando distância < ε

Raymarching é essencialmente um loop:

for (int i = 0; i < MAX_STEPS; i++) {
    float dist = sdf(currentPos);
    if (dist < EPSILON) hitSurface();
    currentPos += rayDir * dist;
}

O ingrediente mágico é a função SDF que passamos.


2. O que são Campos de Distância Assinada (SDFs)?

Um Campo de Distância Assinada é uma função que retorna:

> 0  distância fora do objeto  
= 0  exatamente na superfície  
< 0  distância dentro do objeto  

2.1 Diagrama SDF

           fora
        +------------+
        |   d = 0.5  |
        |            |
dentro  |     SDF    | superfície d = 0
d < 0   |            |
        |   d = -0.3 |
        +------------+

2.2 Exemplo: SDF de Esfera

float sdSphere(vec3 p, float r) {
    return length(p) - r;
}

Ao combinar essas formas básicas com operações booleanas (união, subtração, interseção), você pode construir cenas complexas sem qualquer geometria tradicional.


3. Por que usar Raymarching SDF no WebGL 2.0?

3.1 Benefícios

  • Sem buffers de vértices ou malhas necessários Tudo é calculado matematicamente no fragment shader.

  • Detalhe geométrico infinito SDFs definem superfícies suaves e contínuas.

  • Objetos dinâmicos e deformáveis Anima facilmente formas com matemática.

  • Cenas compactas Uma cena 3D completa pode ser definida usando apenas algumas linhas de GLSL.

3.2 Recursos do WebGL 2.0 que tornam isso possível

  • Floats de alta precisão
  • Suporte completo a shaders GLSL ES 3.0
  • UBOs (buffers uniformes)
  • Texturas float
  • Loops e ramificações mais flexíveis

Isso permite raymarching estável e de alto desempenho que era difícil no WebGL 1.0.


4. Construindo um Raymarcher WebGL 2.0 Passo a Passo

4.1 Configuração do Raio da Cena

Calcule um raio para cada pixel:

vec3 rayOrigin = cameraPos;
vec3 rayDir = normalize(uv.x * camRight + uv.y * camUp + camForward);

4.2 O Loop de Raymarch

float marchRay(vec3 ro, vec3 rd) {
    float totalDist = 0.0;

    for (int i = 0; i < MAX_STEPS; i++) {
        vec3 p = ro + rd * totalDist;
        float d = map(p);     // sua função SDF

        if (d < EPSILON) break;    // acerto
        if (totalDist > MAX_DISTANCE) break;  // erro

        totalDist += d;
    }
    return totalDist;
}

4.3 Definindo a Cena SDF

float map(vec3 p) {
    float s = sdSphere(p, 1.0);
    float box = sdBox(p - vec3(2.0, 0.0, 0.0), vec3(0.7));
    return min(s, box); // união
}

4.4 Cálculo da Normal

Usando aproximação de gradiente:

vec3 calcNormal(vec3 p) {
    const vec2 e = vec2(0.001, 0.0);
    return normalize(vec3(
        map(p + e.xyy) - map(p - e.xyy),
        map(p + e.yxy) - map(p - e.yxy),
        map(p + e.yyx) - map(p - e.yyx)
    ));
}

4.5 Modelo de Iluminação

Sombreamento difuso simples:

float diffuse = max(dot(normal, lightDir), 0.0);

5. Renderizando Volumes (Névoa, Nuvens, Fumaça)

Raymarching SDF pode ser estendido para renderização volumétrica, onde cada passo contribui com cor e densidade em vez de parar em uma superfície.

5.1 Diagrama de Volume

Raio →
[baixa densidade] [média] [alta densidade] [opaco]
   +--------+---------+---------+-------+
   amostra1   amostra2   amostra3   amostra4

5.2 Modelo de Acumulação de Volume

vec3 color = vec3(0);
float absorption = 1.0;

for (int i = 0; i < STEPS; i++) {
    float density = computeDensity(p);
    vec3 sampleColor = density * vec3(0.6, 0.7, 1.0);

    color += sampleColor * absorption;
    absorption *= (1.0 - density * 0.1);

    p += rd * STEP_SIZE;
}

Raymarching de volumes é mais caro, mas as melhorias de desempenho do WebGL 2.0 (especialmente em GPUs móveis) tornam nuvens, névoa e nebulosas em tempo real viáveis.


6. Técnicas de Otimização de Desempenho

Raymarching pode ser pesado, então otimizações são essenciais.

6.1 Técnicas Principais

  1. Culling de Distância Pule grandes áreas vazias confiando em distâncias SDF precisas.

  2. Volumes Delimitadores Teste se o raio sequer entra na região onde os SDFs existem.

  3. Tamanho de Passo Adaptativo Use passos menores perto de superfícies, passos maiores em espaço aberto.

  4. Saída Antecipada Pare de marchar assim que a superfície for atingida.

  5. Reduzir MAX_STEPS Valores típicos variam de 64–128 para renderização em tempo real.

  6. Use uniforms e buffers do WebGL 2.0 com eficiência Mova valores que não mudam para fora dos loops.


7. Estrutura de Código para um Projeto WebGL 2.0

Exemplo de layout de diretório:

shader/
  raymarch.vert
  raymarch.frag
src/
  webgl2-context.js
  camera.js
  renderer.js
index.html

Seções típicas de fragment shader:

// 1. Configuração de Câmera/Raio
// 2. Definições SDF
// 3. Funções de Material e Iluminação
// 4. Loop de Raymarch
// 5. Saída de Cor Final

8. Quando Você Deve Usar Raymarching?

Raymarching se destaca quando você quer:

  • Formas suaves infinitas
  • Fractais
  • Cenas de ficção científica
  • Sombras suaves de distância assinada
  • Geometria procedural
  • Efeitos volumétricos (nuvens, névoa, raios de deus)

Evite raymarching quando você precisa:

  • Muitas malhas complexas detalhadas
  • Personagens realistas com skinning
  • Cenas dinâmicas grandes com milhares de objetos

Raymarching é melhor para mundos procedurais e efeitos visuais estilizados.


9. Conclusão

O raymarching WebGL 2.0 traz renderização avançada em tempo real para o navegador usando nada mais que matemática e GLSL. Com SDFs, você pode criar cenas 3D complexas sem um único buffer de vértices. Embora a técnica seja computacionalmente intensiva, otimização cuidadosa permite visuais expressivos que rivalizam com aplicações GPU nativas.

Raymarching representa uma interseção única de matemática, arte e programação GPU, tornando-o uma das técnicas mais emocionantes para explorar no desenvolvimento WebGL moderno.


Como isso se relaciona com o Volume Shader BM Test

Você leu a teoria — agora a ponte prática com a ferramenta. Veja como o que está acima se aplica ao Volume Shader BM Test.

Por que este teste é mais pesado que um demo 3D comum

Um demo WebGL típico desenha alguns milhares de polígonos. Este benchmark pede que a GPU rode um loop de raymarching por pixel — frequentemente mais de 1.000 iterações cada — sem geometria para encurtar o caminho. GPUs de mid-range que rodam jogos a 60 FPS frequentemente caem abaixo de 30 FPS em Heavy.

Por que o FPS cai em celulares

Celulares começam a fazer throttling assim que o SoC esquenta. Os primeiros 10 segundos parecem ótimos, depois o clock da GPU diminui. Ligue na tomada, rode em Light ou Medium e compare por estabilidade, não pelo pico de FPS. Veja o guia de teste GPU para celular.

Por que a primeira execução pode ser mais lenta (compilação de shader)

Na primeira carga o navegador precisa compilar GLSL em binário do driver, e em alguns drivers isso leva centenas de milissegundos — aparecendo como um pequeno engasgo no início. Descarte a primeira execução e use a segunda.

Como comparar resultados de forma justa

Mesmo modo, mesma aba em primeiro plano, mesma fonte de energia. Light, Medium e Heavy não podem ser comparados diretamente porque são cargas diferentes. Veja o guia de FPS.

O que fazer se o navegador estiver usando a GPU integrada

Em laptops com iGPU e dGPU, Chrome / Edge muitas vezes optam pela integrada para poupar bateria. Abra chrome://gpu e verifique GL_RENDERER. Se aparecer a iGPU, force o navegador para a GPU dedicada nas configurações gráficas do sistema. O guia de correção de lag detalha o processo.


Faça o teste

Você já tem a teoria. Rode o benchmark real — leva menos de um minuto.

Iniciar Volume Shader BM Test →

Guias relacionados

Tags
WebGLRaymarchingRenderização de VolumeDesempenho GPU