实时阴影渲染(三):软阴影深度校正
2016-10-22 14:36
344 查看
上一篇介绍的软阴影技术已经可以生成很好的软阴影
再结合第一篇介绍的PSSM就可以实现不错的阴影效果
但在实际应用中的会遇到一个很重要的问题:阴影渲染中的自阴影问题
这种问题的产生的原因和锯齿原因类似:
视空间中的像素和灯光空间像素不一致
比如视空间中的一块区域(多个像素)在渲染阴影时对应同一个像素,因而仅产生一个深度值(中心深度)
对于灯光空间中倾斜的三角面来说,这些值是应该不同的
一般对这种问题的解决办法是通过一个小的深度偏移量,或者再通过背面渲染缓解这种问题
而采用多个采样的深度软阴影技术,这种问题会更加显著,这样仅采用一个小小的偏移就不够了
但如果深度偏移太大又会导致本该出现阴影的地方没有阴影
下图以水平3像素的软阴影采样为例说明这种问题:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202011/03/4f5d987f35d212fa5a9884a7c85cf343.png)
如上图,假设场景中仅存在ABC所在的平面,ABC为相邻的三个阴影像素,
采用水平3采样计算c点阴影时,会得到强度为0.333的阴影,因为 depth(a)>depth(c)+depthBias
这样渲染那出来的结果是:整个平面都在强度为0.333阴影中;而实际上整个平面都不应该有阴影
除非我们将depthBias设的足够大,但AB平面越倾斜、采样数越多所需要的depthBias的值就越大
这样通过增大depthBias的值是不能解决问题的
思考一下,如果我们能知道ac点的深度差dz = depth(c)-depth(a)的值,就可以通过计算比较出:
depth(a) - dz < depth(c)+depthBias;
depth(c) < depth(c)+depthBias;
depth(b) + dz < depth(c)+depthBias;
从而得出整个平面都不在阴影中的结果
计算深度差dz
在GPU设计体系中,片段程序执行时并不知道其它片段的信息
但好在GPU的实现中提供了ddx ddy两个例外的指令,通过这两条指令可以得出相邻片段间的偏导,也就是相邻片段之间的数据差值
因为实际采样一般为3*3,5*5,我们需要计算水平和垂直两个方向上的深度差zx、zy
假设在当前片段所在三角面对应一个阴影纹理像素的深度差为float2(zx, zy), 阴影纹理宽高为float2(w,h)
通过求解二元一次方程组:
ddx(uv) * float2(zx, zy) * float2(w,h)= ddx(z)
ddy(uv) * float2(zx, zy) *float2(w,h)= ddy(z)
就可以得到zx、zy
注:uv 为当前片段的深度纹理uv坐标, z 为当前片段深度值 ,这些都是已知
2017-9-22修改: +方程求解说明
之前的方程写的意思不明确,想表达的是:
ddx(u)*zx*w + ddx(v)*zy*h = ddx(z) 即 x方向z变化量【ddx(z)】 = x方向u变化量【ddx(u)】 * 单位u变化对应的z变化量【zx】 + x向v变化量【ddx(v)】 * 单位v变化对应的z变化量【zy】
ddy(u)*zx*w + ddy(v)*zy*h = ddy(z) 同上
求解我就不写了,相当于求解 方程组:
a* zx + b * zy = c
d* zx + e * zy = f 即利用a b c d e f六个已知量,计算两个未知量zx\zy,但写出来挺长,还不如自己推导便于理解
方程ddx(u)*zx*w + ddx(v)*zy*h = ddx(z) 成立的意思是:
当前片段x方向变化对应纹理坐标uv两个变化,而阴影纹理u、v的变化分别产生各自的z变化值,累加就是ddx(z)
再结合第一篇介绍的PSSM就可以实现不错的阴影效果
但在实际应用中的会遇到一个很重要的问题:阴影渲染中的自阴影问题
这种问题的产生的原因和锯齿原因类似:
视空间中的像素和灯光空间像素不一致
比如视空间中的一块区域(多个像素)在渲染阴影时对应同一个像素,因而仅产生一个深度值(中心深度)
对于灯光空间中倾斜的三角面来说,这些值是应该不同的
一般对这种问题的解决办法是通过一个小的深度偏移量,或者再通过背面渲染缓解这种问题
而采用多个采样的深度软阴影技术,这种问题会更加显著,这样仅采用一个小小的偏移就不够了
但如果深度偏移太大又会导致本该出现阴影的地方没有阴影
下图以水平3像素的软阴影采样为例说明这种问题:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202011/03/4f5d987f35d212fa5a9884a7c85cf343.png)
如上图,假设场景中仅存在ABC所在的平面,ABC为相邻的三个阴影像素,
采用水平3采样计算c点阴影时,会得到强度为0.333的阴影,因为 depth(a)>depth(c)+depthBias
这样渲染那出来的结果是:整个平面都在强度为0.333阴影中;而实际上整个平面都不应该有阴影
除非我们将depthBias设的足够大,但AB平面越倾斜、采样数越多所需要的depthBias的值就越大
这样通过增大depthBias的值是不能解决问题的
思考一下,如果我们能知道ac点的深度差dz = depth(c)-depth(a)的值,就可以通过计算比较出:
depth(a) - dz < depth(c)+depthBias;
depth(c) < depth(c)+depthBias;
depth(b) + dz < depth(c)+depthBias;
从而得出整个平面都不在阴影中的结果
计算深度差dz
在GPU设计体系中,片段程序执行时并不知道其它片段的信息
但好在GPU的实现中提供了ddx ddy两个例外的指令,通过这两条指令可以得出相邻片段间的偏导,也就是相邻片段之间的数据差值
因为实际采样一般为3*3,5*5,我们需要计算水平和垂直两个方向上的深度差zx、zy
假设在当前片段所在三角面对应一个阴影纹理像素的深度差为float2(zx, zy), 阴影纹理宽高为float2(w,h)
通过求解二元一次方程组:
ddx(uv) * float2(zx, zy) * float2(w,h)= ddx(z)
ddy(uv) * float2(zx, zy) *float2(w,h)= ddy(z)
就可以得到zx、zy
注:uv 为当前片段的深度纹理uv坐标, z 为当前片段深度值 ,这些都是已知
2017-9-22修改: +方程求解说明
之前的方程写的意思不明确,想表达的是:
ddx(u)*zx*w + ddx(v)*zy*h = ddx(z) 即 x方向z变化量【ddx(z)】 = x方向u变化量【ddx(u)】 * 单位u变化对应的z变化量【zx】 + x向v变化量【ddx(v)】 * 单位v变化对应的z变化量【zy】
ddy(u)*zx*w + ddy(v)*zy*h = ddy(z) 同上
求解我就不写了,相当于求解 方程组:
a* zx + b * zy = c
d* zx + e * zy = f 即利用a b c d e f六个已知量,计算两个未知量zx\zy,但写出来挺长,还不如自己推导便于理解
方程ddx(u)*zx*w + ddx(v)*zy*h = ddx(z) 成立的意思是:
当前片段x方向变化对应纹理坐标uv两个变化,而阴影纹理u、v的变化分别产生各自的z变化值,累加就是ddx(z)
相关文章推荐
- untiy 3d ShaderLab_第8章_4_ 单光照贴图在Deferred 渲染路径下的实时阴影
- 移动设备渲染实时阴影
- 实时阴影渲染相关资料
- 实时阴影渲染(一):PSSM平行分割阴影图
- 实时阴影渲染(二):软阴影
- 关于Unity中混合模式、Alpha测试、深度测试、通道遮罩、面剔除的使用----渲染通道通用指令(二)
- 实时SLAM的未来及深度学习与SLAM对比
- C#学习笔记(十):阴影和深度复制
- 实时的效果如何与渲染的动画相近
- 【PhotoShop】【ARkit】3d模型单独渲染阴影的一种方法给ARKIT用
- 3D地形多层纹理混合加阴影渲染方法
- 【Unity&2.5D&Shader】2D2.5D精灵实时阴影怎么使用
- Unity5.0实时阴影的优化
- 实时渲染(一)——图形渲染管线
- 实时删除数组中的值,实时渲染到页面上
- 实时渲染(第三版):第三章 图形处理单元 3.1 3.2
- 实时渲染(第三版):第四章 转换 4.1.3 4.1.4
- Unity局部高效实时阴影的思考和实现
- WPF/Silverlight深度解决方案:(六)HLSL自定义渲染特效之完美攻略(上)
- WPF/Silverlight深度解决方案:(九)HLSL自定义渲染特效之完美攻略(下)