Sombras en Tiempo Real y Oclusión Ambiental con SDF

EN NL ES PT-BR


Los efectos de renderizado basados en SDF van más allá de las superficies primarias trazadas con sphere tracing que se cubren en el artículo del hub. Los campos de distancia también impulsan dos efectos de iluminación que son difíciles de lograr bien con los mapas de sombras tradicionales: sombras suaves con penumbra uniforme y oclusión ambiental sin una pasada de screen-space. Este artículo explica las matemáticas detrás de ambos, recorre el GLSL y compara los resultados con el pipeline estándar de mapas de sombras.

Para los fundamentos del sphere tracing y el gradiente del SDF, comienza con la visión general de los Campos de Distancia con Signo . Para el contexto a nivel de motor, consulta los SDF en el desarrollo de videojuegos .

Sombras Suaves con Campos de Distancia

Las sombras suaves de luces de área son costosas con mapas de sombras porque necesitas muestrear la fuente de luz en múltiples posiciones y promediar los resultados. Los mapas de sombras también producen aliasing severo en ángulos rasantes y necesitan cascadas para escenas grandes.

Las sombras suaves con campos de distancia aproximan la penumbra de las luces de área avanzando un rayo secundario desde cada punto de superficie hacia la fuente de luz y registrando qué tan cerca pasa el rayo de la geometría oclusora. La distancia mínima al oclusor a lo largo del rayo determina la suavidad de la sombra:

float sdfSoftShadow(vec3 origin, vec3 lightDir, float maxDist, float softness,
                    SDF scene) {
    float res = 1.0;
    float t = 0.02;  // Start slightly off the surface to avoid self-occlusion

    for (int i = 0; i < MAX_SHADOW_STEPS; i++) {
        float d = evaluateSDF(origin + lightDir * t, scene);
        // The closer the ray passes to an occluder, the darker the shadow
        res = min(res, softness * d / t);
        t += clamp(d, 0.01, 0.5);
        if (res < 0.001 || t > maxDist) break;
    }
    return clamp(res, 0.0, 1.0);
}

La idea clave está en la línea softness * d / t. Cuando el rayo pasa lejos de cualquier superficie, d se mantiene grande y res permanece cerca de 1.0 (completamente iluminado). Cuando el rayo roza cerca de un oclusor, d se vuelve pequeño, d / t se reduce y res cae hacia 0.0 cerca del contacto. El parámetro softness controla qué tan amplia es la penumbra: valores mayores extienden el borde de la sombra sobre una región más amplia.

Un ejemplo práctico hace concreta la proporción. A una distancia de paso t=1.0t = 1.0 a lo largo del rayo de luz, el campo lee d=0.1d = 0.1, lo que significa que el rayo pasa a 0.1 unidades de una superficie. Con softness = 8.0, la contribución es 8.00.1/1.0=0.88.0 \cdot 0.1 / 1.0 = 0.8, así que ese paso atenúa el resultado al 80% de brillo. Si el rayo pasa dos veces más cerca, d=0.05d = 0.05, la contribución es 8.00.05/1.0=0.48.0 \cdot 0.05 / 1.0 = 0.4, y el punto cae al 40% de brillo. La penumbra es la región donde esta proporción interpola entre los valores completamente iluminados y completamente sombreados, y el parámetro softness estira o comprime esa región.

Esto produce sombras suaves y físicamente plausibles con un solo rayo por punto de superficie, sin límites de resolución de mapas de sombras ni costuras de cascadas. El costo son los pasos adicionales de ray-marching dentro del bucle de sombras, pero esos pasos evalúan el mismo SDF que el rayo primario ya usó, así que no se necesitan nuevas estructuras de datos. Cuando la escena ya es un SDF, la pasada de sombras es solo un segundo bucle sobre la misma función.

Oclusión Ambiental con SDF

La oclusión ambiental mide qué tan ocluido está un punto de superficie por la geometría cercana. En un pipeline de mallas, esto requiere muestreo en screen-space (SSAO) o mapas de oclusión pre-horneados. Con un SDF, la oclusión ambiental se puede calcular directamente durante la pasada de sombreado muestreando el campo de distancia en un hemisferio alrededor del punto de superficie:

