Surface Shader的組成
一拍谐、編譯指令
編譯指令
所謂編譯指令就是使用命令來(lái)告訴Unity我將使用那些函數(shù)以及光照模型來(lái)處理相應(yīng)的數(shù)據(jù),并輸出我想要的顏色,同時(shí)不要生成哪些渲染路徑下的代碼(如延遲渲染等)
// surf - 要使用的表面函數(shù).
// CustomLambert - 要使用的自定義光照函數(shù).
// vertex:myvert - 自定義模型定點(diǎn)修改函數(shù).
// finalcolor:mycolor - 最終要使用的處理顏色的函數(shù).
// addshadow - 生成正確的陰影,因?yàn)樵谛薷哪P投c(diǎn)后會(huì)產(chǎn)生錯(cuò)誤的陰影.
// exclude_path:延時(shí)渲染路徑的代碼不要生成
// nometa - do not generate a “meta” pass (that’s used by lightmapping & dynamic global illumination to extract surface information).
#pragma surface surf CustomLambert vertex:myvert finalcolor:mycolor addshadow exclude_path:deferred exclude_path:prepass nometa
二咕晋、默認(rèn)自定義函數(shù)
1、表面函數(shù)(surFunction)
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = tex.rgb;
o.Alpha = tex.a;
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
因?yàn)樵谟?jì)算光照引起的顏色的時(shí)候我們經(jīng)常需要根據(jù)輸入的一些信息如紋理顏色收奔,透明度掌呜,反射率,法線等來(lái)計(jì)算最終的顏色坪哄,所以SurFunction就相當(dāng)于把這部分抽象出來(lái)站辉,根據(jù)輸入改變對(duì)應(yīng)的值呢撞。
2、自定義改變頂點(diǎn)函數(shù)
void myvert (inout appdata_full v)
{
v.vertex.xyz += v.normal * _Amount;
}
這個(gè)函數(shù)的作用是用來(lái)改變輸入給頂點(diǎn)著色器的數(shù)據(jù)饰剥,理論上凡是輸入給頂點(diǎn)著色器的數(shù)據(jù)都可以改變:
v2f_surf vert_surf (appdata_full v)
{
v2f_surf o;
......
myvert (v);
o.pos = UnityObjectToClipPos(v.vertex);
o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
o.pack0.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
.....
return o;
}
3殊霞、自定義光照模型函數(shù)
half4 LightingCustomLambert (SurfaceOutput s, half3 lightDir, half atten)
{
half NdotL = dot(s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
c.a = s.Alpha;
return c;
}
如果不想使用提供好的光照模型,我們可以自定義關(guān)照模型汰蓉,但是函數(shù)的參數(shù)類型和個(gè)數(shù)是固定的绷蹲。
4、自定義最終改變顏色函數(shù)
void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)
{
color *= _ColorTint;
}
在最終輸出顏色之前會(huì)調(diào)用這個(gè)函數(shù)顾孽,經(jīng)過(guò)這個(gè)函數(shù)后才知我們想要的顏色祝钢。
三、代碼的生成以及調(diào)用過(guò)程
1若厚、代碼生成
以下代碼作為示例:
Shader "Custom/NormalExtrusion"
{
Properties {
_ColorTint ("Color Tint", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_BumpMap ("Normalmap", 2D) = "bump" {}
_Amount ("Extrusion Amount", Range(-0.5, 0.5)) = 0.1
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 300
CGPROGRAM
#pragma surface surf CustomLambert vertex:myvert finalcolor:mycolor addshadow exclude_path:deferred exclude_path:prepass nometa
#pragma target 3.0
fixed4 _ColorTint;
sampler2D _MainTex;
sampler2D _BumpMap;
half _Amount;
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
};
void myvert (inout appdata_full v)
{
v.vertex.xyz += v.normal * _Amount;
}
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = tex.rgb;
o.Alpha = tex.a;
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
half4 LightingCustomLambert (SurfaceOutput s, half3 lightDir, half atten)
{
half NdotL = dot(s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
c.a = s.Alpha;
return c;
}
void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)
{
color *= _ColorTint;
}
ENDCG
}
FallBack "Legacy Shaders/Diffuse"
}
以上代碼會(huì)形成以法線方向上的膨脹效果拦英,因?yàn)楦淖兞四P偷捻旤c(diǎn)位置。
生成代碼
生成代碼后打開(kāi):
代碼生成
雖然很多测秸,但發(fā)現(xiàn)基本上只有三個(gè)Pass疤估,一個(gè)Base Pass用來(lái)處理逐像素平行光,一個(gè)Add Pass用來(lái)處理其他逐像素的光霎冯,一個(gè)Shadow Caster用來(lái)處理陰影投射铃拇。
無(wú)論幾個(gè)Pass,里面都包含了我們所寫的幾個(gè)函數(shù):
image.png
2沈撞、調(diào)用過(guò)程
自定義的頂點(diǎn)修改函數(shù)會(huì)在每個(gè)Pass的頂點(diǎn)著色器中最開(kāi)始的地方執(zhí)行:
myvert
SurFunction用于輸出改變后的法線慷荔,反射率,透明度等信息缠俺,會(huì)在每個(gè)Pass的片元著色器中显晶,根據(jù)我們給的INPUT結(jié)構(gòu)調(diào)用并輸出:
surf
自定義光照模型函數(shù)在SurFunction后執(zhí)行,使用的正是SurFunction的輸出
LightingCustomLambert
自定義最終改變顏色函數(shù)一般只會(huì)在Base Pass的片元著色器中執(zhí)行一次壹士,用來(lái)做最后輸出:
mycolor