1. 程式人生 > >【Unity Shaders】使用CgInclude讓你的Shader模組化——Unity內建的CgInclude檔案

【Unity Shaders】使用CgInclude讓你的Shader模組化——Unity內建的CgInclude檔案

這裡是本書所有的插圖。這裡是本書所需的程式碼和資源(當然你也可以從官網下載)。

========================================== 分割線 ==========================================

寫在前面

啦啦啦,又開了新的一章。。。為什麼會講CgInclude呢?什麼又是Cg呢?嗚,按我的理解就是Cg是Shader語言裡面的跨平臺語言。眾所周知,GLSL語言是工作在OpenGL介面上的,而HLSL語言是工作在DirectX介面上的,而Cg語言可以使用這兩種不同的API,而不需要考慮平臺問題。當然,這裡面還有很多平臺相關的效能問題。Unity允許在Shader中巢狀Cg程式碼片段,然後會再編譯成OpenGL、DirectX、Flash等,以便讓我們的Shader工作在不同的平臺上。而使用CgInclude可以讓我們重用程式碼,實現Shader的模組化。

實際上,我們之前在不知不覺中就使用過一系列Unity內建的CgInclude來編寫Surface Shader。還記得Lambert、BlingPhony光照函式嗎?這就是使用了Unity提前為我們編寫好的Cg片段。理解並編寫我們自己的CgInclude檔案,有助於我們更快、更方便地修改Shader。而在編寫自己的檔案之前,我們先來學習下Unity為我們提供了哪些內建的光照模型、函式和狀態變數。

Surface Shader是Unity的驕傲,它為我們節省了很多程式碼量,其中很重要的原因就是它在背後為我們做了很多工作。我們可以在Editor/Data/CGIncludes(MAC下是Content/CGIncludes)下找到這些程式碼。這些檔案有的負責陰影和光照,有的則是一些輔助函式,還有一些負責平臺依賴。如果沒有它們,我們的Shader編寫起來會變得更加費勁。

你可以在這個連結裡找到Unity提供的一些資訊。

下面通過使用UnityCG.cginc檔案裡面的輔助函式,來正式開始理解內建的CgInclude檔案。

準備工作

  1. 建立一個新的場景和一個球體,新增一個平行光。
  2. 建立一個新的Shader和Material,可以命名為HelperFunctionShader。
  3. 把Shader賦給Material,把Material賦給球體。
  4. 最後,開啟UnityCG.cginc檔案,以便我們可以檢視這些輔助函式的具體實現。

實現


  1. 在Properties塊中新增下面新屬性。我們需要一張紋理以及一個控制去色滑動條:
    	Properties {
    		_MainTex ("Base (RGB)", 2D) = "white" {}
    		_DesatValue ("Desaturate", Range(0, 1)) = 0.5
    	}

  2. 在CGPROGRAM裡面新增上述新屬性的引用:
    		sampler2D _MainTex;
    		fixed _DesatValue;

    注意:fixed型別的範圍是-2.0到+2.0,精度是1/256,超過了就不行了哦!

  3. 最後,修改surf函式。它裡面使用了一個我們之前沒有見過的函式——lerp和Luminance,Luminance函式是在UnityCG.cginc裡面定義的,而lerp是Cg的一個函式。
    		void surf (Input IN, inout SurfaceOutput o) {
    			half4 c = tex2D (_MainTex, IN.uv_MainTex);
    			
    			o.Albedo = lerp(c.rgb, Luminance(c.rgb), _DesatValue);
    			o.Alpha = c.a;
    		}
最後,通過改變去色滑動條的大小,就可以得到下面的效果(從左到右去色值分別對應0.0,0.5,1.0):

解釋

我們通過使用內建的輔助函式Luminance(),來快速得到一個去色效果,或者說是實現了Shader的灰度化。這些都是因為UnityCG.cginc檔案自動為我們的Shader包含了相關程式碼。如果你搜索UnityCG.cginc檔案,你可以找到如下程式碼:
// Converts color to luminance (grayscale)
inline fixed Luminance( fixed3 c )
{
	return dot( c, fixed3(0.22, 0.707, 0.071) );
}
由於Unity會自動編譯這些程式碼,因此我們可以直接在Shader中使用這些函式。而另一個函式lerp(),是Cg的一個函式,官網裡有詳細的函式說明。細心的話,你可以在CGInclude資料夾下找到另一個檔案——Lighting.cginc(程式碼不多)。這個檔案裡面包含了所有我們在類似#pragmasurfacesurfLambert這樣的聲明裡使用的光照模型。