NeHe OpenGL教程 第四十七课:CG顶点脚本
轉自【翻譯】NeHe OpenGL 教程
前言
聲明,此?NeHe OpenGL教程系列文章由51博客yarin翻譯(2010-08-19),本博客為轉載并稍加整理與修改。對NeHe的OpenGL管線教程的編寫,以及yarn的翻譯整理表示感謝。
?
?
NeHe OpenGL第四十七課:CG頂點腳本
CG 頂點腳本
nVidio的面向GPU的C語言,如果你相信它就好好學學吧,同樣這里也只是個入門。記住,類似的語言還有微軟的HLSL,OpenGL的GLSL,ATI的shaderMonker。不要選錯哦:)
使用頂點和片斷腳本去做渲染工作可以得到額外的好處,最大的好處就是把CPU的一些工作交給了GPU,Cg提供了書寫這些強大的腳本的一種手段。
這篇教程有許多目的,第一向你展現了一個非常簡單的頂點腳本,第二向你說明如何在OpenGL中使用Cg編寫的腳本。
這個教程是基于最新的NeHeGL的基本代碼,為了獲得更多的信息,你可以訪問nVidia的官方網站(developer.nvidia.com),它會給你一個完整的答案。
注意:這個教程不是叫你如何去寫一個完整的Cg腳本,而是教你在OpenGL中載入并運行腳本。
開始:
第一步,從nVidia的網站上下載Cg Compiler庫,最好去下載1.1版本的,因為nvidia各個版本的變化很大,為了讓程序不出現任何問題,最好這樣做,因為我們用的是1.1版本的。
下一步,包含編譯需要的頭文件和庫文件。
我已經幫你把它們拷貝到了工程的文件夾里了。
Cg介紹
你必須有以下幾個概念:
1、頂點腳本會作用于你輸入的每一個頂點,如果你想要作用于一些頂點,那么你必須在作用前加載頂點腳本,并于作用后釋放頂點腳本。
2、頂點腳本輸出的結果被送入到片斷處理器中,你不用管這其中是如何實現的。
最后,記住頂點腳本在圖元裝配前被執行,片斷腳本在光柵化后被執行。
好了,現在我們創建一個空白的文件吧(保存為wave.cg),接著我們創建一個數據結構,它被我們得腳本使用。下面的代碼被加入到wave.cg文件中。
?
struct appdata {?float4 position : POSITION;?float4 color?: COLOR0;?float3 wave?: COLOR1;};
上面的結果說明,我們輸入的頂點包含一個位置坐標,一個顏色和我們自定義的波的顏色
下面的代碼定義一個輸出頂點的數據,包括一個頂點和顏色
?
struct vfconn{?float4 HPos?: POSITION;?float4 Col0?: COLOR0;};
??
下面的代碼是Cg的主函數,每個頂點都會被以下函數執行:
?
vfconn main(appdata IN, uniform float4x4 ModelViewProj)
{
vfconn OUT; // 保存我們輸出頂點的數據
// 計算頂點y的坐標
IN.position.y = ( sin(IN.wave.x + (IN.position.x / 5.0) ) + sin(IN.wave.x + (IN.position.z / 4.0) ) ) * 2.5f;
// 保存到輸出數據中
OUT.HPos = mul(ModelViewProj, IN.position);
// 不改變輸入的顏色
OUT.Col0.xyz = IN.color.xyz;
return OUT;
}
完成了上面的代碼,記得保存一下.
下面我們到了程序中,首先包含使用cg需要的頭文件,和庫文件
?
#include <cg\cg.h>?????????#include <cg\cggl.h>?????????
#pragma comment( lib, "cg.lib" )???????#pragma comment( lib, "cggl.lib" )???????
下面我們定義一些全局變量,用來計算我們得網格和控制cg程序的開關?
??
#define??SIZE?64????????// 定義網格的大小bool??cg_enable = TRUE, sp;???????// 開關Cg程序GLfloat??mesh[SIZE][SIZE][3];???????// 保存我們的網格GLfloat??wave_movement = 0.0f;???????// 記錄波動的移動
??
下面我們來定義一些cg相關的全局變量
?CGcontext?cgContext;????????// 用來保存cg腳本
我們需要的第一個變量是CGcontext,這個變量是多個Cg腳本的容器,一般來說,你獲得你可以用函數從這個容器中獲得你想要的腳本
接下來我們定義一個CGprogram變量,它用來保存我們得頂點腳本
?
CGprogram?cgProgram;????????// 我們得頂點腳本
??
接下來我們需要一個變量來設置如何編譯這個頂點腳本?
??
CGprofile?cgVertexProfile;???????// 被頂點腳本使用
下面我們需要一些參數用來把Cg腳本使用的數據從程序中傳送過去。?
??
CGparameter?position, color, modelViewMatrix, wave;?????// 腳本中需要的參數
在初始化階段我們先要創建我們網格數據?
??
?glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);?????
for (int x = 0; x < SIZE; x++)
{
for (int z = 0; z < SIZE; z++)
{
mesh[x][z][0] = (float) (SIZE / 2) - x;
mesh[x][z][1] = 0.0f;
mesh[x][z][2] = (float) (SIZE / 2) - z;
}
}
我們設置多邊形的現實模式為線框圖,接著遍歷沒有頂點,設置其高度。
接下來,我們初始化Cg程序
// 設置Cg?cgContext = cgCreateContext();???????// 創建一個Cg容器
// 測試是否創建成功
if (cgContext == NULL)
{
MessageBox(NULL, "Failed To Create Cg Context", "Error", MB_OK);
return FALSE;
}
我們創建一個Cg程序的容器,并檢查它是否創建成功?
??
cgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);????// 配置在OpenGL中使用頂點緩存
// 檢測Cg程序的是否創建成功
if (cgVertexProfile == CG_PROFILE_UNKNOWN)
{
MessageBox(NULL, "Invalid profile type", "Error", MB_OK);
return FALSE;
}
cgGLSetOptimalOptions(cgVertexProfile); // 啟用配置文件
如果你想使用片斷腳本,使用CG_GL_FRAGMENT變量。如果返回的變量為CG_PROFILE_UNKNOW表示沒有可用的配置文件,則不能編譯你需要的Cg程序。?
??
// 從文件中載入Cg程序?cgProgram = cgCreateProgramFromFile(cgContext, CG_SOURCE, "CG/Wave.cg", cgVertexProfile, "main", 0);
// 檢測是否成功
if (cgProgram == NULL)
{
CGerror Error = cgGetError();
MessageBox(NULL, cgGetErrorString(Error), "Error", MB_OK);
return FALSE;
}
我們嘗試從源文件中創建一個Cg程序,并返回編譯后的結果。??
??
// 載入腳本?cgGLLoadProgram(cgProgram);
??
下面我們把頂點腳本載入到顯存,并準備幫定給GPU。所有的腳本在使用前必須加載。?
?// 把數據變量地址發送給Cg程序?position?= cgGetNamedParameter(cgProgram, "IN.position");?color??= cgGetNamedParameter(cgProgram, "IN.color");?wave??= cgGetNamedParameter(cgProgram, "IN.wave");?modelViewMatrix?= cgGetNamedParameter(cgProgram, "ModelViewProj");
return TRUE;
在初始化的最后,我們必須告訴Cg腳本在那里去獲得輸入的數據,我們需要把變量的指針傳遞過去,下面的函數完成了這個功能。
程序結束時,記得釋放我們創建的內容。
?
cgDestroyContext(cgContext);???????
??
下面的代碼使用空格切換是否使用Cg程序?
??
if (g_keys->keyDown [' '] && !sp)?{??sp=TRUE;??cg_enable=!cg_enable;?}
if (!g_keys->keyDown [' '])??sp=FALSE;
??
現在我們已經完成了所有的準備工作了,到了我們實際繪制網格的地方了,按照慣例我們還是先設置我們得視口。
?gluLookAt(0.0f, 25.0f, -45.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0);
// 把當前Cg程序的模型變化矩陣告訴當前程序?cgGLSetStateMatrixParameter(modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
??
?上面我們要做的事就是把當前Cg程序的模型變化矩陣告訴當前程序。
結下來如果使用cg程序,則把頂點的顏色設置為綠色
?// 如果使用Cg程序?if (cg_enable)?{??// 使用頂點腳本配置文件??cgGLEnableProfile(cgVertexProfile);??????????// 幫定到當前的頂點腳本??cgGLBindProgram(cgProgram);??// 設置繪制顏色??cgGLSetParameter4f(color, 0.5f, 1.0f, 0.5f, 1.0f);?}
??
下面我們來繪制我們的網格。????
?// 開始繪制我們的網格?for (int x = 0; x < SIZE - 1; x++)?{??glBegin(GL_TRIANGLE_STRIP);??for (int z = 0; z < SIZE - 1; z++)??{???// 設置Wave參數???cgGLSetParameter3f(wave, wave_movement, 1.0f, 1.0f);???//設置輸入的頂點???glVertex3f(mesh[x][z][0], mesh[x][z][1], mesh[x][z][2]);?????glVertex3f(mesh[x+1][z][0], mesh[x+1][z][1], mesh[x+1][z][2]);????wave_movement += 0.00001f;????????????if (wave_movement > TWO_PI)?????????????wave_movement = 0.0f;??}??//經過Cg程序處理,進行繪制??glEnd();?}
??
上面的代碼完成具體的繪制操作,對于每一個頂點,我們動態的傳入波動系數和輸入原始的頂點數據。在繪制開始前,頂點腳本接受所有的頂點數據并處理,接著進行光柵華操作。
別忘了在繪制完成后,關閉我們啟用的頂點腳本,否則在繪制其它的模型時會讓你得到不想要的結果。
if (cg_enable)??
?cgGLDisableProfile(cgVertexProfile);?????// 禁用頂點腳本配置文件
原文及其個版本源代碼下載:
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=47
轉載于:https://www.cnblogs.com/arxive/p/6239555.html
總結
以上是生活随笔為你收集整理的NeHe OpenGL教程 第四十七课:CG顶点脚本的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 资金博弈大户为负数什么意思
- 下一篇: 重排和重绘