【Unity Shaders】使用CgInclude讓你的Shader模塊化——建立CgInclude文件存儲光照模型

本系列主要參考《Unity Shaders and Effects Cookbook》一書(感謝原書做者),同一時候會加上一點我的理解或拓展。函數

這裏是本書所有的插圖。ui

這裏是本書所需的代碼和資源(固然你也可以從官網下載)。spa

========================================== 切割線 ==========================================操作系統



寫在前面


瞭解內置的CgInclude文件固然很是好,但是假設咱們想要建立本身的CgInclude文件來存儲光照模型和輔助函數又該怎麼辦呢?.net


好消息是咱們的確可以建立本身的CgInclude文件。壞消息是咱們需要再瞭解一點代碼語法。好啦,那就開始吧!code



準備工做


好消息是此次的準備工做最終有點不一樣了。。orm

。壞消息是我不能再複製粘貼了。blog

ip

資源

  1. 首先,建立一個新的文本文件,好比MyCgInclude.txt。
  2. 而後。把文件後綴改成.cginc。

    固然,操做系統一般會給你一些警示信息。說這個文件將變得不可用,但相信我,咱們這個是可用的。

  3. 將新的.cginc文件導入到咱們的Unity項目中(注意,在個人項目裏,它的位置在一個新的名爲CgIncludes的目錄下)。等編譯完畢後,咱們可以看到Unity把該文件當成一個CgInclude文件編譯好了。像如下這樣:

現在,咱們已經作好準備可以建立本身定義的CgInclude代碼啦。雙擊CgInclude文件。在MonoDevelop中打開它吧~


實現


打開CgInclude文件後。開始鍵入例如如下代碼。
  1. 首先,使用如下的預處理指令開始咱們的CgInclude文件。

    這些聲明和#pragma、#include類似,在這裏,咱們想要去定義一個新的代碼集合,僅僅要咱們的Surface Shader在它的編譯指令裏面包括了這個文件,這些代碼就可以運行了。在CgInclude文件的最開始鍵入例如如下代碼:

    #ifndef MY_CG_INCLUDE
    #define MY_CG_INCLUDE

  2. 而後。咱們必須確保#ifndef或者#ifdef要有一個#endif來結束定義檢查。

    就和一個if語句需要兩個花括號同樣。

    #define指令如下鍵入例如如下代碼:

    #endif

  3. 接下來,咱們就可以填充剩餘部分了。鍵入例如如下代碼:
    // Custom Build-in Variables
    fixed4 _MyColor;
    
    // Lighting models
    inline fixed4 LightingHalfLambert (SurfaceOutput s, fixed3 lightDir, fixed atten) {
    	fixed diff = max (0, dot (s.Normal, lightDir));
    	
    	diff = (diff + 0.5) * 0.5;
    	
    	fixed4 c;
    	c.rgb = s.Albedo * _LightColor0.rgb * ((diff * _MyColor.rgb) * atten * 2);
    	c.a = s.Alpha;
    	return c;
    }
    

  4. 如下是完整的MyCgInlcude.cginc文件:
    #ifndef MY_CG_INCLUDE
    #define MY_CG_INCLUDE
    
    // Custom Build-in Variables
    fixed4 _MyColor;
    
    // Lighting models
    inline fixed4 LightingHalfLambert (SurfaceOutput s, fixed3 lightDir, fixed atten) {
    	fixed diff = max (0, dot (s.Normal, lightDir));
    	
    	diff = (diff + 0.5) * 0.5;
    	
    	fixed4 c;
    	c.rgb = s.Albedo * _LightColor0.rgb * ((diff * _MyColor.rgb) * atten * 2);
    	c.a = s.Alpha;
    	return c;
    }
    
    #endif

    上面至關於一個頭文件,但想要完整利用它還需要一些其它的步驟。

    咱們需要告訴當前的Shader。咱們想要使用本身的文件和代碼。

  5. 返回上一節所用的Shader。

    咱們需要在塊中包括咱們本身的CgInclude文件,就像C++中需要在開頭加入頭文件引用同樣。

    同一時候,以前咱們的Shader使用內置的Lambert光照模型,但現在咱們想要使用本身定義的Half Lambert光照模型。

    因爲咱們已經包括了該CgInclude文件,咱們可以直接在#pragma指令中指明這一模型:

    		CGPROGRAM
    		#include "../CgIncludes/MyCgInclude.cginc"
    		#pragma surface surf HalfLambert

    解釋:這裏需要指明.cginc文件的相對與該Shader的路徑。

    也就是說。假設它和Shader放在同一個目錄下,那麼直接寫名稱就能夠。

    但在個人項目中,Shader放在了Shaders目錄下,而.cginc放在了CgIncludes目錄下。所以需要上述寫法。

  6. 最後,還記得咱們在CgInclude文件裏聲明瞭一個_MyColor變量嗎?咱們還需要在Shader的Properties中加入該屬性:
    	Properties {
    		_MainTex ("Base (RGB)", 2D) = "white" {}
    		_DesatValue ("Desaturate", Range(0, 1)) = 0.5
    		_MyColor ("My Color", Color) = (1, 1, 1, 1)
    	}


最後,返回Unity。假設出現編譯錯誤。說找不到.cginc文件。那麼就是你的位置寫的有問題。又一次看上面的解釋更改一下就可以嘍。

最後的結果例如如下所看到的。注意到。這裏Unity已經使用了咱們新的Half Lambert光照模型(和原來相比。就是提亮了背光面的亮度),並且加入了一個新的樣色樣本。左側爲上一篇結果,右側爲本篇結果。
 



解釋


當編寫Shader的時候,咱們可以像使用C++中的頭文件同樣,使用#include預處理指令來包括其它代碼集合。這告訴Unity咱們想要當前的Shader使用包括的這些文件裏的代碼。咱們這樣作其實是在對應位置包括了Cg代碼片斷。

一旦咱們聲明瞭#include指令,Unity就可以在項目中找到該文件,而後Unity會在文件裏查找定義的代碼片斷。

也就是指。咱們使用#ifndef指令和#ifndef指令的地方。

當咱們聲明#ifndef指令時,咱們就是在告訴Unity,假設未定義這個名字,那麼就使用這個名字去定義一些東西!

在本節中。咱們是想要去#define MY_CG_INCLUDE

所以,假設Unity沒有找到一個名爲MY_CG_INCLUDE的定義,它就會在編譯該CgInclude文件時建立它。而#endif就是告訴Unity,這是該定義在這裏結束啦。如下的不用再找啦。


現在,你看到了本身定義的CgInclude文件是多麼強大(和C++中的頭文件類似),咱們可以使用它們來存儲所有的本身定義光照模型。以下降代碼的反覆。

其它優勢,像靈活性等。你可以聯想C++頭文件來得出啦~

相關文章
相關標籤/搜索