博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在Deferred框架中轻松实现Decal
阅读量:5872 次
发布时间:2019-06-19

本文共 1738 字,大约阅读时间需要 5 分钟。

转载请注明出处为,本文的永久链接为

现代3D游戏经常会需要用到decal,子弹孔、脚印……传统的decal渲染从Quake 2时代开始就没怎么变过,通过画一个紧贴着物体的四边形来实现。问题一直很多,比如光照的不一致,z-fighting造成的闪烁,渲染状态的来回切换,等等。那么到了deferred框架中,这种情况会有所好转吗?

有趣的是,deferred框架内实现decal不但非常容易:100行之内的代码量,不到20分钟就能完成,而且非常稳定,完全没有上述各种缺点。更有趣的是,deferred的decal被至少三组不同的人都提出过完全相同的算法,都在讨论会出现的相同问题,只是被分别叫成了不同的名字。现在看看这三组:

  • Crytek的Jan Krassnigg在2010年于Game Engine Gems 1里的一篇文章A Deferred Decal Rendering Technique提出了称为Deferred Decal的方法,同时他也在SIGGRAPH 2011的talk CryEngine 3: Reaching the Speed of Light中提到了一次。
  • Avalanche Studios的Emil Persson在2011年的GPU Pro 2的文章中独立提出了Volume Decals,在他也给出了一个demo。
  • Relic Entertainment的Pope Kim在SIGGRAPH 2012的一个talk中提出了Screen Space Decals

既然这三种方法完全相同,我们其实只要讨论一种即可,统称为Deferred Decal。(顺便吐槽一下第三个,Screen Space Decals。作者不但是在看了前两个后提出了个毫无新意的东西,并且起了个奇烂无比的名字——很显然那东西不是screen space的。更恶心的是用了个SSD的缩写,嫌缩写混乱还不够多吗?他的ppt基本就是前两篇的问题,只是换成自己的图。遇到新问题直接就选择了避开,或者胡搞一个解法。)

Deferred Decal的基本思路就是,在G-Buffer建立之后,把每一个decal当作一个立方体迭加到G-Buffer上。对于G-Buffer中被立方体覆盖的像素,用decal的color和normal来替换掉。在PS中,只要

1
2
3
4
5
6
7
8
9
10
// 从eye坐标系转回decal立方体的坐标系
float4 decal_pos = mul(float4(pos_es, 1), inv_mv);
// 忽略超过范围的像素
if (any( (decal_pos.xyz) > decal_pos.w))
{
discard;
}
// 计算像素对应的decal纹理坐标
decal_pos /= decal_pos.w;
texcoord = float2(decal_pos.x, -decal_pos.y) * 0.5f + 0.5f;

由于操作的对象是整个G-Buffer,包括normal、diffuse、specular、shininess,所以这样的decal可以修改掉其中任何一个属性,并且在光照阶段不会增加任何开销。这也是传统的decal系统很难做到的。这里我贴了一个shininess很高的decal:

这种方法的最常见问题是,因为立方体的覆盖面积远远大于decal,有时候会在不该贴的地方贴上了拉伸严重的。解决方法是把decal立方体的normal和G-Buffer中的normal作比较,如果差别较大,就忽略掉。但因为写入的目标是G-Buffer,decal的PS就没法读取G-Buffer。所以我的方法是在PS里读取相邻点的depth,计算一个screen space normal(就好像里做的一样),把它和decal立方体的normal比较。下面比较了没加此处修正和加上后的区别:

修正前:

修正后:

另一个常见问题就是视点进入decal立方体后,由于culling的关系,decal消失。解决方法是在那种情况下改成画back face。

在deferred下实现decal就这么简单!

你可能感兴趣的文章
for循环实例
查看>>
N1试卷常考词汇总结
查看>>
构建之法阅读笔记(1)
查看>>
POJ 3663:Costume Party
查看>>
主机连接虚拟机 web服务
查看>>
ajaxSubmit的data属性
查看>>
NetStatusEvent info对象的状态或错误情况的属性
查看>>
linux命令学习
查看>>
Windows下第三方库安装Nuget与Vcpkg
查看>>
URL的截取问题
查看>>
My first post
查看>>
git分支
查看>>
Ehcache 缓存
查看>>
list删除重复元素
查看>>
绘制屏幕时给单选按钮分组
查看>>
TCP/IP协议、DoD模型、OSI模型
查看>>
java开发环境
查看>>
Can't create handler inside thread that has not called Looper.prepare()
查看>>
ADB命令详解
查看>>
urllib模块学习
查看>>