這個demo放出來之后,對其中的角色陰影部分的技術十分感興趣,我就趕緊下過來研究了一下。官方的技術博客里有對這一部分技術的介紹,鏈接在這里:獨特的角色陰影,
其中寫到只要在其他shader里添加
#PRagma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE#include "UniqueShadow_ShadowSample.cginc"這兩行代碼就能使用這個高級陰影了。 我之前也因為在做一些demo的時候發現unity默認陰影達不到理想效果,和ue4比起來還是有一定差距的。于是就想到使用這個陰影技術了。于是我興致勃勃的把這兩行代碼和幾個庫文件加到我的shader和項目里去,一運行發現,高級陰影并沒有出現。哎,看樣子只能自己研究了。既然是陰影,那么著手點就是unity里的陰影部分的代碼,手動寫過自定義陰影的人應該都知道,unity陰影計算:SHADOW_COORDS、TRANSFER_SHADOW、SHADOW_ATTENUATION三個函數了,unity把陰影生成的代碼都寫在了這三個函數里,方便調用。我看The Blacksmith的技術博客上寫著: 我們發現原來有一個非常簡單的方法來對常見的Unity shader所用的陰影方法進行重寫。 于是我琢磨著應該是他們也用了這三個方法,于是打開 UniqueShadow_ShadowSample.cginc 文件,果不其然,在最下面找到了這么一段代碼
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_FORWARDADD) || defined(UNIQUE_SHADOW_FORCE_REPLACE_BUILTIN) #undef SHADOW_COORDS #undef TRANSFER_SHADOW #undef SHADOW_ATTENUATION #define SHADOW_COORDS(i) UNIQUE_SHADOW_INTERP(i) #define TRANSFER_SHADOW o.uniqueShadowPos = mul(u_UniqueShadowMatrix, float4(worldPos.xyz, 1.f)); #define SHADOW_ATTENUATION(i) UNIQUE_SHADOW_SAMPLE(i);#endif這里的意思就是,如果判斷pass的名字是UNITY_PASS_FORWARDBASE、NITY_PASS_FORWARDADD、UNIQUE_SHADOW_FORCE_REPLACE_BUILTIN這三個的話,就會把
SHADOW_COORDS(i) 替換成UNIQUE_SHADOW_INTERP(i),SHADOW_ATTENUATION(i)替換成UNIQUE_SHADOW_SAMPLE(i);TRANSFER_SHADOW的值替換成后面的 o.uniqueShadowPos這樣的話就好說了,之后只要把自己的shader里生成陰影的pass名字改成三個里的任意一個,生成陰影的代碼還是按照原來的方式寫就可以了。于是我立馬新建了一個Unlit Shader,添加上生成陰影的代碼后,把pass的名字改成了UNITY_PASS_FORWARDBASE,代碼如下
Shader "Custom/simpleSuperShadow"{ Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { Tags{ "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "AutoLight.cginc"#define UNITY_PASS_FORWARDBASE#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE#include "UniqueShadow/UniqueShadow_ShadowSample.cginc" struct v2f { float2 uv : TEXCOORD0; float4 pos : SV_POSITION; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2) }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata_full v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.worldPos = mul(_Object2World, v.vertex).xyz; TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); fixed shadow = SHADOW_ATTENUATION(i); return col * shadow; } ENDCG } } FallBack "Diffuse"}點擊運行之后,shader報錯,提示我頂點函數里worldPos未定義,報錯的地方是在TRANSFER_SHADOW(o)這一行,但是我明明在v2f里定義了這個變量,并且在上一行賦值了才對。這個提示不應該出現才對。對于這個問題,我毫無頭緒,不知道自己哪里出了問題。于是我又新建了一個standard surface shader,這次我只在里面添加了#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE#include "UniqueShadow/UniqueShadow_ShadowSample.cginc"兩行,運行一下,居然成功了,于是我在編輯器里點開了surface shader的原始代碼,通過仔細對比陰影生成的三個函數發現,surface shader在頂點函數使用worldPos的時候,并不是直接給o.worldPos賦值的,而是先定義了一個float3的worldPos變量,計算出來以后再讓o.worldPos = worldPos,這里感覺應該是一樣的才是,并沒有什么特別的地方啊。雖然我不是很清楚surface shader里為啥要這么寫,但是抱著試一試的心情,我把自己的shader的頂點函數從原來的v2f vert (appdata_full v){ v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.worldPos = mul(_Object2World, v.vertex).xyz; TRANSFER_SHADOW(o); return o;}這樣,改成了v2f vert (appdata_full v){ v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); float3 worldPos = mul(_Object2World, v.vertex).xyz; o.worldPos = worldPos; TRANSFER_SHADOW(o); return o;}這樣,于是我運行一下。臥槽竟然成功了。按道理來說定義一個臨時變量和直接賦值應該沒有區別才是,為啥這里不定義一個就不行呢,mul(_Object2Wrold,v.vertex).xyz返回的本來就是一個float3的變量才是,為毛非要這么做才能正確顯示呢。實在是不知道要怎么解釋。希望知道的大大們能夠幫我解釋一下??偨Y一下這個高級陰影的使用方法1.給計算陰影的pass添加#define UNITY_PASS_FORWARDBASE#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE#include "UniqueShadow/UniqueShadow_ShadowSample.cginc"
這三行代碼,然后在頂點函數使用TRANSFES_SHADOW的地方改成float3 worldPos = mul(_Object2World, v.vertex).xyz;o.worldPos = worldPos;TRANSFER_SHADOW(o);這樣自定義的shader也能夠使用這個超高分辨率的陰影了。
這里我用了一個卡通shader做測試未使用高級陰影:
使用高級陰影:
這樣就能做出媲美ue4的高級陰影來了。
新聞熱點
疑難解答