Cg(C for Graphic)語言函數使用方法

摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU編程與CG語言之陽春白雪下里巴人”

通過第 5 章到第 7 章的閱讀,我們已經知道了怎麼聲明變量(第 5 章),怎麼寫表達式和語句(第 6 章),怎麼將輸入 / 輸出參數綁定到語義詞(第 7 章),本章將首先描述 Cg 語言中函數的寫法,以及函數是否可以重載;然後闡述頂點 / 片段着色程序中入口函數的概念(類似 C/C++ 中的 main() 函數);最後,以 Cg 標準函數庫來結束本章。

8.1 函數

函數可以被看作一個由用戶定義的操作。 Cg 語言中的函數聲明形式與 C/C++ 中相同, 由返回類型( return type )、函數名、形參列表( parameter list ,位於括號中,並用逗號分隔的參數表)和函數體組成。函數體包含在花括號中。如果沒有返回值,則函數的返回類型是 void 。下面是函數定義的例子:

 

void myFunc(inout float val )

{

 

       ………………

   val += 10.0;

}

 

 

float myFunc(float vals[])

{

   float sum = 0.0;

     ……………………..

   return sum;

}

注意:如果函數沒有返回值,函數的返回類型一定要是 void ,否則編譯會出現大量的錯誤,錯誤信息的大概形式是:

error C0000: syntax error, unexpected’(’at token “(”

error C0501: type name expected at token “(”

error C1110: function “main_v” has no return statement

參數傳遞機制是函數概念中的重中之重,請參閱 7.4 輸入 / 輸出修辭符 中的論述。此外,有一個比較特殊的函數形參類型,不論在 C/C++ 中還是在 Cg 語言中,都是一個令人頭疼的話題,它就是數組形參。

8.1.1 數組形參

C/C++ 中,當一個數組作爲函數的形參時,實際上傳入的只是指向首元素的指針,並且數組邊界被忽略(參閱 stephen C.Dewhurst 所著的《 C++ 必知必會》)。而在 Cg 語言中不存在指針機制(圖形硬件不支持),數組作爲函數形參,傳遞的是數組的完整拷貝。關於 Cg 中形參數組的原始資料可以在文獻 [3]Array 章節中查到:

 “The most important difference from C is that arrays are first-class types. That means array assignments actually copy the entire array, and arrays that are passed as parameters are passed by value, rather than by reference”.

這段英文中描述道, Cg 語言中數組是“ first-class types ”,中文翻譯爲 第一類數據類型 ,所謂 第一類( first-class 的含義是,強調該類型數據是 不可分解的、最高級別的、不被重述的 ,即 第一類數據類型 基礎數據類型 的概念是近同的。如有興趣深入瞭解 “first-class” 概念,可參閱 Matthieu Sozeau and Nicolas Oury 所著的 “First-Class Type Classes” 一文。

數組類型變量作爲函數形參,可以是一維的也可以是多維的,並且不必聲明數組長度,即 Unsized Array 。例如:

 

float myFunc( float vals[])

{

float sum = 0.0;

   for(int i = 0; i< vals.length; i++)

   {

      sum += vals[i];

   }

      return sum;

}

myFunc 是一個函數,輸入一個數組變量,計算數組中所有數據之和,然後返回 float 類型數據。請注意:數組形參不必指定長度。如果指定了函數中形參數組的長度,那麼在調用該函數時實參數組的長度和形參數組的長度必須保持一致,如果沒有保持一致,編譯時會出現錯誤提示信息: error C1102: incompatible type for parameter…

 

float myFunc( float vals[3])

{

float sum = 0.0;

   for(int i = 0; i< vals.length; i++)

   {

      sum += vals[i];

   }

      return sum;

}

 

void main(…)

{

   float a[2] = {0.0, 1.0};

float b[3] = {0.0, 1.0, 2.0};

   myFunc(a); // 錯誤調用,會導致編譯錯誤

   myFunc(b); // 正確調用

}

 

對於函數的形參數組最好不要指定長度,這樣就可以片配任意長度的參數數組。

如果函數的形參數組是多維數組,其聲明方式和上面是一樣的,可以不指定長度;如果指定形參數組長度,則實參數組長度必須保持一致。

8.2 函數重載

Cg 語言支持函數重載( Functon Overlaoding ),其方式和 C++ 基本一致,通過形參列表的個數和類型來進行函數區分。例如:

 

bool function(float a, float b)   {return  ( a == b);}

bool function(boo a, bool b)   {return  ( a == b);}

 

Cg 語言標準函數庫中絕大部分函數都被重載過。

8.3 入口函數

所謂入口函數,即一個程序執行的入口,例如 C/C++ 程序中的 main() 函數。

通常高級語言程序中只有一個入口函數,不過由於着色程序分爲頂點程序和片斷程序,兩者對應着圖形流水線上的不同階段,所以這兩個程序都各有一個入口函數。

頂點程序和片段程序有且只有一個入口函數,當程序進行編譯時,需要指定入口函數名稱(參閱 4.4 CG 編譯),除非入口函數名爲 main 。當我們編寫或閱讀 Cg 代碼時,如何區分哪個函數是入口函數呢?或者哪個入口函數對應着頂點程序或片段程序?事實上,頂點程序和片段程序的入口函數形式,已經完全由它們在渲染管線中所處的階段所決定。在前面已經闡述過,頂點程序接收應用程序傳遞的頂點數據(通常位於模型座標空間),然後進行座標空間轉換和光照處理,最後輸出投影座標和計算得到的光照顏色;而片段程序接收從頂點程序輸出的數據,並進行像素顏色計算。在片段程序中往往涉及到紋理顏色的處理,其輸入參數中常有紋理形參的聲明。所以通過觀察程序的輸入輸出語義綁定(參閱 7.5 節語義詞與語義綁定),就可以區分入口函數對應到頂點程序還是片段程序。而內部函數則忽略任何應用到形參上的語義,通常也沒有人會在內部函數使用語義詞,除非他 / 她的目的是練習打字速度。

下面的代碼展示了一個頂點程序的入口函數,名稱爲 C2E1v_green ,這個頂點着色程序接收二維頂點數據,然後轉換爲齊次座標(請思考,頂點和向量的齊次座標有什麼不同?齊次座標的本質是什麼?),並將該頂點設置爲綠色,最後使用 return 語句輸出。如果電腦安裝了 Cg ,該程序文件位於 “NVIDIA Corporation/Cg/examples/OpenGL/basic/ 01_vertex_program/C2E1v_green.cg” 目錄下

 

struct C2E1v_Output {

  float4 position : POSITION;

  float3 color    : COLOR;

};

 

C2E1v_Output C2E1v_green(float2 position : POSITION)

{    

  C2E1v_Output OUT;

 

  OUT.position = float4(position,0,1);

  OUT.color = float3(0,1,0);

 

  return OUT;    

}

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章