opengl 教程(5) shader(2) uniform變數

weixin_34391854發表於2012-10-28

      原帖地址:http://ogldev.atspace.co.uk/www/tutorial05/tutorial05.html

 

      在這篇教程中,我們將接觸到一種新的shader變數uniform variables,這種變數和屬性變數的區別:屬性變數是指每個頂點shader呼叫時,都會根據屬性的位置從頂點緩衝中裝入該頂點的相應屬性值,而uniform變數,則對每個draw呼叫保持不變,這意味著你在draw呼叫前裝入該變數,然後draw中每個頂點shader執行時,都能訪問該變數,而且該變數值會保持不變。uniform變數常用來儲存一些draw執行時候的常量資料,比如光照引數、變化矩陣、紋理物件控制程式碼等等。注:uniform變數類似於D3D11中的const buffer中的變數

      在這篇教程中,我們會使渲染的物體在螢幕上運動,實現動畫的效果。主要通過繫結一個uniform變數以及一個idle回撥函式來實現,uniform變數的值在每幀中都會變化。

      GLUT不會重複呼叫我們的渲染函式,只有發生一些特殊事件的時候,才會執行渲染操作,比如視窗最大化、最小化,當前視窗被別的視窗遮擋等等,如果程式執行後,我們不做任何變化,則渲染函式只會執行一次,我們可以通過在渲染函式中增加一個print函式來驗證它,在最大化、最小化視窗時候,該函式會在控制檯視窗會列印相關資訊。如果實現靜態物體的渲染,這種方法當然可以,但是在本教程中,我們要實現動畫,需要重複呼叫渲染函式,該怎麼實現呢?我們可以註冊一個idle回撥函式,把渲染函式放在該函式中,或者直接把渲染函式註冊成idle函式,在GLUT不接受windows系統事件時,idle函式會重複執行,這樣結合idle函式和變化的uniform變數,我們就可以實現動畫的效果。

主要程式碼:

glutIdleFunc(RenderSceneCB);

       通過上面的程式碼,我們把渲染函式註冊成idle函式,需要注意的是在渲染函式的末尾要加上glutPostRedisplay()函式呼叫,否則的話idle函式會反覆執行,但渲染函式卻沒有,glutPostRedisplay()會重繪當前顯示視窗,並保證下一次glut訊息迴圈中,渲染函式會被呼叫。

gScaleLocation = glGetUniformLocation(ShaderProgram, "gScale");
assert(gScaleLocation != 0xFFFFFFFF);

      通過查詢shader程式物件,我們能夠得到uniform變數的位置,該位置和該uniform變數在shader程式碼中的位置一致。通常情況下,我們不能直接訪問和更新uniform變數。在glsl compiler編譯shader程式碼時候,它會給每個uniform變數分配一個索引,在shader內部訪問uniform變數都是通過這個索引來實現的,應用程式則是通過glGetUniformLocation函式來訪問相應的uniform變數,函式的引數為shader程式控制程式碼以及uniform變數名字。函式呼叫成功,則會返回索引值,失敗的話返回-1,對返回值進行錯誤檢測也非常重要,這樣可以保證shader值被正確更新。在兩種情況下,該函式會呼叫失敗,第一種就是變數名字拼寫錯誤,或者就是compiler進行的優化操作,這時也不能得到正確的索引值

static float Scale = 0.0f;
Scale += 0.001f;
glUniform1f(gScaleLocation, sinf(Scale));

      我們定義一個縮放因子變數,每次渲染函式呼叫時候,該變數都增加0.001。該變數的sin值通過函式glUniform1f傳輸到shader中去。使用sin函式值可以保證Scale範圍在[-1,1]之間,注意sinf的引數是以弧度為單位。opengl提供了glUniform{1234}{if}函式的多個版本,分別用來裝入1維、2維、3維、4維向量,i表示變數是整數,f表示變數是浮點,該函式也有向量和矩陣的版本,可以用來設定向量或矩陣型別的uniform變數。該函式的第一個引數是我們用glGetUniformLocation函式得到的uniform變數索引值。

下面我們看下VS中的程式碼變化(注意:FS和上篇教程中一致,沒有變化)。

uniform float gScale;

首先在shader中宣告該uniform型別變數。

gl_Position = vec4(gScale * Position.x, gScale * Position.y, Position.z, 1.0);

我們用uniform變數gScale,改變頂點的x、y值,這樣每幀中x、y座標值都不同,從而實現動畫的效果。

程式執行後效果如下:

image

相關文章