Variance Shadow Maps

来源:互联网 发布:河南省保险数据 编辑:程序博客网 时间:2024/05/17 21:46

1.Shadow Mapping

Shadow mapping是一种two pass的阴影算法,首先从光源的视角渲染出一张深度图depthMap;然后再从camera的角度渲染整个场景,把每一个pixel都投影到depthMap中,然后和depthMap texel中的深度去比较,判断当前pixel是否在阴影中。Shadow mapping的算法是逐像素级的,因此会在边缘留下锯齿的走样痕迹;Shadow mapping算法产生的是一种硬阴影,没有半阴,阴影到非阴影的过渡不真实。Donnelly和Lauritzen就提出了一种阴影软化的方法。

2. Variance Shadow Maps

Variance Shadow Maps算法和标准的Shadow Mapping算法很接近,Variance Shadow Maps算法把depth和depth²存储在depthMap中,然后在特定的区域滤波,获得了深度分布在区域的一阶和二阶矩:

M1=E(x)=xp(x)dxM2=E(x2)=x2p(x)dx

M1,M2可以计算出这个分布的期望和方差:
μ=E(x)=M1σ2=E(x2)E(x)2=M2M21

通过应用切比雪夫不等式,可以得出随机变量x大于当前深度值t的一个概率上限:
P(xt)Pmax(t)=σ2σ2+(tμ)2

这个概率可以看做比率,表示光照射到当前像素的比率,可以直接用在渲染方程中,避免了像素被完全照亮。在计算概率时,为了避免一些数值问题最好给方差一下下限,下面是计算概率的片元着色器代码:

float chebyshevUpperBound(float distance,vec2 texCoord){    vec2 moments = texture(shadowMap,texCoord).rg;    //片元不在阴影里    if (distance <= moments.x)        return 1.0;    //计算片元在阴影里的最大概率上届    float variance = moments.y - (moments.x*moments.x);    variance = max(variance, 0.00002);    float d = distance - moments.x;    float p_max = variance / (variance + d*d);    return p_max;}

2.1 Biasing

Variance shadow map针对shadow biasing问题提供了一种优雅的解决方法,使用二阶矩来表示每个像素上深度的变化范围,考虑每个像素上深度在各个方向的范围复杂度比较高,仅仅考虑在局部平面上的分布,由一下参数方程表示:

f(x,y)=μ+xfx+yfyM2=μ2+14(fx)2+14(fy)2

当光线和面垂直的时候上述公式就变成了深度的平方,通过opengl自带的偏导数函数可以很容易的计算出M2,一下是增加biasing的vertex shader的代码:

in vec4 v_position;out vec4 outColor;void main() {    float depth = v_position.z / v_position.w;    depth = depth * 0.5 + 0.5;    float moment1 = depth;    float moment2 = depth * depth;    float dx = dFdx(depth);    float dy = dFdy(depth);    moment2 += 0.25*(dx*dx+dy*dy);    outColor = vec4( moment1, moment2, 0.0, 0.0);};

2.2 Light Bleeding

Variance shadow maps的一个潜在问题就是光线渗透问题,即在场景的遮挡关系比较复杂的时候软阴影出现的位置错误,如下图的红圈所示:
figure1
出现这个问题是由于切比雪夫不等式计算的只是一个概率上界,并不是精准的概率,从切比雪夫不等式可以得出只有当红色区域的深度值远远大于对应depth中的μ 时,概率才为0。Gpu Gems3中提到一种方法,即当概率小于某个min值的时候,就把概率设为0,来降低影响。

2.3 Numeric Stability

在存储depth和depth²的时候最好使用线性的深度值,而不是opengl默认的深度值,当光源距离场景非常远时depth和depth²的精度损失非常大,使得方差的计算变得不稳定,使用线性的深度值,精度的损失与光源到场景的距离无关,方差的计算更加稳定。因此最后使用光源空间的深度值。

实现代码

基于opengl的实现代码

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 酷翼x9忘了密码怎么办 楼上的路由器楼下不好使怎么办 电信4g网络不好怎么办 农村只有2g网怎么办 电信卡4g网速慢怎么办 小米手机触屏失灵怎么办 荣耀v10电信网速很慢怎么办 华为路由器掉线了怎么办 三星s6只识别一张卡怎么办 华为手机卡不显示了怎么办 华为账号手机卡丢了怎么办 荣耀8耗电量太快怎么办 vivo卡2不显示怎么办 电信宽带玩王者荣耀卡怎么办 联通4g玩游戏卡怎么办 华为悦盒遥控器丢了怎么办 6s不能用电信卡怎么办 iphone6电信卡无服务怎么办 魅族手机电信卡怎么办 小米手机读不出sim卡怎么办 魅蓝note6耗电快怎么办 oppo手机下载密码忘了怎么办 华为v9玩飞车卡怎么办 苹果7耳机转换器不支持怎么办 华为mate10耳机声音小怎么办 200打一年到期了怎么办 手机欠费变成2g怎么办 手机4g网用不了怎么办 手机玩王者荣耀卡怎么办 华为隐私空间密码忘记了怎么办 华为手机王者太卡怎么办 华为手机太卡怎么办呢 华为手机5x太卡!怎么办 华为手机玩游戏时太卡了怎么办? 买到华为翻新机怎么办 华为畅享8声音小怎么办 华为5a安全模式怎么办 手机跳屏怎么办金立 苹果手机触控不灵敏怎么办 华为mate8手机声音小怎么办 华为mate9相机无法对焦怎么办