float sdfAmbientOcclusion(vec3 position, vec3 normal, float radius,
                           SDF scene) {
    float occlusion = 0.0;
    float weightSum = 1e-6;

    for (int i = 0; i < AO_SAMPLES; i++) {
        vec3 dir = sampleHemisphere(normal, i, AO_SAMPLES);
        float t = 0.01;
        float sampleOcclusion = 0.0;

        // March a short ray into the hemisphere
        for (int j = 0; j < AO_STEPS; j++) {
            float d = evaluateSDF(position + dir * t, scene);
            // If we are inside nearby geometry, accumulate occlusion
            sampleOcclusion += max(0.0, -d) / (1.0 + t);
            t += max(abs(d), 0.01);
            if (t > radius) break;
        }

        float weight = 1.0 / (1.0 + t);
        occlusion += sampleOcclusion * weight;
        weightSum += weight;
    }
    return 1.0 - occlusion / weightSum;
}

Cada dirección de muestra avanza un rayo corto hacia afuera desde la superficie y acumula oclusión cada vez que la distancia se vuelve negativa (dentro de la geometría cercana). El denominador 1.0 + t hace que los oclusores cercanos contribuyan más que los lejanos. Un rayo de muestra que golpea geometría justo al lado del punto de superficie acumula un término de oclusión grande; un rayo que sale al espacio abierto acumula nada y contribuye un peso grande al promedio final, manteniendo el resultado brillante.

Un ejemplo práctico: un rayo de muestra a una distancia de paso t=0.5t = 0.5 lee d=0.2d = -0.2, lo que significa que el rayo está dentro de geometría cercana. El término contribuido es max(0,0.2)/(1+0.5)=0.133\max(0, 0.2) / (1 + 0.5) = 0.133 y el peso para esta dirección es 1/(1+0.5)=0.6671 / (1 + 0.5) = 0.667, así que esta dirección arrastra el promedio hacia lo ocluido. En terreno abierto, cada dirección de muestra lee distancias positivas, cada término de oclusión es cero y el resultado permanece en 1.0.

Esto produce sombras de contacto en grietas y bajo salientes sin necesidad de una pasada de screen-space separada ni de precomputación. Comparte el SDF existente del renderizador, así que la geometría dinámica se maneja automáticamente: mueve una caja y la respuesta de AO se mueve con ella, sin re-horneado y sin artefactos de screen-space.

Comparación con los Mapas de Sombras

PropiedadMapas de sombrasSombras SDF
Costo de configuraciónUna pasada de render por luzNinguno (usa el SDF existente)
Costo por píxelUna muestra de textura (dura) / varias (suave)Múltiples evaluaciones de SDF
AliasingLimitado por resolución, necesita cascadasSuave por construcción
Geometría dinámicaGratis (re-renderizar el mapa de sombras)Gratis (el SDF se actualiza con la escena)
Mundos grandesNecesita mapas de sombras en cascadaUn solo SDF cubre todo
Sombras semitransparentesDifícilNatural (basado en distancia)

Las sombras SDF no son un reemplazo universal para los mapas de sombras. Los mapas de sombras son más rápidos para sombras duras de luces direccionales distantes en escenas estáticas. Las sombras SDF sobresalen cuando necesitas penumbra suave, cuando la escena ya está representada como un SDF, o cuando la geometría dinámica cambia la oclusión en cada fotograma.

Las limitaciones merecen exponerse con claridad. Los bucles de sombras y AO añaden costo de ray-marching encima del rayo primario, así que una escena completamente rasterizada con mallas y sombras en screen-space puede ser más barata en total. Y la calidad de ambos efectos depende de la garantía de distancia del campo: un campo muestreado o suavizado que sobreestima la distancia puede permitir que los rayos de sombra atraviesen oclusores delgados, así que efectos como estos son más confiables en campos analíticos exactos o en rejillas cuidadosamente horneadas con límites de paso conservadores.

Resumen

Dos efectos de iluminación surgen del mismo contrato de los SDF:

  • Sombras suaves avanzan un rayo hacia la luz y registran la aproximación más cercana a la geometría, softness * d / t, que estima el ancho de la penumbra a partir de un solo rayo.
  • Oclusión ambiental avanza rayos cortos hacia un hemisferio y acumula -d / (1 + t) dondequiera que el campo se vuelva negativo, produciendo sombras de contacto sin una pasada de screen-space.

Ambos efectos reutilizan el SDF de la escena, así que la geometría dinámica es gratis y no se aplican límites de resolución de mapas de sombras. Cuando el resto de la escena ya está basado en campos, son la ruta de iluminación natural; la inmersión profunda en terreno destructible muestra el mismo campo impulsando la geometría que estas pasadas iluminan.