Calculating a Per-Texel Depth Bias with DDX and DDY for Large PCFs

shadow map技术中经常出现的一个问题就是,当放大阴影的边缘时会出现锯齿状的边界,如下图:

出现这种现象的原因是shadow map的分辨率有限,场景中的相邻的多个fragment会sampler shadow map中的同一个texel,也就是会获取到相同的深度值,于是阴影就产生了这种参差不齐的锯齿状的边界。

   你可以增加shadow map的分辨率来减轻这种状况,但会增加内存的消耗量。

   有一种更好的办法,叫做PCF(percentage-closer-filtering),可以减轻这种锯齿状的阴影效果,产生更加柔和的阴影边界。这种方法的主要思想就是多次采样shadow map,采样原来采样点周围的相邻texel,然后把这些值相加再平均,得到一个值来确定要渲染的fragment是否在阴影中。但是这种方法有一个缺点,就是在shadow map中对周围相邻texel采样的值都要和要渲染的fragment的深度值作比较,这样是不精确的,因为如果被渲染的fragment如果所在的平面角度很大的话,它相邻的fragment的深度值应该和它相差很大,所以我们应该用相邻fragment本身的z值来和在shadow map中取得的相邻的texel值作比较,怎么获取到fragment相邻的fragment在light space中比较精确的深度值呢?这就要用到了hlsl或glsl shader语言为我们提供的ddx/ddy函数了。

    GPU在运行pixel shader时是以2*2个fragment为一单元运行的,所以ddx/ddy的实现方式就是简单的把相应的要求的属性值减去邻居fragment的相应值,得到差值就算作是导数,所以ddx/ddy求得的导数或偏导数是以屏幕坐标screen space的x,y坐标为自变量的,如果我们想要求以其他变量为自变量的函数的导数或偏导数,比如说,PCF这里我们要求待渲染平面的在light space 中的深度z值随x,y坐标(也就是纹理坐标)变化的导数,那怎么求呢?这就要用到高数中多元微积分中的多变量复合函数求导链式法则了,

我们可以先求出待渲染平面上的某顶点的z值关于屏幕坐标screen space的x,y坐标的两个偏导数,然后在求出该顶点的深度纹理坐标x,y分别关于屏幕坐标screen space 的x,y坐标的两个偏导数,这样我们就可以用链式法则求出该点的深度值z关于纹理坐标x,y的偏导数,在一些资料中会生成一个叫雅克比矩阵的中间量来完成这个转换,

下面的代码片段较为清晰的列出了具体怎么实现的,

// Derivatives of light-space depth with respect to texture coordinates
float2 DepthGradient(float2 uv, float z)
{
    float2 dz_duv = 0;

    float3 duvdist_dx = ddx(float3(uv,z));
    float3 duvdist_dy = ddy(float3(uv,z));

    dz_duv.x = duvdist_dy.y * duvdist_dx.z;
    dz_duv.x -= duvdist_dx.y * duvdist_dy.z;
    
    dz_duv.y = duvdist_dx.x * duvdist_dy.z;
    dz_duv.y -= duvdist_dy.x * duvdist_dx.z;

    float det = (duvdist_dx.x * duvdist_dy.y) - (duvdist_dx.y * duvdist_dy.x);
    dz_duv /= det;

    return dz_duv;
}

float BiasedZ(float z0, float2 dz_duv, float2 offset)
{
    return z0 + dot(dz_duv, offset);
}
 

   求出了点的z值关于x,y(texture cordinates)的偏导数后,我们就可以在进行PCF计算时更精确的计算出邻居fragment在light space中的z值,用这个值和shadow map中对应的texel 值进行比较以判断是否处在阴影中,从而消除self shadow等问题,产生更为平滑精确的shadow 边界。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值