從OpenGL 進入 3.0 版之後,很多舊有的 Function 開始標記成 Deprecated。從 3.1版開始把 Fixed-Function Pipeline 的相關 OpenGL Function 通通移至 Compatible Profile , Core Profile 只留下 Programmable pipeline 相關的 Function 。在 OpenGL Shading Language (GLSL) 的部分,則隨著新功能的增加而改版 。此外,最近 Khronos Group 發表了OpenGL 3.3 與 OpenGL 4.0,相對於 3.2 版增加新功能,並沒有移除更多的 Function 。以下是 OpenGL 版本與 GLSL 版本發表時間的對應。
OpenGL Version | OpenGL Shading Language Version |
OpenGL 4.0 | GLSL 4.0 |
OpenGL 3.3 | GLGL 3.3 |
OpenGL 3.2 | GLSL 1.5 |
OpenGL 3.1 | GLSL 1.4 |
OpenGL 3.0 | GLSL 1.3 |
OpenGL 2.1 | GLSL 1.2 |
OpenGL 2.0 | GLSL 1.1 |
所 以OpenGL 3.x 之後的 Core Profile 與 OpenGL ES 2.0 (未來的WebGL) 都只剩下 Programmable Rendering Pipeline。因此,不管要畫什麼,既使只是一個簡單的三角形,都需要撰寫 Vertex Shader 與 Fragment Shader 才行。
而在 OpenGL 3.x 的資料結構上,也變成以 Buffer Object 為主。所以幾乎所有資料,都需要放到各種的 Buffer Object來使用,下面兩張圖是由 OpenGL 管理單位 Khronos Group 簡報 OpenGL 3 跟 OpenGL 4 的 Buffer Object Model 架構。
Khronos Group 在09年 GDC 簡報的OpenGL 3 資料 |
Khronos Group 在 2010年 GDC 簡報的OpenGL 4 資料 |
參考資料來 源網站: http://www.khronos.org/
現在第一個範例:畫出個三角形,我們以第 0 章的程式為基礎,若要畫出一個三角形,只要添加下面流程 2、 3、 4 部分的程式碼:
- Initial OpenGL Canvas
- Load 繪圖所需的資料 / 建立儲存資料的資料結構
- Initial OpenGL state 與 各種 OpenGL buffer objects
- Draw and Display
- 接 受各種事件,根據事件變更資料結構的內容、OpenGL State 或是 OpenGL buffer objects
- 反覆流程 4 與流程 5 直至程式結束
首先是流程 2,在這個例子裡只要準備三角形的資料、Vertex Shdaer 程式碼與 Fragment Shader 程式碼,因為都直接寫死放在程式的變數內,所以只需要有變數的宣告就可以把Init () 省略。
首先三角形的資料很簡單,使用一個 Array 儲存三角形頂點資料即可。
GLfloat afVertex[][3]= { {-0.75,-0.5,0.0}, {0.75,-0.5,0.0}, {0.0,0.75,0.0} }; |
三個三角形頂點資料 |
而 Vertex Shader 與 Fragment Shader,也簡單使用 char pointer 來存。
Vertex Shader 程式碼 |
const char* cpVShader = { "#version 150 " "" "in vec3 vPos;" "" "void main() {" " gl_Position = vec4(vPos,1);" "}" }; |
"in vec3 vPos;" 表示 Vertex Shader 會接受 三個 float 的 Vertex Attribute 「Vpos」變數輸入。
然後 Vertex Shader 的預設 Vertex 輸出為內建的變數 gl_Position,Type 為 4個 float 的 Vector 。
因為只有要畫單純的三角形,並沒有要對三角形多做處理,所以在Vertex Shader 裡面 直接把輸入的 vPos 變成 homogenious coordinate 也就是後面再加個 1,放到 gl_Position 裡 。
Fragment Shader 程式碼 |
const char* cpFShader = { "#version 150 " "" "out vec4 fColor;" "" "void main() {" " fColor = vec4( 1, 1, 1, 1 );" "}" }; |
"out vec4 fColor;" 宣告輸出的 Fragment 變數名稱。
然後設定三角形上面的每個 Fragment 用 ( 1, 1, 1, 1) 的白色輸出。
接下來資料都準備好了,開始進行流程 3 撰寫 initGL 的內容。
void initGL() { |
|
glGenBuffers(1,&uVbo ); glBindBuffer(GL_ARRAY_BUFFER,uVbo); glBufferData(GL_ARRAY_BUFFER,sizeof(afVertex), afVertex, GL_STATIC_DRAW ); |
產生一個 Vertex Buffer Object ,並且把GL_ARRAY_BUFFER 設定為 uVbo ,然後將Array的頂點資料存到這個 GL_ARRAY_BUFFER 設定的 uVbo 這個buffer object裡。 |
uProgram = glCreateProgram(); AttachProgram( uProgram, cpVShader , GL_VERTEX_SHADER ); AttachProgram( uProgram, cpFShader , GL_FRAGMENT_SHADER ); glLinkProgram( uProgram ); |
產生一個 Shader Program,然後分別把Vertex Shader、Fragment Shader attach 至program上,最後 Link 起來可以在 Draw時使用這個 Shader Program。 |
uPos = glGetAttribLocation( uProgram, "vPos" ); | 取得 Shader Program 裡面 vPos 這個變數的位置。 |
glClearColor( 0.0, 0.0, 1.0, 1.0 ); | 設 定OpenGL Canvus 背景顏色。 |
} |
這邊 InitGL() 主要作了四件事,分別是產生一個 Vertex Buffer Object ,一個 Shader Program ,取得 Shader Program 裡面 vPos 變數的輸入位置。
最後就是顯示的部分 Display 這個 Function:
glUseProgram(uProgram); | 設定現在使用的 Shader Program為 uProgram |
glBindBuffer( GL_ARRAY_BUFFER, uVbo ); | 設定現在使用的 GL_ARRAY_BUFFER 為uVbo |
glVertexAttribPointer( uPos, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); | 設定 GL_ARRAY_BUFFER 裡面 Vertex 資料的格式,並且設定資料是當作 Shader Program 內 uPos 位置的變數內容 |
glEnableVertexAttribArray( uPos ); | Enable uPos 這個 Vertex attribute array |
glDrawArrays( GL_TRIANGLES, 0, 3 ); | 最後在 Vertex Array 裡從第 0 個開始取三個 Vertex 當成三角形來畫 |
這樣就可以畫出一個白色的三角形了。
一些概念
OpenGL 的運作是一個 State Machine,所以程式執行是根據 OpenGL 內部各種 State 的狀況,因此常見的模式就是設定某些 State 狀態,呼叫 Function 針對現在的 State 執行,透過如此的反覆進行完成一個 OpenGL程式。
以下是這個範例的原始檔: Lession 1.zip
您好我想在linux環境下編譯opengl 3.0以上的版本也就是用到glsl,請問我要怎麼建制我的環境需要哪些lib,compile command要用什麼,希望大大不吝指教謝謝
我這邊的linux使用的都是配有nvidia顯示卡的主機,所以就是安裝nvidia的driver,然後安裝glew這套library,使用其header file.link時的library就照常使用-lGL -lGLU 以及如果是用glut就加上-lglut. 這邊使用到的GL library 就是安裝nvidia driver時提供的library.
請問一下使用shader真的可以幫opengl加速繪製嗎?
譬如我一條現有200頂點
我總共有1萬條線
我該如何利用opengl渲染來加速?
shader是為了能夠更彈性的繪製圖形,至於要使用OpenGL加速,只要使用OpenGL的API寫程式繪圖,然後搭配上支援OpenGL的顯示卡與正確的驅動程式即可.