最近使用unity,碰到到一個很有趣的例子.場景無光線,卻模擬出了光照,效果挺好.其思路與法線貼圖原理異曲同工.
原作者提供的效果印象深刻.
模型除了使用原來的diffuse貼圖外,還用到了一張模擬記錄了"光照"信息的貼圖(見機器人頭上的貼圖).這一點與法線貼圖是一致的.
這個方法比較簡單,也比較死.思路很巧.
分析一下貼圖,有效范圍基本是一個圓形.以前在學習法線貼圖時,就遇到過法線投射在貼圖的情景(http://www.cnblogs.com/flytrace/p/3387748.html).當各個方向的法線投影到一個正平面時,它形成一個圓.
法線貼圖本質就是為了預先保存法線信息.那幾乎就可以引申出來了,我們也可以保存一個冒充的法線(光線)的信息,根據這個信息我們可以還原一個"偽"的光照過程.這個貼圖就反過來利用了這一點.將模型的法線轉換到model-view空間,再假設法線被投影到一個正平面(貼圖上).於是法線的投影點可換算為貼圖的uv坐標.此時在該點我們保存一個顏色值,可以與模型的diffuse貼圖顏色進行計算,模擬出光照的效果.
struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float2 cap : TEXCOORD1; }; uniform float4 _MainTex_ST; v2f vert (appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); half2 capCoord; capCoord.x = dot(UNITY_MATRIX_IT_MV[0].xyz,v.normal); capCoord.y = dot(UNITY_MATRIX_IT_MV[1].xyz,v.normal); o.cap = capCoord * 0.5 + 0.5; return o; } uniform sampler2D _MainTex; uniform sampler2D _MatCap; fixed4 frag (v2f i) : COLOR { fixed4 tex = tex2D(_MainTex, i.uv); fixed4 mc = tex2D(_MatCap, i.cap); return (tex + (mc*2.0)-1.0); }
capCoord.x = dot(UNITY_MATRIX_IT_MV[0].xyz,v.normal);
capCoord.y = dot(UNITY_MATRIX_IT_MV[1].xyz,v.normal);
上邊2行是這里比較關鍵的一步,把法線轉換到view空間.參看(http://www.cnblogs.com/flytrace/p/3379816.html)說明了原理.總之法線不能直接使用model-view矩陣轉換到view空間.
o.cap = capCoord * 0.5 + 0.5;
上邊是把法線值轉換到紋理區間[0,1],之后在fragment shader通過這個值去貼圖里查找對應的顏色值.
這種手法似乎叫MatCap shader.這里是些卡通效果,其他地方有更真實的.