最近,随着外包告一段落,开始整理和重构GC了,顺手整理一下GC的MRT。
之前没有认真读完的星际2的白皮书,这次至少是把MRT部分和Shadow部分读了一下。
先说MRT吧:
星际2的MRT大约如下配置:
具体就不解释了,看样子,为了保证精度,每个MRT应该都是64-bit的,0、2、3三个MRT保存表面颜色信息,1用来保存对于DS而言最重要的Normal Depth,还不错。
关于MRT,其用途可能比看起来的要大得多。其实很多效果都可以通过MRT来实现,例如Killzone2就把SH球谐光照编码到Lighting Accumulation域里,这个Lighting Accumulation在我感觉可能很像Emissive,稍有不同吧——很可能最后用的是与Albedo的乘法?也就是公式是:
Albedo * LightingAccumulation + Albedo * dot(N,L) + Specular* dot(N,H)
Lighting Accumulation主要是用来存储静态光照图、Decal和球谐光照。SC这里面没有Lighting Accumulation,其实很多工作也是可以做的,比如SH光照,可以编到Emissive里嘛,然后Albedo给0000,这样加出来的效果跟Lighting Accumulation的最终效果可能也差不了多少。这样的公式是:
Emissive + Albedo * dot(N,L) + Specular * dot(N,H)
由于GC是一个为了学习而创造的工具,因此也无所谓商业应用的问题,所以就大胆使用了SC的64位MRT,只不过稍微改了一下:
1、Normal Depth这里,SC2用的是3个half描述Normal,1个half描述深度。我比较担心half描述深度的精度问题,所以我这里用的是第一个32位float编码深度,第二个32位float,拆解为高16和低16,分别存储NormalX和NormalY。
2、Emissive和Specular,同样的,我并没有分到两个MRT上,用总共6个Half描述,而是放到了一个MRT里,Emissive使用前32位,Specular用后32位,均使用RGBE编码。这样就剩下来整一个MRT,准备用来做一些后期特效——例如SS Motion Blur等等。
这一点从SC2学到了不少,32位的MRT太纠结了,类如查询表等很多麻烦的事情需要处理,64位显然这里好一些。
第二个学到的部分,是半透明Shadow的处理:
半透明阴影确实能带来很多真实感,效果看起来也很不错。如果烟雾没有投影,给人最深刻的感觉就是这些半透明的东西,很可能是“浮”的,似乎不存在于世界之中。
星际2Shadow部分的处理,是把整个Shadow Map分成两个组成部分,一个是不透明物的Opaque Shadow Map,一个是透明物的Translucent Shadow Map+Translucent Shadow Color,分两个批次来渲染投影。
不透明物的就不用说的,老算法,开Opaque Shadow Map的RenderTarget,光照空间——渲染物体——记录深度。
半透明这里稍微有点不同:
首先,别清空DepthStencil,因为半透明这里还需要获取不透明物体的Depth Stencil。但是这里,需要把半透明物的Translucent Shadow Map和Translucent Shadow Color设置为Render Target。
然后,半透明那套设置方法,开Blend。
渲染的时候,算法是像下面这样:不断的“滤除”颜色分量。例如,青的物体(0,1,1),滤除的将是红色,如果阴影过来,那么红色分量就会被无视掉。然后,黄色的物体(1,1,0),滤除的将是蓝色。这样,上一个Stage经过的(0,1,1)就会进一步只剩下(0,1,0)。这个应该是自然界投影的一个原则。
Shadow Map渲染完后,在最后场景渲染的时候就好办了:
如果被半透明深度遮挡,就从半透明颜色Translucent Shadow Color中读取颜色进行Shadow着色。
否则,如果被不透明深度遮挡,就根据光源的Shadow颜色进行着色。
把GC根据这个原则大概整理了一下,因为要重构,就没写的太深,效果可能还不是太对,大概齐吧,发图:
中间那个蓝色的物体是个半透明物体,光照为它投了一个半透明的影子在后面的模型上,本意是模拟肥皂泡那种感觉的Shadow,参数调的还不是太好。
等全部重构完了,然后再贴正常一点的图吧。
最近真的太懒了,嘿嘿。