如何对立方体贴图阴影使用偏置

How to use biasing with cubemap shadows

所以,我还有一个关于阴影贴图的问题。我正在尝试使用立方体贴图阴影实现点光源,并且几乎可以正常工作。

我正在将阴影渲染到 DEPTH_COMPONENT16 类型的立方体贴图中。我进行了 6 次遍历,使用与我对平行光和聚光灯所做的完全相同的着色器。我没有任何颜色输出,只使用深度缓冲区。我认为这应该没问题,因为立方体贴图几乎只有 6 个聚光灯,我没有问题。

现在,当我尝试在我的光照着色器中采样阴影贴图时,我的问题来了。我的渲染器是延迟的,所以我必须从深度重建所有位置。

当我从立方体贴图采样时,我这样做:

// world space fragment to light
vec3 cubeNorm = normalize(w_pos - LB.position);
vec3 absNorm = abs(cubeNorm);
bool xy = absNorm.x > absNorm.y;
bool yz = absNorm.y > absNorm.z;
bool zx = absNorm.z > absNorm.x;
// which cube face will be sampled from
int index = 0; 
if (xy && !zx) index = 0 + int(cubeNorm.x < 0.f);
if (yz && !xy) index = 2 + int(cubeNorm.y < 0.f);
if (zx && !yz) index = 4 + int(cubeNorm.z < 0.f);
// point in light space with small normal offset
vec4 sc = LB.matArr[index] * vec4(w_pos+w_surf*0.06f, 1.f); 
vec4 shadcrd = vec4(cubeNorm, sc.z / sc.w * 0.5f + 0.5f);
// normals in view space
float bias = get_bias(v_surf, dirToPoint);
float vis = sample_shadow(shadcrd, bias, texShad);

get_bias函数:

float get_bias(vec3 _normal, vec3 _lightDir) {
    float lightDot = dot(_normal, -_lightDir);
    float magicTan = sqrt(1.f - lightDot * lightDot) / lightDot;
    return clamp(0.006f * magicTan, 0.f, 0.03f);
}

sample_shadow函数:

float sample_shadow(vec4 _sc, float _bias, samplerCubeShadow _tex) {
    return texture(_tex, vec4(_sc.xyz, _sc.w-_bias));
}

而且,这就是我得到的。我禁用了距离滚降以使问题更容易看到:

因此,偏置无法正常工作。将 get_bias 函数调整为 return 更大的值似乎没有帮助。唯一能去除粉刺的方法似乎是增加了一个巨大的持续偏差,这显然不是一个选择。

为了比较,这是一个聚光灯,在同一个地方以 90 度视野渲染。 shader使用相同的get_bias函数,near/far平面相同(0.2/5.0):

没有偏见问题。我可以只使用 6 个聚光灯(没有圆边),但我宁愿使用立方体贴图。我做错了什么?

解决了。 '这是一个简单的疏忽。该行:

vec3 cubeNorm = normalize(w_pos - LB.position);

应该是正常偏移:

vec3 cubeNorm = normalize((w_pos+w_surf*0.06f) - LB.position);

此外,还有一种更好的方法来获取深度以在答案中进行比较here。不过它确实需要近平面和远平面。