OpenGL從OpenGL 3.0開始將API分紅了兩種類型:即舊式的OpenGL(Legacy OpenGL)和新式的OpenGL(Core Profile),OpenGL3.3 的官方API文檔完整地描述了新式的OpenGL API,舊式的OpenGL API能夠在OpenGL 2.1中查看。html
對於OpenGL渲染的的第一站:也就是把頂點數據(包括頂點位置、頂點法線、頂點顏色、紋理座標等)傳入到OpenGL,舊式的OpenGL中有如下幾種方式實現:數組
此外VBO在Legacy OpenGL中和Core Profile OpenGL中的使用也有着不一樣的方式。服務器
(1) 開啓和關閉VAide
//開啓和關閉客戶端狀態 void glEnableClientState(GLenum cap); void glDisableClientState(GLenum cap); //參數cap取值 GL_VERTEX_ARRAY //頂點位置 GL_COLOR_ARRAY //頂點顏色 GL_EDGE_FLAG_ARRAY //頂點邊界線標識 GL_FOG_COORD_ARRAY //頂點霧座標 GL_INDEX_ARRAY //頂點索引 GL_NORMAL_ARRAY //頂點法線 GL_SECONDARY_COLOR_ARRAY //頂點輔助顏色 GL_TEXTURE_COORD_ARRAY //頂點紋理座標
(2) 設置數據到頂點函數
////////////////////////////////////////////////////////////////////////// //如下是一系列設置頂點數據的API //參數取值(默認形參表明OpenGL中默認值): // size 描述數據的維度(2D\3D) // type 描述每一個數據的類型 // stride 描述每一個頂點數據的跨度 //pointer 指向實際數據 //設置頂點位置數據 void glVertexPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //設置頂點顏色數據 void glColorPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //設置頂點邊界線標識數據 void glEdgeFlagPointer( GLsizei stride=0, const GLvoid *pointer=0); //設置頂點霧座標數據 void glFogCoordPointer( GLenum type=GL_FLOAT, GLsizei stride=0, GLvoid *pointer=0); //設置頂點索引數據 void glIndexPointer( GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //設置頂點法線數據 void glNormalPointer( GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //設置頂點輔助顏色數據 void glSecondaryColorPointer( GLint size=3, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //設置頂點紋理座標數據 void glTexCoordPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0);
(3) VA繪製學習
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //經過設置好的頂點數據進行繪製:可使用下列API進行繪製 void glDrawArrays( GLenum mode, GLint first, GLsizei count); //參數描述 //mode 繪製幾何圖元類型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) //first 頂點數據的開始索引位置(對應(2)中pointer) //count 須要渲染的頂點數據數量 void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); //參數描述 //mode 繪製幾何圖元類型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) //count 第四個參數indices中參與渲染的索引數量 //type 第四個參數indices的數據類型 //indices 須要額外傳入的一個索引數組指針 void glDrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices); //參數描述(與glDrawElements一致但多出兩個參數) //mode 繪製幾何圖元類型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) //count 第四個參數indices中參與渲染的索引數量 //type 第四個參數indices的數據類型 //indices 須要額外傳入的一個索引數組指針 //start 索引數組indices中的最小值索引值 //end 索引數組indices中的最大值索引值
以上就是VA所涉及到的基本API,使用過程以下優化
首先開啓客戶端VertexArray狀態,接着綁定數據到頂點狀態,最後進行繪製:ui
static float vertices[][3] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f }; static float colors[][4] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; //繪製函數 void renderScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); ////////////////////////////////////////////////////////////////////////// //開啓VA狀態 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); //綁定數據 glVertexPointer(3, GL_FLOAT, 0, vertices); glColorPointer(4, GL_FLOAT, 0, colors); //繪製 glDrawArrays(GL_TRIANGLES, 0, 3); //關閉VA狀態 glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); ////////////////////////////////////////////////////////////////////////// }
前文描述了VBO在Legacy 和Core Profile中有兩種不一樣的方式:spa
(1)建立(初始化)VBO對象指針
//建立VBO的API ////////////////////////////////////////////////////////////////////////// void glGenBuffers( GLsizei n, GLuint * buffers); //生成緩衝區ID //參數描述 // n 生成ID數量 // buffers 存儲緩衝區ID的數組 void glBindBuffer( GLenum target, GLuint buffer); //設置緩衝區爲當前操做的緩衝區,而且設置緩衝區的類型 //參數描述 //target 緩衝區類型(包括4種) GL_ARRAY_BUFFER GL_ELEMENT_ARRAY_BUFFER GL_PIXEL_PACK_BUFFER GL_PIXEL_UNPACK_BUFFER //buffer 使用glGenBuffers生成的緩衝區ID void glBufferData( GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage); //爲緩衝區設置數據 //參數描述 //target 緩衝區類型(包括4種) GL_ARRAY_BUFFER GL_ELEMENT_ARRAY_BUFFER GL_PIXEL_PACK_BUFFER GL_PIXEL_UNPACK_BUFFER //size 緩衝區大小(多少字節) //data 實際指向數組的指針 //usage 當前緩衝區的使用模式[一種提示用來優化之用](取值以下9種) GL_STREAM_DRAW GL_STREAM_READ GL_STREAM_COPY GL_STATIC_DRAW GL_STATIC_READ GL_STATIC_COPY GL_DYNAMIC_DRAW GL_DYNAMIC_READ GL_DYNAMIC_COPY
(2)開啓/關閉VBO
當建立完VBO以後,咱們並不知道VBO中存儲的是頂點位置、仍是頂點顏色或者是頂點法線,因而使用下面的API來描述某一個VBO中究竟是頂點什麼方面的數據
////////////////////////////////////////////////////////////////////////// //開啓關閉VBO狀態 void glEnableClientState(GLenum cap); void glDisableClientState(GLenum cap); //參考VA中的描述 void glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer); //參考VA中的描述: //可是pointer參數有所區別: //當使用了glBindBuffer將GL_ARRAY_BUFFER綁定到一個非0的VBO ID上以後,這時候的pointer //表明的是一個VBO ID對象中實際數據(glBufferData中data參數)的偏移值,也就是說這時候pointer //並非一個指針,僅僅是一個偏移值。同時GL_ARRAY_BUFFER_BINDING這個狀態會保存在客戶端 //綜合上面VA中的解釋:能夠知道這個glVertexPointer中的pointer兩種含義: //(1)當glBindBuffer綁定到非0的ID時: //pointer表明偏移,此時客戶端glClientState中會保存GL_ARRAY_BUFFER_BINDING暗示如今在用VBO //(2)當glBindBuffer綁定到0的ID時: //pointer表明一個指向數組的指針,此時客戶端glClientState中不會保存GL_ARRAY_BUFFER_BINDING暗示如今在用VA //同理,對於VA中用到的一系列函數都有一樣的解釋,再也不贅述: glColorPointer glEdgeFlagPointer glFogCoordPointer glIndexPointer glNormalPointer glSecondaryColorPointer glTexCoordPointer
(3)VBO繪製
////////////////////////////////////////////////////////////////////////// //繪製VBO void glDrawArrays( GLenum mode, GLint first, GLsizei count); //參考VA中描述 //所不一樣的是數據如今在緩衝區之中,而不是VA所指向的pointer數組中了 void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); //參考VA中描述 //所不一樣的是indices設置爲NULL //由於緩衝區類型有一種是GL_ELEMENT_ARRAY_BUFFER(查看glGenBuffers中類型描述) //咱們會把indices索引值存儲在GL_ELEMENT_ARRAY_BUFFER類型的Buffer中,不須要額外的數組了 //直接用兩個緩衝區便可
以上即是舊式OpenGL中實現VBO的API,使用過程以下:
首先建立緩衝區並設置緩衝區類型和填滿緩衝區,接着指定緩衝裏面是什麼(到底存的是位置仍是顏色或者是法線),最後繪製
static float vertices[][3] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f }; static float colors[][4] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; void renderScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); ////////////////////////////////////////////////////////////////////////// //建立VBO(通常放在初始化函數中) GLuint vertexBufferID, colorBufferID; glGenBuffers(1, &vertexBufferID); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glGenBuffers(1, &colorBufferID); glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); //開啓VBO模式並設置VBO該怎麼解析 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glVertexPointer(3, GL_FLOAT, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); glColorPointer(4, GL_FLOAT, 0, 0); //繪製 glDrawArrays(GL_TRIANGLES, 0, 3); //繪製完成以後關閉VBO狀態 //將glBindBuffer設置爲0,使得後續glVertexPointer相似函數起到VA的做用 glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); ////////////////////////////////////////////////////////////////////////// }
(1)建立VBO
參考Legacy VBO中內容,兩者是同樣的
(2)開啓/關閉VBO
////////////////////////////////////////////////////////////////////////// void glEnableVertexAttribArray( GLuint index); void glDisableVertexAttribArray( GLuint index); //開啓和關閉一個通用的緩衝區對象 //參數描述 //index 緩衝區對象索引值 void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer ); //設置如何解析緩衝區中的數據 //參數描述 //index 當前操做的緩衝區對象索引值 //size 數據的維度是2D/3D/4D //type 數據類型 GL_INT /GL_FLOAT //normalized 是否已經單位化 //stride 數據間距 //pointer 參考Legacy VBO中解釋(在glBindBuffer未開啓時是指針開啓後是索引值)
(3)繪製
參考Legacy VBO中內容,兩者是同樣的
以上即是Core Profile 下的VBO,使用方式以下:
首先建立VBO對象,接着開啓VBO而且用來講明VBO中數據是什麼樣組織的(可是並無說明數據是頂點位置、頂點顏色仍是法線),這一點與 Legacy VBO不一樣,由於它的說明部分(哪一個VBO存儲着位置、哪一個VBO存儲着顏色、哪一個VBO存儲着法線等)是在着色語言Shader中指明的,最後仍是使用 一樣的API繪製:
////////////////////////////////////////////////////////////////////////// GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f }; GLfloat vColors [] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; ////////////////////////////////////////////////////////////////////////// void RenderWidget::paintGL() { ////////////////////////////////////////////////////////////////////////// //生成VBO glGenBuffers(1, &_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vVerts), vVerts, GL_STATIC_DRAW); glGenBuffers(1, &_colorBuffer); glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vColors), vColors, GL_STATIC_DRAW); setShaders(); //開啓VBO並設置VBO裏面存儲的數據模式 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); glVertexAttribPointer( 1, 4, GL_FLOAT, GL_FALSE, 0, (void*)0 ); //繪製VBO glDrawArrays(GL_TRIANGLES, 0, 3); //關閉VBO glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); }
Shader部分:
頂點Shader
#version 330 layout(location = 0) in vec4 vertex; layout(location = 1) in vec4 color; out vec4 inFragColor; void main( void ) { gl_Position = vertex; inFragColor = color; }
片元Shader
#version 330 in vec4 inFragColor; out vec4 outFragColor; void main( void ) { outFragColor = inFragColor; }
經過頂點Shader能夠知道索引值爲0的VBO解釋爲頂點位置,它傳給gl_Position,索引值爲1的VBO解釋爲頂點的顏色
VAO的介紹能夠參考 <<AB是一家?VAO與VBO>>
(1)初始化
////////////////////////////////////////////////////////////////////////// //初始化VAO void glGenVertexArrays(GLsizei n, GLuint *arrays); //建立VAO ID //參數描述 //n 產生VAO ID的數量 //arrays 保存VAO ID的數組 void glBindVertexArray(GLuint array); //設置當前操做的VAO對象 //參數描述 //array VAO的ID
(2)開啓/關閉VAO
VAO的開啓當使用glBindVertexArray時自動開啓,使用glBindVertexArray(0),傳入一個0值能夠視爲將VAO關閉
設置VAO的過程就是調用VBO中(2)的過程
(3) 繪製
同VBO中繪製(繪製以前先啓用VAO)
以上就是VAO涉及到的API,使用過程以下:
首先建立VAO,接着設置VAO(在調用VBO的數據設置過程當中VAO自動完成了設置),最後開啓VAO並繪製:
////////////////////////////////////////////////////////////////////////// GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f }; GLfloat vColors [] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; ////////////////////////////////////////////////////////////////////////// void RenderWidget::paintGL() { ////////////////////////////////////////////////////////////////////////// //生成VBO glGenBuffers(1, &_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vVerts), vVerts, GL_STATIC_DRAW); glGenBuffers(1, &_colorBuffer); glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vColors), vColors, GL_STATIC_DRAW); setShaders(); //初始化VAO GLuint vaoBuffer; glGenVertexArrays(1, &vaoBuffer); glBindVertexArray(vaoBuffer); //經過設置VBO裏面存儲的數據模式完成VAO設置 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); glVertexAttribPointer( 1, 4, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); ////////////////////////////////////////////////////////////////////////// //上述全部的代碼在初始化函數中調用 //只有繪製代碼在渲染函數中調用 //使用VAO繪製 glBindVertexArray(vaoBuffer); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); }