Tutorial

Comprensión de la Renderización Raymarching de WebGL 2.0

Profundiza en la tecnología Raymarching de WebGL 2.0, aprende cómo usar campos de distancia con signo SDF para renderizado de volumen en tiempo real y cómo esta técnica lleva el rendimiento de la GPU al límite.

🚀 volumeshadertest
Hace 4 días
10 min de lectura

Una inmersión profunda en raymarching WebGL 2.0, SDFs y renderizado volumétrico en tiempo real

WebGL 2.0 desbloquea un poderoso conjunto de características de GPU, permitiendo técnicas avanzadas de renderizado que tradicionalmente requerían APIs nativas. Entre estas, el raymarching se destaca como uno de los métodos más expresivos y matemáticamente elegantes para renderizar escenas complejas con geometría mínima.

Este artículo explora los conceptos fundamentales detrás del raymarching WebGL 2.0, explica cómo los Campos de Distancia con Signo (SDFs) permiten renderizado eficiente y muestra cómo esta técnica puede extraer un rendimiento sorprendente de la GPU.


1. ¿Qué es Raymarching?

Raymarching es un método de renderizado donde, en lugar de proyectar geometría en la pantalla, disparamos un rayo desde la cámara por píxel, lo movemos paso a paso a través de una escena virtual y evaluamos distancias hasta que el rayo golpea una superficie o alcanza un rango máximo.

1.1 Cómo Funciona el Raymarching (Diagrama Visual)

Cámara
  |
  | rayo
  v
  +--------------------------------- Píxel de Pantalla
  |
  | paso de marcha 1      (distancia d1)
  |
  |---------> paso de marcha 2      (distancia d2)
  |
  |-----------------------> paso de marcha 3 ...
  |
Superficie alcanzada cuando distancia < ε

Raymarching es esencialmente un bucle:

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

El ingrediente mágico es la función SDF que pasamos.


2. ¿Qué son los Campos de Distancia con Signo (SDFs)?

Un Campo de Distancia con Signo es una función que devuelve:

> 0  distancia fuera del objeto  
= 0  exactamente en la superficie  
< 0  distancia dentro del objeto  

2.1 Diagrama SDF

           fuera
        +------------+
        |   d = 0.5  |
        |            |
dentro  |     SDF    | superficie d = 0
d < 0   |            |
        |   d = -0.3 |
        +------------+

2.2 Ejemplo: SDF de Esfera

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

Al combinar estas formas básicas con operaciones booleanas (unión, sustracción, intersección), puedes construir escenas complejas sin ninguna geometría tradicional.


3. ¿Por qué usar Raymarching SDF en WebGL 2.0?

3.1 Beneficios

  • No se necesitan buffers de vértices o mallas Todo se calcula matemáticamente en el fragment shader.

  • Detalle geométrico infinito Los SDFs definen superficies suaves y continuas.

  • Objetos dinámicos y deformables Anima fácilmente formas con matemáticas.

  • Escenas compactas Una escena 3D completa puede definirse usando solo unas pocas líneas de GLSL.

3.2 Características de WebGL 2.0 que lo hacen posible

  • Floats de alta precisión
  • Soporte completo de shaders GLSL ES 3.0
  • UBOs (buffers uniformes)
  • Texturas float
  • Bucles y ramificaciones más flexibles

Esto permite raymarching estable y de alto rendimiento que era difícil en WebGL 1.0.


4. Construyendo un Raymarcher WebGL 2.0 Paso a Paso

4.1 Configuración del Rayo de la Escena

Calcula un rayo para cada píxel:

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

4.2 El Bucle 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);     // tu función SDF

        if (d < EPSILON) break;    // impacto
        if (totalDist > MAX_DISTANCE) break;  // fallo

        totalDist += d;
    }
    return totalDist;
}

4.3 Definiendo la Escena 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ón
}

4.4 Cálculo de la Normal

Usando aproximación 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 Iluminación

Sombreado difuso simple:

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

5. Renderizando Volúmenes (Niebla, Nubes, Humo)

Raymarching SDF puede extenderse a renderizado volumétrico, donde cada paso contribuye color y densidad en lugar de detenerse en una superficie.

5.1 Diagrama de Volumen

Rayo →
[baja densidad] [media] [alta densidad] [opaco]
   +--------+---------+---------+-------+
   muestra1   muestra2   muestra3   muestra4

5.2 Modelo de Acumulación de Volumen

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 volúmenes es más costoso, pero las mejoras de rendimiento de WebGL 2.0 (especialmente en GPUs móviles) hacen viables nubes, niebla y nebulosas en tiempo real.


6. Técnicas de Optimización de Rendimiento

Raymarching puede ser pesado, por lo que las optimizaciones son esenciales.

6.1 Técnicas Clave

  1. Culling de Distancia Salta grandes áreas vacías confiando en distancias SDF precisas.

  2. Volúmenes Delimitadores Prueba si el rayo incluso entra en la región donde existen los SDFs.

  3. Tamaño de Paso Adaptativo Usa pasos más pequeños cerca de superficies, pasos más grandes en espacio abierto.

  4. Salida Temprana Deja de marchar tan pronto como se golpea la superficie.

  5. Reducir MAX_STEPS Los valores típicos oscilan entre 64–128 para renderizado en tiempo real.

  6. Usa uniforms y buffers de WebGL 2.0 eficientemente Mueve valores que no cambian fuera de los bucles.


7. Estructura de Código para un Proyecto WebGL 2.0

Ejemplo de diseño de directorio:

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

Secciones típicas de fragment shader:

// 1. Configuración de Cámara/Rayo
// 2. Definiciones SDF
// 3. Funciones de Material e Iluminación
// 4. Bucle de Raymarch
// 5. Salida de Color Final

8. ¿Cuándo Deberías Usar Raymarching?

Raymarching se destaca cuando quieres:

  • Formas suaves infinitas
  • Fractales
  • Escenas de ciencia ficción
  • Sombras suaves de distancia con signo
  • Geometría procedural
  • Efectos volumétricos (nubes, niebla, rayos de dios)

Evita raymarching cuando necesites:

  • Muchas mallas complejas detalladas
  • Personajes realistas con skinning
  • Escenas dinámicas grandes con miles de objetos

Raymarching es mejor para mundos procedurales y efectos visuales estilizados.


9. Conclusión

El raymarching WebGL 2.0 lleva renderizado avanzado en tiempo real al navegador usando nada más que matemáticas y GLSL. Con SDFs, puedes crear escenas 3D complejas sin un solo buffer de vértices. Aunque la técnica es computacionalmente intensiva, la optimización cuidadosa permite visuales expresivos que rivalizan con aplicaciones GPU nativas.

Raymarching representa una intersección única de matemáticas, arte y programación GPU, convirtiéndolo en una de las técnicas más emocionantes para explorar en el desarrollo WebGL moderno.

Tags
WebGLRaymarchingRenderizado de VolumenRendimiento GPU

© 2025 Volume Shader BM Test. Original shader core algorithm by cznull.

Disclaimer: Heavy GPU usage may cause high power consumption.