实时阴影渲染(二):软阴影
2016-09-24 22:03
148 查看
软阴影是通过对阴影图进行多次采样实现的
因为多个片段经常会对应同一个阴影纹理像素,单次采样会产生严重的锯齿问题
另外软阴影还可以产生比较柔和的边界,看起来比较自然
锯齿产生的原因
仔细思考阴影锯齿产生的原因,可以想到多个片段对应同一个阴影像素时,其在该阴影像素中对应的的位置是不同的
如下示意图,黑色的大方格表示单个阴影纹理像素,虚线分割的部分表示对应到该阴影像素的9个片段
![](https://images2015.cnblogs.com/blog/690867/201609/690867-20160924184106418-923489898.png)
显然对于AB来说其阴影值和C应该是不同的,算法中应该把这个因素考虑进去
可以想到,当纹理坐标没有对应到正中心时,通过与相邻像素的线性插值也许可以很好的解决我们遇到的锯齿问题
2×2线性插值
![](https://images2015.cnblogs.com/blog/690867/201609/690867-20160924190325652-335262120.png)
如上图,实线分割的四个区域表示阴影纹理中的四个像素,ABCD为其中心点
当一个片段映射到ABCD虚线包含的区域时,这四个像素都应该参与阴影计算,然后通过线性插值得出最终结果
假设纹理大小为float2 size(w, h),像素大小texelSize=float2(1/w, 1/h),当前纹理坐标uv
则以下代码可计算四个点纹理坐标uva/uvb/uvc/uvd,插值系数factor(x, y)【 水平方向插值系数为x, 垂直方向插值为y】:
a、b、c、d分别为A、B、C、D阴影值
这样即便单个阴影像素点也可以产生平滑的阴影,并具有典型的线性插值特征:
![](https://images2015.cnblogs.com/blog/690867/201609/690867-20160924213129277-240683725.png)
更大的采样范围
2x2线性插值虽然可以产生平滑过渡的阴影,但没有完全解决锯齿纹理,效果并不理想
这是因为使用的阴影图本身就是栅格化的
处理这个问题的办法是采用更大的采样范围比如3x3\4x4\5x5
其处理思路都是一样的,比如以5x5为例:
首先计算各行的阴影值: row[i]= b+c+d+lerp(a, e, factor.x) , 其中a b c d e为同一行的五个点阴影结果
总阴影值 = ( row1+row2+row3 + lerp(row0, row4, factor.y) ) / 16
5X5采样得到可以产生非常柔和的阴影
不过需要25次纹理采样,性能相比3×3的9次或 4x4的16次要差些
因为多个片段经常会对应同一个阴影纹理像素,单次采样会产生严重的锯齿问题
另外软阴影还可以产生比较柔和的边界,看起来比较自然
锯齿产生的原因
仔细思考阴影锯齿产生的原因,可以想到多个片段对应同一个阴影像素时,其在该阴影像素中对应的的位置是不同的
如下示意图,黑色的大方格表示单个阴影纹理像素,虚线分割的部分表示对应到该阴影像素的9个片段
![](https://images2015.cnblogs.com/blog/690867/201609/690867-20160924184106418-923489898.png)
显然对于AB来说其阴影值和C应该是不同的,算法中应该把这个因素考虑进去
可以想到,当纹理坐标没有对应到正中心时,通过与相邻像素的线性插值也许可以很好的解决我们遇到的锯齿问题
2×2线性插值
![](https://images2015.cnblogs.com/blog/690867/201609/690867-20160924190325652-335262120.png)
如上图,实线分割的四个区域表示阴影纹理中的四个像素,ABCD为其中心点
当一个片段映射到ABCD虚线包含的区域时,这四个像素都应该参与阴影计算,然后通过线性插值得出最终结果
假设纹理大小为float2 size(w, h),像素大小texelSize=float2(1/w, 1/h),当前纹理坐标uv
则以下代码可计算四个点纹理坐标uva/uvb/uvc/uvd,插值系数factor(x, y)【 水平方向插值系数为x, 垂直方向插值为y】:
factor= frac(uv*size-0.5); uva = (floor(uv*size-0.5) + 0.5) * texelSize; uvb = uva + float(1, 0) * texelSize; uvc = uva + float(0, 1) * texelSize; uvd = uva + float(1, 1) * texelSize;
a、b、c、d分别为A、B、C、D阴影值
//a=depthShadow(sm,uva, z,...); b=depthShadow(uvb,...)
ab = lerp(a, b, factor.x); cd = lerp(c, d, factor.x); shdow = lerp(ab, cd, factor.y); //最终阴影值
这样即便单个阴影像素点也可以产生平滑的阴影,并具有典型的线性插值特征:
![](https://images2015.cnblogs.com/blog/690867/201609/690867-20160924213129277-240683725.png)
更大的采样范围
2x2线性插值虽然可以产生平滑过渡的阴影,但没有完全解决锯齿纹理,效果并不理想
这是因为使用的阴影图本身就是栅格化的
处理这个问题的办法是采用更大的采样范围比如3x3\4x4\5x5
其处理思路都是一样的,比如以5x5为例:
首先计算各行的阴影值: row[i]= b+c+d+lerp(a, e, factor.x) , 其中a b c d e为同一行的五个点阴影结果
总阴影值 = ( row1+row2+row3 + lerp(row0, row4, factor.y) ) / 16
5X5采样得到可以产生非常柔和的阴影
不过需要25次纹理采样,性能相比3×3的9次或 4x4的16次要差些
相关文章推荐
- untiy 3d ShaderLab_第8章_4_ 单光照贴图在Deferred 渲染路径下的实时阴影
- 实时阴影渲染(三):软阴影深度校正
- 移动设备渲染实时阴影
- 实时阴影渲染相关资料
- 实时阴影渲染(一):PSSM平行分割阴影图
- 实时渲染(第三版):第四章 转换 4.4 顶点混合
- WorldWind源码剖析系列:WorldWind实时确定、更新、初始化和渲染地形和纹理数据
- 实时的效果如何与渲染的动画相近
- 3D地形多层纹理混合加阴影渲染方法
- 实时阴影技术
- 如何实现最佳的跨平台游戏体验?Unity成亮解密实时渲染
- PC平台下海量地形的分页调度和实时渲染(转)
- [实时渲染] 2.5 回顾渲染管线
- Unity教程之-RenderTexture实现实时阴影绘制
- wxWidgets中OpenGL渲染环境的配置,主要解决不能显示物体阴影问题
- unity3d Human skin real time rendering plus 真实模拟人皮实时渲染 plus篇
- Direct9学习之--------------------------实时阴影的另一种实现ShadowMap
- React Native View 组件通过阴影渲染实现组件浮现效果
- 3D地形多层纹理混合加阴影渲染方法
- 中国传统风格水墨实时渲染