本次實踐是繪制兩個三角形,重點理解頂點數組對象和OpenGL緩存的使用。
頂點數組對象
頂點數組對象負責管理一組頂點屬性,頂點屬性包括位置、法線、紋理坐標等。
OpenGL緩存
OpenGL緩存實質上是OpenGL服務端的一塊內存區域,用於存儲數據。OpenGL的所有數據都是存儲在緩存對象中的。
在本次實踐的思路是創建一個頂點數組對象來管理所繪制的三角性的頂點數據,數據存儲在緩存對象中,然后使用繪制API繪制三角形。
首先,創建頂點數組對象,函數原型:void genVertexArrays(GLsizei n, GLuint *arrays);其中n表示數量,結果保存在arrays中。
然后使用glBindVertexArray綁定數組對象,那為什么需要綁定數組對象了?在使用OpenGL的過程中會生成的非常多的對象,每一種對象都會有許多的操作,如使用glVertexAttribPointer設置頂點數組對象的屬性,在進行這些操作之前需要明確是對哪個對象進行操作,而綁定機制就是做這件事的。OpenGL綁定對象后,接下來的操作就表示作用於這個對象。示例如下:
glGenVertexArrays(NumVAOs,VAOs);
glBindVertexArray(VAOs[Triangles]);
綁定好對象后我們就需要設置這個頂點數組對象所管理的頂點數據,這個時候就需要緩存了。創建和綁定類似頂點數組對象,但最后需要glBufferData來輸入數據,示例如下:
glGenBuffers(NumBuffers,Buffers); glBindBuffer(GL_ARRAY_BUFFER,Buffers[ArrayBuffer]); glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
創建緩存
glGenBuffers(GLsizei n, GLuint* buffers);//創建n個緩存對象,保存在buffers數組中
向緩存中輸入或輸出數據
glBindBuffer(GLenum target, GLuint buffer); //綁定緩存到target指定的緩存結合點
glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); //為綁定到target的緩存對象分配size大小的存儲空間,如果data不為NULL,則使用data初始化所為配的存儲空間。usage指示緩存中的數據可能具備的一些特定的用途。
glBufferSubData(GLenum target, GLsizeiptr offset, GLsizeiptr size, const GLvoid* data);//使用新數據替換緩存中的部分數據
清除數據
glClearBufferData(GLenum target, GLenum internalformat, GLenum format, GLenum type, const GLvoid* data); //使用data填充緩存存儲空間,format和type指定data的數據格式和類型,填充前需要把data轉化為internalformat
glClearSubBufferData(GLenum target, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const GLvoid* data); //同上,區別是這個方法只填充offset和size指定的區域;
接着我們需要設置頂點屬性,使用glVertexAttribPointer.示例如下:
glVertexAttribPointer(vPosition,2,GL_FLOAT,GL_FALSE,0,BUFFER_OFFSET(0));
設置頂點屬性
glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer);
這些都做好了之后,我們就可以使用頂點數組對象來繪制我們的三角形了。
glBindVertexArray(VAOs[Triangles]);
glDrawArrays(GL_TRIANGLES,0,NumVertices);
使用頂點數據之前需要先綁定,表示當前繪制使用該對象。
繪制命令
glDrawArrays(GLenum mode, GLint first, GLsizei count);//直接讀取頂點數據繪制
glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);基於索引繪制(即所有的頂點在一個數組中,使用索引來引用頂點數據)
具體的示例代碼如下:
#include <GL/glew.h> #include <GL/freeglut.h> #include <stdio.h> #include "ShaderHelper.h" #define BUFFER_OFFSET(n) ((GLvoid*)n) enum VAO_IDs { Triangles,NumVAOs}; enum Buffers_IDs { ArrayBuffer, NumBuffers }; enum Attrib_IDs { vPosition=0 }; GLuint VAOs[NumVAOs]; GLuint Buffers[NumBuffers]; const GLuint NumVertices=6; void init(); void display(); int main(int argc,char* argv[]) { glutInit(&argc,argv); glutInitContextVersion(3,3); glutInitContextProfile(GLUT_CORE_PROFILE); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(0,0); glutInitWindowSize(300,300); glutCreateWindow("Frame Buffer"); /* const GLubyte* name = glGetString(GL_VENDOR); //返回負責當前OpenGL實現廠商的名字 const GLubyte* biaoshifu = glGetString(GL_RENDERER); //返回一個渲染器標識符,通常是個硬> 件平台 const GLubyte* OpenGLVersion =glGetString(GL_VERSION); //返回當前OpenGL實現的版本號 const GLubyte* gluVersion= gluGetString(GLU_VERSION); //返回當前GLU工具庫版本 printf("OpenGL實現廠商的名字:%s\n", name); printf("渲染器標識符:%s\n", biaoshifu); printf("OOpenGL實現的版本號:%s\n",OpenGLVersion ); printf("OGLU工具庫版本:%s\n", gluVersion);*/ glewExperimental=GL_TRUE; glewInit(); init(); glutDisplayFunc(display); glutMainLoop(); return 0; } void init() { glClearColor(0.0,0.0,0.0,1.0); glMatrixMode(GL_PROJECTION); glOrtho(-5,5,-5,5,5,15); glMatrixMode(GL_MODELVIEW); gluLookAt(0,0,10,0,0,0,0,1,0); glGenVertexArrays(NumVAOs,VAOs); glBindVertexArray(VAOs[Triangles]); GLfloat vertices[NumVertices][2]={ {-0.90,-0.90}, {0.85, -0.90}, { -0.90, 0.85 }, { 0.90, -0.85 }, { 0.90, 0.90 }, {-0.85, 0.90 }, }; glGenBuffers(NumBuffers,Buffers); glBindBuffer(GL_ARRAY_BUFFER,Buffers[ArrayBuffer]); glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW); ShaderInfo shaders[] = { {GL_VERTEX_SHADER,"triangles.vert"}, {GL_FRAGMENT_SHADER,"triangles.frag"}, {GL_NONE,NULL}, }; GLuint program = LoadShaders(shaders); glUseProgram(program); glVertexAttribPointer(vPosition,2,GL_FLOAT,GL_FALSE,0,BUFFER_OFFSET(0)); glEnableVertexAttribArray(vPosition); } void display() { glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(VAOs[Triangles]); glDrawArrays(GL_TRIANGLES,0,NumVertices); glFlush(); }
注意:代碼根據紅寶書編寫,一些輔助性代碼(如LoadShader)並未貼出,詳情請參照www.opengl-readbook.com。
GLEW說明
GLEW(OpenGL Extension Wrangler) 是OpenGL的另一個輔助庫,主要封裝了從OpenGL庫中獲取函數地址的過程,還包含了一些可以跨平台使用的OpenGL編程方法。
最終的效果如下: