【Unity Shaders】使用CgInclude讓你的Shader模塊化――創(chuàng)建CgInclude文件存儲(chǔ)光照模型
來源:程序員人生 發(fā)布時(shí)間:2014-10-11 08:00:01 閱讀次數(shù):3371次
本系列主要參考《Unity Shaders and Effects Cookbook》一書(感謝原書作者),同時(shí)會(huì)加上一點(diǎn)個(gè)人理解或拓展。
這里是本書所有的插圖。這里是本書所需的代碼和資源(當(dāng)然你也可以從官網(wǎng)下載)。
========================================== 分割線 ==========================================
寫在前面
了解內(nèi)置的CgInclude文件當(dāng)然很好,但是如果我們想要?jiǎng)?chuàng)建自己的CgInclude文件來存儲(chǔ)光照模型和輔助函數(shù)又該怎么辦呢?
好消息是我們的確可以創(chuàng)建自己的CgInclude文件,壞消息是我們需要再了解一點(diǎn)代碼語法。好啦,那就開始吧!
準(zhǔn)備工作
好消息是這次的準(zhǔn)備工作終于有點(diǎn)不同了。。。壞消息是我不能再復(fù)制粘貼了。。。
- 首先,創(chuàng)建一個(gè)新的文本文件,例如MyCgInclude.txt。
- 然后,把文件后綴改為.cginc。當(dāng)然,操作系統(tǒng)一般會(huì)給你一些警示信息,說這個(gè)文件將變得不可用,但相信我,我們這個(gè)是可用的。
- 將新的.cginc文件導(dǎo)入到我們的Unity項(xiàng)目中(注意,在我的項(xiàng)目里,它的位置在一個(gè)新的名為CgIncludes的文件夾下)。等編譯完成后,我們可以看到Unity把該文件當(dāng)成一個(gè)CgInclude文件編譯好了。像下面這樣:

現(xiàn)在,我們已經(jīng)做好準(zhǔn)備可以創(chuàng)建自定義的CgInclude代碼啦。雙擊CgInclude文件,在MonoDevelop中打開它吧~
實(shí)現(xiàn)
打開CgInclude文件后,開始鍵入如下代碼。
- 首先,使用下面的預(yù)處理指令開始我們的CgInclude文件。這些聲明和#pragma、#include類似,在這里,我們想要去定義一個(gè)新的代碼集合,只要我們的Surface Shader在它的編譯指令里面包含了這個(gè)文件,這些代碼就可以執(zhí)行了。在CgInclude文件的最開始鍵入如下代碼:
#ifndef MY_CG_INCLUDE
#define MY_CG_INCLUDE
- 然后,我們必須確保#ifndef或者#ifdef要有一個(gè)#endif來結(jié)束定義檢查。就和一個(gè)if語句需要兩個(gè)花括號(hào)一樣。在#define指令下面鍵入如下代碼:
#endif
- 接下來,我們就可以填充剩余部分了。鍵入如下代碼:
// 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;
}
- 下面是完整的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
上面相當(dāng)于一個(gè)頭文件,但想要完整利用它還需要一些其他的步驟。我們需要告訴當(dāng)前的Shader,我們想要使用自己的文件和代碼。
- 返回上一節(jié)所用的Shader。我們需要在塊中包含我們自己的CgInclude文件,就像C++中需要在開頭添加頭文件引用一樣。同時(shí),之前我們的Shader使用內(nèi)置的Lambert光照模型,但現(xiàn)在我們想要使用自定義的Half Lambert光照模型。因?yàn)槲覀円呀?jīng)包含了該CgInclude文件,我們可以直接在#pragma指令中指明這一模型:
CGPROGRAM
#include "../CgIncludes/MyCgInclude.cginc"
#pragma surface surf HalfLambert
解釋:這里需要指明.cginc文件的相對(duì)與該Shader的路徑。也就是說,如果它和Shader放在同一個(gè)文件夾下,那么直接寫名稱即可。但在我的項(xiàng)目中,Shader放在了Shaders文件夾下,而.cginc放在了CgIncludes文件夾下,因此需要上述寫法。
- 最后,還記得我們在CgInclude文件中聲明了一個(gè)_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。如果出現(xiàn)編譯錯(cuò)誤,說找不到.cginc文件,那么就是你的位置寫的有問題,重新看上面的解釋更改一下就可以嘍。
最后的結(jié)果如下所示。注意到,這里Unity已經(jīng)使用了我們新的Half Lambert光照模型(和原來相比,就是提亮了背光面的亮度),并且添加了一個(gè)新的樣色樣本。左側(cè)為上一篇結(jié)果,右側(cè)為本篇結(jié)果。
解釋
當(dāng)編寫Shader的時(shí)候,我們可以像使用C++中的頭文件一樣,使用#include預(yù)處理指令來包含其他代碼集合。這告訴Unity我們想要當(dāng)前的Shader使用包含的這些文件中的代碼。我們這樣做實(shí)際上是在相應(yīng)位置包含了Cg代碼片段。
一旦我們聲明了#include指令,Unity就可以在項(xiàng)目中找到該文件,然后Unity會(huì)在文件中查找定義的代碼片段。也就是指,我們使用#ifndef指令和#ifndef指令的地方。當(dāng)我們聲明#ifndef指令時(shí),我們就是在告訴Unity,如果沒有定義這個(gè)名字,那么就使用這個(gè)名字去定義一些東西!在本節(jié)中,我們是想要去#define MY_CG_INCLUDE。因此,如果Unity沒有找到一個(gè)名為MY_CG_INCLUDE的定義,它就會(huì)在編譯該CgInclude文件時(shí)創(chuàng)建它。而#ifndef就是告訴Unity,這是該定義在這里結(jié)束啦,下面的不用再找啦!
現(xiàn)在,你看到了自定義的CgInclude文件是多么強(qiáng)大(和C++中的頭文件類似),我們可以使用它們來存儲(chǔ)所有的自定義光照模型,以減少代碼的重復(fù)。其他好處,像靈活性等,你可以聯(lián)想C++頭文件來得出啦~
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)