WebGL RayMarching Distance Field Soft Shadows

499 阅读1分钟

入门Distance Field Soft Shadows - 知乎 (zhihu.com)

Inigo Quilez :: fractals, computer graphics, mathematics, shaders, demoscene and more (iquilezles.org)

Signed Distance Field(有向距离场)

  • distance field的一个巨大好处就是,它提供了许多全局信息。

Sphere Tracing

float depth = start;
for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
    float dist = sceneSDF(eye + depth * viewRayDirection);
    if (dist < EPSILON) {
        // We're inside the scene surface!
        return depth;
    }
    // Move along the view ray
    depth += dist;
 
    if (depth >= end) {
        // Gone too far; give up
        return end;
    }
}

Distance Field Soft Shadows

image.png

  • 朝着light vector 进行raymarch,直到找到一个相交。
float shadow( in vec3 ro, in vec3 rd, float mint, float maxt )
{
    for( float t=mint; t < maxt; )
    {
        float h = map(ro + rd*t);
        if( h<0.001)
            return 0.0;
        t += h;
    }
    return 1.0;
}
float softshadow( in vec3 ro, in vec3 rd, float mint, float maxt, float k )
{
    float res = 1.0;
    for( float t=mint; t < maxt; )
    {
        float h = map(ro + rd*t);
        if( h<0.001 )
            return 0.0;
        res = min( res, k*h/t );
        t += h;
    }
    return res;
}
  • 下分别是k值的2,8,32 image.png

进一步优化

  • 助消除了一些复杂几何下产出的banding effects image.png
  • 其中白色箭头是我们进行marching的光线,绿点是我们当前的位置,而红点是上一次计算的位置。而两个圆圈分别表示在两个点使用SDF得到的最近距离球。那么我们考虑黄点为场景到光线的最近距离,这个距离用简单的平面几何就计算出来了。话不多说,直接看代码就很清楚了:
float softshadow( in vec3 ro, in vec3 rd, float mint, float maxt, float k )
{
    float res = 1.0;
    float ph = 1e20;
    for( float t=mint; t < maxt; )
    {
        float h = map(ro + rd*t);
        if( h<0.001 )
            return 0.0;
        float y = h*h/(2.0*ph);
        float d = sqrt(h*h-y*y)
        res = min( res, k*d/max(0.0,t-y) );
        ph = h;
        t += h;
    }
    return res;
}

image.png