ShadowGun shader 解析(2)
关于ShadowGun中的光照,大家可以在unity的官网上下载这篇ppt,Shadowgun_Unite2011.pdf,里面有关于shadowgun的技术讲解,很有启发性希望大家可以借鉴。两年前的东西了,不过还是很受用。
这次谈谈全局光照,shadowgun的GI(全局光照)是由lightmap和light probes组成的。 ![]()
Light map大家都知道什么东西,我来给大家讲一讲light probes。翻译成中文应该叫光源探针,探测场景中光的分布情况将其赋值到球体上。当然看上去是球体其实是场景中的数据节点,受光体使用这些节点的差值得到光照信息。这是一种模拟全局光照的效果。 ![]()
Shadowgun中的lightmap和light probes是一同完成的,这需要美术了解和熟悉unity中的光照和烘焙系统。light probes主要用于静态光的生成,其中的每个球保存了光线的信息,再要渲染的时候在球体间进行差值,得到所要的信息通过shader程序体现在渲染上。其实只要知道这点就可以很好的使用了。但对于一个追求真理的程序猿来说是远远不够的。打开unityCG.cginc文件,里面有个叫half3 ShadeSH9 (half4 normal)的函数,具体如下:
复制代码
// SH lighting environment
//
float4 unity_SHAr;
float4 unity_SHAg;
float4 unity_SHAb;
float4 unity_SHBr;
float4 unity_SHBg;
float4 unity_SHBb;
float4 unity_SHC;
// normal should be normalized, w=1.0
half3 ShadeSH9 (half4 normal)
{
half3 x1, x2, x3;
// Linear + constant polynomial terms
x1.r = dot(unity_SHAr,normal);
x1.g = dot(unity_SHAg,normal);
x1.b = dot(unity_SHAb,normal);
// 4 of the quadratic polynomials
half4 vB = normal.xyzz * normal.yzzx;
x2.r = dot(unity_SHBr,vB);
x2.g = dot(unity_SHBg,vB);
x2.b = dot(unity_SHBb,vB);
// Final quadratic polynomial
float vC = normal.x*normal.x - normal.y*normal.y;
x3 = unity_SHC.rgb * vC;
return x1 + x2 + x3;
}
这代码源自于Stupid Spherical Harmonics (SH) Tricks这篇文章,重要的是每一行都是抄的还不写出处,让我找了半天。Spherical Harmonics中文叫做球谐函数,可以wiki上看一下,原理是通过类似傅里叶变换的方法,记录下场景里某个点的光照信息。傅里叶变换的应用非常广泛,音频视频中大量使用,其实相当是一个数据压缩的方法,可以把一个数据串变成几个函数的近似和。球谐函数也是这个道理,把光照信息变成几个球谐函数的和,渲染的时候把他们按不同比例相加。如图: ![]()
图不好大家见谅,下次补上。
下图中人物不同的光照就是light probe的作用,既有效率又有效果。 ![]()
关于人物渲染:
例子中只有一个Mobile-TexPseudoBRDF-WrapAround-ShadowgunStyleLightProbes的shader,用于敌人的渲染,可惜没有主角的shader。其实名字中就有LightProbe。在shader的同目录下还可以看到一个BRDFLookupTexture.cs的脚本文件,这个脚本用来生成一张BRDF贴图,BRDF是指双向反射分布函数,其实就是计算光照的方法。把预计算的结果存在图片上,是优化性能的常用方法,就是下面这张贴图: 
直接上代码
复制代码
struct MySurfaceOutput {
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
half Specular;
fixed Gloss;
fixed Alpha;
fixed3 OcclusionAndAmbientLight;
};
sampler2D _BRDFTex;
inline fixed4 LightingPseudoBRDF (MySurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten)
{
// Half vector
fixed3 halfDir = normalize (lightDir + viewDir);
// N.L
fixed NdotL = dot (s.Normal, lightDir);
// N.H
fixed NdotH = dot (s.Normal, halfDir);
// remap N.L from [-1..1] to [0..1]
// this way we can shade pixels facing away from the light - helps to simulate bounce lights
fixed biasNdotL = NdotL * 0.5 + 0.5;
// lookup light texture
// rgb = diffuse term
// a = specular term
fixed4 l = tex2D (_BRDFTex, fixed2(biasNdotL, NdotH));
fixed4 c;
// mask specular term by Gloss factor
// modulate specular with Albedo to allow metalic-ish look
//
// Shadowgun style: instead of adding LightProbes, treat them as both occlusion for MainLight and Ambient bounce
// that is not physically correct, but it
// 1) provides way to occlude MainLight without using runtime shadows
// 2) allows bounce light to be affected by per-pixel normals
// note that bounce lights becomes much weaker!
c.rgb = s.OcclusionAndAmbientLight * s.Albedo * (l.rgb + s.Gloss * l.a) * 2;
c.a = 0;
return c;
}
sampler2D _MainTex;
sampler2D _BumpMap;
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
fixed3 shOcclusionAndAmbient;
};
void separateSH (inout appdata_full v, out Input o)
{
float3 worldN = mul ((float3x3)_Object2World, SCALED_NORMAL);
o.shOcclusionAndAmbient = ShadeSH9 (float4(worldN,1.0));
}
void surf (Input IN, inout MySurfaceOutput o) {
fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = tex.rgb;
o.Gloss = tex.a;
o.Alpha = tex.a;
o.Normal = tex2D(_BumpMap, IN.uv_BumpMap).rgb * 2.0 - 1.0;
o.OcclusionAndAmbientLight = IN.shOcclusionAndAmbient;
}
这个shader使用了surfshader,surfshader是个不错的思想,主要是Unity为了整合forward render和deferred render。不过在移动设备上我一般不用,因为很容易造成多pass的情况发生,对效率也有一定影响。其实代码很简单没什么好说的,主要的的计算在LightingPseudoBRDF里,计算光照,可以清晰的看到使用了BRDF贴图。
fixed4 l = tex2D (_BRDFTex, fixed2(biasNdotL, NdotH));
LightingPseudoBRDF 使用了计算光照的,separateSH 用来生成SH信息在shOcclusionAndAmbient,其实SH应该不能算作是Occlusion只能是是一种Ambient的方法。surf 是用来提供计算光照的参数。
他们的运行顺序应该是separateSH -> surf -> LightingPseudoBRDF。Surfshader我就不详细讲了,大家都可以找的到。
总结:
shadow gun中的光照这次着重讨论了LightProbe和人物身上的光照,充分利用了unity的光照系统,代来了全新的视觉体验。期望能给大家一下启示,也可以给自己的游戏带来更多的光影效果。

浙公网安备 33010602011771号