本次实践是绘制两个三角形,重点理解顶点数组对象和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编程方法。
最终的效果如下: