頂點函數是在每個頂點被傳送到GPU之前被調用一次。它的作用是從模型坐標系中得到三維坐標,然后再轉換到其渲染到屏幕時在屏幕坐標系中的二維位置。因此,通過頂點函數,我們可以修改頂點的位置、顏色和UV坐標。一旦我們完成了對頂點的修改后,就會進入到surf函數的執行。與頂點函數是逐頂點執行的方式不同,surf函數則是逐像素執行的。
通過頂點函數,我們可以創造像海上的波浪、旗幟飄動的動態效果,或者使用Shader來給頂點着色。這一篇,我們來學習如何在一個Surface Shader中創建一個最簡單的頂點函數!
首先,我們要准備一個已經給頂點着色過的模型,以便我們可以在頂點函數中查看頂點顏色。為了方便,我們使用本書自帶資源(見文章開頭)中第七章的模型資源——VertexColorObject.fbx。我們把VertexColorObject.fbx導入Unity,並拖入到一個新的場景中。最后添加一個平行光。
新建一個Shader和Material,可以分別命名為SimpleVertexColor,並將Shader賦給Material,再將Material賦給模型。
你的場景應該看起來是這樣的:
下面,我們開始編寫Shader。
在Properties塊中添加新的Properties:
Properties { _MainTint(“Global Color Tint”, Color) = (1,1,1,1) }
為Properties中新添加的屬性添加對應的引用:
float4 _MainTint;
下面是很重要的Input結構。我們添加了一個新的變量vertColor以便surf函數可以訪問vert函數中傳遞的數據:
struct Input { float2 uv_MainTex; float4 vertColor; };
最后,我們使用從Input中得到的數據填充SurfaceOutput結構體的Albedo參數:
void surf (Input IN, inout SurfaceOutput o) { o.Albedo = IN.vertColor.rgb * _MainTint.rgb; }
完整代碼如下:
Shader “Custom/SimpleVertexColor” { Properties { _MainTint(“Global Color Tint”, Color) = (1,1,1,1) } SubShader { Tags { “RenderType”=”Opaque” } LOD 200 CGPROGRAM #pragma surface surf Lambert vertex:vert float4 _MainTint; struct Input { float2 uv_MainTex; float4 vertColor; }; void vert(inout appdata_full v, out Input o) { o.vertColor = v.color; } void surf (Input IN, inout SurfaceOutput o) { o.Albedo = IN.vertColor.rgb * _MainTint.rgb; } ENDCG } FallBack “Diffuse” }
效果如下:
解釋
通過頂點函數,我們可以修改頂點的位置、顏色、UV坐標等值。在本節中我們使用了一個從maya導入的已給頂點着色的模型,但我們可以發現,在使用默認材質的情況下這些顏色在Unity中是不顯示的。我們需要編寫Shader,提取這些顏色再在模型上顯示出來。
我們首先通過在#pragma聲明中添加vertex:vert語句。這實際上告訴Unity,嘿,不要用你自己內置的頂點函數訪問模型頂點信息啦,去我寫的Shader里找一個名叫vert的家伙,用它去處理信息!如果Unity沒有找到,它就會報一個編譯錯誤。
vert函數里,除了我們熟悉的Input結構體,還有一個很特別的參數——appdata_full 。這個參數也是Unity內置的一個變量,它包含了模型頂點的所有信息,包括位置、切線、法線、兩個紋理坐標和顏色信息。其他的還有appdata_base和appdata_tan,具體可以看見官網。
你還可以發現,vertColor是一個float4類型的變量,這意味着我們還可以訪問它的透明通道。像下面這樣:
void surf (Input IN, inout SurfaceOutput o)
{
o.Albedo = IN.vertColor.rgb * _MainTint.rgb;
o.Alpha = IN.vertColor.a;
}