最近公司项目中导入了一些自带光照图的场景模型。这些场景的颜色本应严格按照光照图给出的颜色,但场景中的灯光会使得它们更亮。在Unity中也没能找到支持光照图的不打光Shader,于是自己下来做了一个实现。效果上能够和Unity自带Shader一致,因为去掉了光照计算的过程,在性能上也略有提升。
要解决的问题
照理说Unity应该实现所有关键词(diffuse/transparent/unlit等)组合而成的shader。而实际上有些组合确实没有相应的内置shader。像这个内置的Lightmap,既然已经有光照图了,何必再接受光照以及叠色呢!写一个Unlit + Texture + Lightmap版的Shader吧,这就是最初的动机。
首先帖Shader
Shader "NewShader/Lightmap/Unlit"{
Properties{
_MainTex ("Base (RGB)", 2D) = "white" {}
_Lightmap ("Lightmap", 2D) = "black" {}
}
SubShader{
Tags {"RenderType"="Opaque"}
LOD 100
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata{
float4 vertex : POSITION;
half2 uv : TEXCOORD0;
half2 uv1: TEXCOORD1;
};
struct v2f {
float4 pos : SV_POSITION;
half2 uv :TEXCOORD0;
half2 uv1:TEXCOORD1;
};
sampler2D _MainTex;
sampler2D _Lightmap;
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv1 = v.uv1;
return o;
}
half4 frag(v2f i) : COLOR
{
half4 c = tex2D(_MainTex, i.uv);
half4 c1= tex2D(_Lightmap, i.uv1);
half4 o;
o.rgb = c.rgb * c1.rgb;
o.a = 1;
return o;
}
ENDCG
}
}
}
整体思路
这个Shader是参考Unity的”Legacy/Lightmap/Diffuce”(简称Lightmap_Diffuse)和”Unlit/Texture”。
因为此Shader不处理任何光照,每个空间点的纹理颜色经位置投影视图变换直接作为输出颜色。而Lightmap_Diffuse使用的surface着色器似乎必须制定一个Lambert之类的光照模型。为了不受光照影响,参考Unlit/Texture的方案,写一个vert着色器和一个frag着色器,变换后将颜色图和光照图直接相乘输出。
性能对比
周五湘明说起特效对性能有所影响,写这篇文章的时候也想对比一下替换Shader前后性能上有何变化。
下图是两Shader的GPU时间对比。
手头没有合适的带Lightmap模型,于是拿Unity里的大叔版玛丽充数了。用的是控制变量法,唯一的差异在Shader。
结果还是很明显的,Lightmap_Diffuse的Drawing时间为0.28ms左右,新的Shader为0.25ms左右。换做一个真正的游戏场景,也许这个差异会被放得更大。
我博客原文:http://www.lolofinil.com/2014/04/25/lightmap_unlit_shader/