Surface Shader:
(1)必須放在SubShdader塊,不能放在Pass内部;
(2)#pragma sufrace surfaceFunction lightModel [optionalparams]
(3)格式
CG規定了聲明為表面着色器的方法(就是我們這裡的surf)的參數類型和名字,是以我們沒有權利決定surf的輸入輸出參數的類型,隻能按照規定寫。這個規定就是第一個參數是一個Input結構,第二個參數是一個inout的SurfaceOutput結構。
struct SurfaceOutput {
half3 Albedo; //像素的顔色
half3 Normal; //像素的法向值
half3 Emission; //像素的發散顔色
half Specular; //像素的鏡面高光
half Gloss; //像素的發光強度
half Alpha; //像素的透明度
};
sampler2D就是GLSL中的2D貼圖的類型,相應的,還有sampler1D,sampler3d,samplerCube等等格式。而具體地想知道像素與坐标的對應關系,以及擷取這些資料,我們總不能一次一次去自己計算記憶體位址或者偏移,是以可以通過sampler2D來對貼圖進 行操作。
在CG程式中,我們有這樣的約定,在一個貼圖變量(在我們例子中是_MainTex)之前加上uv兩個字母,就代表提取它的uv值(其實就是兩個代表貼圖上點的二維坐标 )。
Input 這個輸入結構通常擁有着色器需要的所有紋理坐标(texture coordinates)。紋理坐标(Texturecoordinates)必須被命名為“uv”後接紋理(texture)名字。(或者uv2開始,使用第二紋理坐标集)。
可以在輸入結構中根據自己的需要,可選附加這樣的一些候選值:
float3 viewDir - 視圖方向( view direction)值。為了計算視差效果(Parallax effects),邊緣光照(rim lighting)等,需要包含視圖方向( view direction)值。
float4 with COLOR semantic -每個頂點(per-vertex)顔色的插值。
float4 screenPos - 螢幕空間中的位置。 為了反射效果,需要包含螢幕空間中的位置資訊。比如在Dark Unity中所使用的 WetStreet着色器。
float3 worldPos - 世界空間中的位置。
float3 worldRefl - 世界空間中的反射向量。如果表面着色器(surface shader)不寫入法線(o.Normal)參數,将包含這個參數。 請參考這個例子:Reflect-Diffuse 着色器。
float3 worldNormal - 世界空間中的法線向量(normal vector)。如果表面着色器(surface shader)不寫入法線(o.Normal)參數,将包含這個參數。
float3 worldRefl; INTERNAL_DATA - 世界空間中的反射向量。如果表面着色器(surface shader)不寫入法線(o.Normal)參數,将包含這個參數。為了獲得基于每個頂點法線貼圖( per-pixel normal map)的反射向量(reflection vector)需要使用世界反射向量(WorldReflectionVector (IN, o.Normal))。
float3 worldNormal; INTERNAL_DATA -世界空間中的法線向量(normal vector)。如果表面着色器(surface shader)不寫入法線(o.Normal)參數,将包含這個參數。為了獲得基于每個頂點法線貼圖( per-pixel normal map)的法線向量(normal vector)需要使用世界法線向量(WorldNormalVector (IN, o.Normal))。
vertex shader modifier:Surface Shader還可以單獨指定一個vertex shader,用于做一些運算,vertex函數擁有固定的輸入參數 <code>inout appdata_full</code> 。下面的例子通過vertex shader對頂點在發現方向上做了一些偏移:
也可在vertex shader中計算自定義變量(Input中的這些變量不能以uv開頭,否則會出錯),這個計算結果會逐像素的傳遞到surface shader, 如下:


final color modifier: 編譯指令為finalcolor:functionName,函數接收三個參數 Input IN, SurfaceOutput o, inout fixed4 color
final color會影響渲染的最終顔色,它在所有的計算的最後進行影響,比如lightmap、lightprobe等産生的顔色也會受此函數影響。
final color可以用來實作fog,fog隻影響渲染的rgb,而不影響alpha,fog的原理是讓物體在最終的rgb和fog.color之間根據距離進行過度。


uniform:用于指定變量的資料初始化方式。 Uniform inputs,表示一些與三維渲染有關的離散資訊資料,這些資料通常由應用程式傳入,并通常不會随着圖元資訊的變化而變化,如材質對光的反射資訊、運動矩陣等。Uniform 修辭一個參數,表示該參數的值由外部應用程式初始化并傳入。
使用Uniform 修辭的變量,除了資料來源不同外,與其他變量是完全一樣的。需要注意的一點是:uniform 修辭的變量的值是從外部傳入的,是以在Cg 程式(頂點程式和片段程式)中通常使用uniform 參數修辭函數形參,不容許聲明一個用uniform 修辭的局部變量!
Lighting model:光照模式,在編寫surface shader時,我們隻需要描述各種屬性即可,真正的光照計算是Lighting mode負責的。
内置光照模式:Lambert(diffuse lighting)、BlinnPhong(specular lighting),源碼在unity install path}/Data/CGIncludes/Lighting.cginc目錄。
Lighting model其實就是按照指定規範編寫的一堆cg/hlsl,我們也可以定義自己的Lighting model。
自定義光照模式:
Surface Shader Lighting Models其實就是一些函數,這些函數我們也可以自己來寫。
下面的例子就是一個自定義的Lambert光照模式,并在此基礎上實作的Toon效果:
下面的代碼表示了一個簡單的BlinnPhong的模式:
再下面是關于lightmap的光照模式代碼,并在光照貼圖的基礎是添加了一個自定義顔色的實作:
還有一些相關的編譯選項:
#pragma debug 檢視生成的代碼
#pragma only_renderers: d3d9 隻支援特定平台
noforwardadd
nolightmap
exclude_path:prepass 不支援deferred模式