第05章 CG 數(shù)據(jù)類型
書讀的越多而不加思考未巫,你就會(huì)覺得你知道得很多;而當(dāng)你讀書而思考得越多的時(shí)候,你就會(huì)越清楚地看到,你知道得很少笤虫。
------ 伏爾泰
本章將著重介紹 Cg 語言中預(yù)定義的內(nèi)置(built in)的、或稱為基本(primitive)的數(shù)據(jù)類型祖凫。然后介紹可以用來聲明對(duì)象的各種類型琼蚯,主要是數(shù)組和結(jié)構(gòu)類型。學(xué)習(xí)本章時(shí)惠况,需要體會(huì)內(nèi)置向量類型和數(shù)組類型的區(qū)別遭庶。
5.1 基本數(shù)據(jù)類型
Cg 支持 7 種基本的數(shù)據(jù)類型:
- float, 32 位浮點(diǎn)數(shù)據(jù),一個(gè)符號(hào)位稠屠。浮點(diǎn)數(shù)據(jù)類型被所有的 Profiles 支持(但是 DirectX8 Pixel Profiles 在一些操作中降低了浮點(diǎn)數(shù)的精度和范圍)峦睡;
- half,16 位浮點(diǎn)數(shù)據(jù)权埠;
- int榨了,32 位整形數(shù)據(jù),有些 Profile 會(huì)將 int 類型作為 float 類型使用攘蔽;
- fixed阻逮,12 位定點(diǎn)數(shù),被所有的 fragment Profiles 所支持秩彤;
- bool叔扼,布爾數(shù)據(jù),通常用于 if 和條件操作符(?:), 布爾數(shù)據(jù)類型被所有的 Profiles 支持漫雷;
- sampler, 紋理對(duì)象的句柄(the handle to a texture object)瓜富,分為 6 類:sampler,sampler1D降盹,sampler2D与柑,sampler3D,samplerCUBE 和 samplerRECT。DirectX Profiles 不支持 samplerRECT 類型价捧,除此之外這些類型被所有的 Pixel Profiles 和 NV40 vertex program profile 所支持(CgUsersManual 30 頁)丑念。由此可見,在不遠(yuǎn)的未來结蟋,頂點(diǎn)程序也將廣泛支持紋理操作脯倚;
- string,字符類型嵌屎,該類型不被當(dāng)前存在 Profiles 所支持推正,實(shí)際上也沒有必要在 Cg 程序中用到字符類型,但是泥可以通過 Cg Runtime API 聲明該類型變量宝惰,并賦值植榕;因此,該類型變量可以保存 Cg 文件的信息尼夺。
前 6 種類型會(huì)經(jīng)常用到尊残,事實(shí)上在 Wikipedia 有關(guān) Cg 語言的闡述中只列舉了前 6 種類型,而并沒有提到 string 數(shù)據(jù)類型淤堵。除了上面的基本數(shù)據(jù)類型外夜郁,Cg 還提供了內(nèi)置的向量數(shù)據(jù)(built-in vector data types),內(nèi)置的向量數(shù)據(jù)類型基于基礎(chǔ)數(shù)據(jù)類型粘勒。例如:float4竞端,表示 float 類型的 4 元向量; bool4庙睡,表示 bool 類型 4 元向量事富。
注意:向量最長(zhǎng)不能超過 4 元,即在 Cg 程序中可以聲明 float1乘陪、float2统台、float3、float4 類型的數(shù)組變量啡邑,但是不能聲明超過 4 元的向量贱勃,例如:
float5 array; // 編譯報(bào)錯(cuò)
向量初始化方式一般為:
float5 array = float4(1.0, 2.0, 3.0, 4.0);
較長(zhǎng)的向量還可以通過較短的向量進(jìn)行構(gòu)建:
float2 a = float2(1.0, 2.0);
float4 b = float4(a, 0.0, 0.0, 0.0);
此外,Cg 還提供矩陣數(shù)據(jù)類型谤逼,不過最大的維數(shù)不能超過 4 * 4 階贵扰。例如:
float1x1 matrix1; // 等價(jià)于 float matirx1; x 是字符流部,并不是乘號(hào)戚绕;
float2x3 matrix2; // 表示2 * 3 階矩陣枝冀,包含了 6 個(gè) float 類型數(shù)據(jù)舞丛;
float4x3 matrix3耘子; // 表示4 * 2 階矩陣,包含了 8 個(gè) float 類型數(shù)據(jù)球切;
float4x4 matrix4谷誓; // 表示4 * 4 階矩陣,這是最大的維數(shù)吨凑;
矩陣的初始化方式為:
float2x3 matrix5 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
注意:Cg 中向量捍歪、矩陣與數(shù)組是完全不同,向量和矩陣是內(nèi)置的數(shù)據(jù)類型(矩陣基于向量)怀骤,而數(shù)組則是一種數(shù)據(jù)結(jié)構(gòu)费封,不是內(nèi)置數(shù)據(jù)類型焕妙!這一點(diǎn)和 C\C++ 中不太一樣蒋伦,在 C\C++ 中,這三者同屬于數(shù)據(jù)結(jié)構(gòu)焚鹊,數(shù)組可以構(gòu)建向量和矩陣痕届。下一節(jié)中將詳細(xì)闡述 Cg 中的數(shù)組類型。
5.2 數(shù)組類型
“General-purpose arrays can only be used ad uniform parameters to a vertex program. The intent is to allow an application to pass arrays of skinning matrices and arrays of light parameters to a vertex program”(文獻(xiàn)【3】的 Array 章節(jié))末患。
在著色程序中研叫,數(shù)組通常的使用目的是:作為從外部應(yīng)用程序傳入大量參數(shù)到 Cg 的頂點(diǎn)程序中的形參接口,例如與皮膚形變相關(guān)的矩陣數(shù)組璧针,或者光照參數(shù)數(shù)組等嚷炉。
簡(jiǎn)而言之,數(shù)組數(shù)據(jù)類型在 Cg 程序中的作用是:作為函數(shù)的形參探橱,用于大量數(shù)據(jù)的傳遞申屹。
Cg 中聲明數(shù)組變量的方式和 C 語言類似,例如:
float a[10]; // 聲明了一個(gè)數(shù)組隧膏,包含 10 個(gè) float 類型數(shù)據(jù)哗讥;
float4 b[10]; // 聲明了一個(gè)數(shù)組,包含 10 個(gè) float4 類型數(shù)據(jù)胞枕;
對(duì)數(shù)組進(jìn)行初始化的方式為:
float a[4] = {1.0, 2.0, 3.0, 4.0}; // 初始化一個(gè)數(shù)組杆煞;
要獲取數(shù)組長(zhǎng)度,可以調(diào)用“.legth”腐泻,例如:
float a[10]; // 聲明一個(gè)數(shù)組决乎;
int length = a.length; // 獲取數(shù)組的長(zhǎng)度;
聲明多維數(shù)組以及初始化的方式如下所示:
float b[2][3] = {{0.0, 0.0, 0.0}, {1.0, 1.0, 1.0}}派桩;
對(duì)多維數(shù)組取長(zhǎng)度的方式為:
int length1 = b.length瑞驱; // length1 值為 2
int length2 = b[0].length; // length2 值為 3
數(shù)組和矩陣有些類似窄坦,但是并不是相同唤反。例如 4 * 4 階數(shù)組的聲明方式為: float M[4][4]; 4 階矩陣的聲明方式為: float4x4 M凳寺。前者是一個(gè)數(shù)據(jù)結(jié)構(gòu),包含 16 個(gè) float 類型數(shù)據(jù)彤侍,后者是一個(gè) 4 階矩陣數(shù)據(jù)肠缨。float4x4 M[4],表示一個(gè)數(shù)組盏阶,包含 4 個(gè) 4 階矩陣數(shù)據(jù)晒奕。
進(jìn)行數(shù)組變量聲明時(shí),一定要指定數(shù)組長(zhǎng)度名斟,除非是作為函數(shù)參數(shù)而聲明的形參數(shù)組脑慧。并且在當(dāng)前的 profiles 中,數(shù)組的長(zhǎng)度和所引用的數(shù)組元素的地址必須在編譯時(shí)就知道砰盐。
“Unsized arrays may only be declared as function parameters-key may not be declared as variables. Furthermore, in all current profiles, the actual array length and address calculations implied by array indexing must be known at compile time”(文獻(xiàn)【3】)闷袒。
由于形參數(shù)組的概念與函數(shù)的概念緊密結(jié)合,所以將在第 8 章的 8.1 函數(shù)章節(jié)進(jìn)行統(tǒng)一闡述岩梳。
5.3 結(jié)構(gòu)類型
Cg 語言支持結(jié)構(gòu)體(structure)囊骤,實(shí)際上 Cg 中的結(jié)構(gòu)體的聲明、使用和 C++ 非常類似(只是類似冀值,不是相同)也物。一個(gè)結(jié)構(gòu)體相當(dāng)于一種數(shù)據(jù)類型,可以定義該類型的變量列疗。引入結(jié)構(gòu)體機(jī)制滑蚯,賦予了 Cg 語言一絲面向?qū)ο蟮纳省_€記得 C++ 中抵栈,結(jié)構(gòu)體與類的區(qū)別嗎告材?沒有區(qū)別,除了默認(rèn)訪問屬性在結(jié)構(gòu)體中為 public竭讳,類中為 private创葡,所以結(jié)構(gòu)體與類是非常近似的,由此可以看出 shader 語言的發(fā)展趨勢(shì)還是向著具有面向?qū)ο筇匦缘母呒?jí)語言绢慢。不過目前的 Cg 語言中的結(jié)構(gòu)體以展現(xiàn)“封裝”功能為主灿渴,并不支持集成機(jī)制。
結(jié)構(gòu)體的聲明以關(guān)鍵字 struct 開始胰舆,然后緊跟結(jié)構(gòu)體的名字骚露,接下來是一個(gè)大括號(hào),并以分號(hào)結(jié)尾(不要忘了分號(hào))缚窿。大括號(hào)中是結(jié)構(gòu)體的定義棘幸,分為兩大類:成員變量和成員函數(shù)。例如倦零,定義一個(gè)名為 myAdd 的結(jié)構(gòu)體误续,包含一個(gè)成員變量吨悍,和一個(gè)執(zhí)行相加功能的成員函數(shù),然后聲明一個(gè)該結(jié)構(gòu)體類型的變量蹋嵌,代碼為:
struct myAdd
{
float val;
float add(float x)
{
return val + x;
}
};
myAdds;
使用符號(hào)“.”引用結(jié)構(gòu)體中的成員變量和成員函數(shù)育瓜。例如:
float a = s.value;
float b = s.add(a)栽烂;
注意:在當(dāng)前的所有的 profile 版本下躏仇,如果結(jié)構(gòu)體的一個(gè)成員函數(shù)使用了成員變量,則該成員變量要聲明在前腺办。此外焰手,成員函數(shù)是否可以重載依賴于使用的 Profile 版本。(文獻(xiàn)【3】 的 structures and Member functions 章節(jié))
一般來說怀喉,Cg 的源代碼都會(huì)在文件首部定義二個(gè)結(jié)構(gòu)體书妻,分別用于定義輸入和輸出的類型,這個(gè)二個(gè)結(jié)構(gòu)體定義與普通的 C 結(jié)構(gòu)定義不同磺送,除了定義結(jié)構(gòu)體成員的數(shù)據(jù)類型外驻子,還定義了該成員的綁定語義類型(Binding Semantics)灿意,所謂綁定語義類型是為了與宿主環(huán)境進(jìn)行數(shù)據(jù)交換的時(shí)候識(shí)別不同數(shù)據(jù)類型的估灿。目前 Cg 支持的綁定語義類型包括 POSTION (位置),COLOR(顏色)缤剧,NORMAL(法向量)馅袁,Texcoord(紋理坐標(biāo))等類型。
當(dāng)頂點(diǎn)著色程序向片段著色程序傳遞的數(shù)據(jù)類型較多的情況下荒辕,使用結(jié)構(gòu)體可以大大的方便代碼的編寫和維護(hù)汗销。總而言之抵窒,使用結(jié)構(gòu)體是一個(gè)好習(xí)慣弛针,高智商的孩子都使用(感覺是不是很囧 哈哈哈 O(∩_∩)O哈哈~)。
5.4 接口(Interfaces)類型
Cg 語言提供接口類型李皇,實(shí)際上削茁,我本人很少見到使用接口類型的著色程序,原因在于掉房,Cg 語言中的接口類型還不夠完善茧跋,不能被擴(kuò)展和包含。此外卓囚,目前的 GPU 編程大多是針對(duì)獨(dú)立的算法進(jìn)行編碼瘾杭,規(guī)模較小,使用接口類型沒有太大的優(yōu)勢(shì)哪亿。所以這里對(duì)該類型并不多做說明粥烁。有興趣的讀者可以參閱文獻(xiàn)【3】的 Interfaces 章節(jié)贤笆。
5.5 類型轉(zhuǎn)換
Cg 中的類型轉(zhuǎn)換和 C 語言的類型轉(zhuǎn)換很類似。C 語言中類型轉(zhuǎn)換可以是強(qiáng)制類型轉(zhuǎn)換讨阻,也可以是隱式類型轉(zhuǎn)換苏潜,如果是后者,則數(shù)據(jù)類型從低精度向高精度轉(zhuǎn)換变勇。在 Cg 語言中也是如此恤左。例如:
float a = 1.0;
half b = 2.0搀绣;
float c = a + b飞袋; // 等價(jià)于 float c = a + (float)b;
當(dāng)有類型變量和無類型常量數(shù)據(jù)進(jìn)行運(yùn)算時(shí),該常量數(shù)據(jù)不做類型轉(zhuǎn)換链患,舉例如下:
float a = 1.0巧鸭;
float b = a + 2.0;// 2.0 為無類型常量數(shù)據(jù)麻捻,編譯時(shí)作為 float 類型;
Cg 語言中對(duì)于常量數(shù)據(jù)可以加上類型后綴纲仍,表示該數(shù)據(jù)的類型,例如:
float a = 1.0贸毕;
float b = a + 2.0h郑叠;// 2.0h 為half類型常量數(shù)據(jù);
運(yùn)算是需要做類型轉(zhuǎn)換常量的類型后綴(type suffix)有 3 種:
f : 表示 float明棍;
h : 表示 half乡革;
x : 表示 fixed;