入门Distance Field Soft Shadows - 知乎 (zhihu.com)
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
- 朝着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
进一步优化
- 助消除了一些复杂几何下产出的banding effects
- 其中白色箭头是我们进行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;
}