OpenGL中的VBO与VAO的使用

此代码来自《OpenGL编程指南》,最近所写程序中需要使用到VBO与VAO,故将其在自己的机器上跑起来,并对此做了注释,方便日后查看


vbo.cpp

#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>

#pragma comment( lib, "glew32.lib") 

// 使用此宏来简化偏移量的表达形式
#define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes))
#define VERTICES 0
#define INDICES 1
#define NUM_BUFFERS 2
GLuint buffers[NUM_BUFFERS];

GLfloat vertices[][3] = {
	{-1.0f,-1.0f,-1.0f},
	{1.0f,-1.0f,-1.0f},
	{1.0f,1.0f,-1.0f},
	{-1.0f,1.0f,-1.0f},
	{-1.0f,-1.0f,1.0f},
	{1.0f,-1.0f,1.0f},
	{1.0f,1.0f,1.0f},
	{-1.0f,1.0f,1.0f}
};
GLubyte indices[][4] = {
	{0,1,2,3},
	{4,7,6,5},
	{0,4,5,1},
	{3,2,6,7},
	{0,3,7,4},
	{1,5,6,2}
};

GLfloat* bdata;

void changeSize(int w, int h)
{
	glViewport(0,0,(GLsizei)w,(GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0,(double)w/(double)h,0.01,30);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void keyDown(unsigned char key, int x, int y)
{
	switch (key)
	{
	case 'b':
		// 返回一个缓冲区对象的指针(指向与GL_ARRAY_BUFFER相关联的当前绑定缓冲区对象的数据存储),可以在这个缓冲区对象中写入新值,就像对数组赋值一样
		// GL_READ_WRITE 表示可以对数据进行读写操作
		bdata = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
		for (int i = 0; i < 24; i++)
		{
			*(bdata + i) *=1.1f;
		}
		glUnmapBuffer(GL_ARRAY_BUFFER);
		glutPostRedisplay();
		break;
	case 's':
		bdata = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
		for (int i = 0; i < 24; i++)
		{
			*(bdata + i) *= 0.9f;
		}
		glUnmapBuffer(GL_ARRAY_BUFFER);
		glutPostRedisplay();
		break;
	}
}

void mouse(int button, int state, int x, int y)
{

}

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glTranslatef(0.0f, 0.0f, -5.0f);
	glRotatef(45.0f, 1.0f, 1.0f, 0.0f);

	// GL_QUADS 创建图元的类型
	// 24 使用24个元素定义一个几何图元序列
	// GL_UNSIGNED_BYTE 数组数据类型
	// BUFFER_OFFSET(0) 偏移量
	glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));

	glutSwapBuffers();
}

void init(void)
{
	glClearColor(0.0f,0.0f,0.0f,0.0f);
	glShadeModel(GL_FLAT);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glewInit();
	// 创建2个缓冲区对象
	glGenBuffers(NUM_BUFFERS, buffers);
	glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTICES]);
	// GL_ARRAY_BUFFER 表示顶点数据
	// sizeof(vertices) 表示存储相关数据所需要的内存数量
	// vertices 指向数据所存储的内存的指针,用于初始化缓冲区对象
	// GL_DYNAMIC_DRAW 提示数据在分配之后将如何进行读取和写入
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
	// 指定了需要访问的空间坐标数据
	// 3 表示每个顶点的坐标数量
	// GL_FLOAT 指定数组中每个坐标的数据类型
	// 0 跨距
	// BUFFER_OFFSET(0) 是数组包含的第一个顶点的第一个坐标的内存地址
	glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
	// 启用数组
	glEnableClientState(GL_VERTEX_ARRAY);

	// GL_ELEMENT_ARRAY_BUFFER(表示索引数据),用索引数据初始化缓冲区对象
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[INDICES]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
}

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GL_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(600, 600);
	glutCreateWindow("VBO");
	glutReshapeFunc(changeSize);
	glutMouseFunc(mouse);
	glutKeyboardFunc(keyDown);
	glutDisplayFunc(display);
	init();
	glutMainLoop();
	return 0;
}

以下运行结果分别为未缩放,放大,缩小之后的截图




vao.cpp

#include <windows.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include <math.h>
#include <iostream>

#include <stdio.h>

#pragma comment (lib, "glew32.lib")

using namespace std;

#define M_PI 3.1415926f

// 使用此宏来简化偏移量的表达形式
#define BUFFER_OFFSET(offset)  ((GLvoid*)offset)
#define NumberOf(array)        (sizeof(array)/sizeof(array[0])) //求数组大小

typedef struct {
	GLfloat x, y, z;
} vec3;


typedef struct {
	vec3     xlate;   //glTranslatef参数
	GLfloat  angle;
	vec3     axis;	  //glRotatef参数
} xform;

enum { Cube, Cone, NumVAOs };   //{0, 1, 2}
GLuint   VAO[NumVAOs];          //顶点数组对象
GLenum   primType[NumVAOs];     //图元类型
GLsizei  numElements[NumVAOs];	//索引数据
xform    xForm[NumVAOs] = {
	{ { -3.0, 0.0, 0.0 }, 45.0, { 1.0, 1.0, 1.0 } },
	{ {  0.0, 0.0, 3.0 }, 0.0, { 1.0, 1.0, 1.0 } }
};
GLfloat  Angle = 0.0;

void init()
{
	//初始化glew
	GLenum err = glewInit();
	if (GLEW_OK != err)
	{
		fprintf(stderr, "GLEW初始化失败!\n");
		exit(EXIT_FAILURE);
	}
	enum { vertices, colors, elements, NumVBOs };   //{0, 1, 2, 3}
	//缓冲区对象,包含顶点坐标,顶点颜色,顶点索引
	GLuint  buffers[NumVBOs];
	//生成顶点数组对象,本代码中只画了两个图形
	glGenVertexArrays(NumVAOs, VAO);

	{
		//顶点坐标
		GLfloat  cubeVerts[][3] = {
			{ -1.0, -1.0, -1.0 },
			{ -1.0, -1.0,  1.0 },
			{ -1.0,  1.0, -1.0 },
			{ -1.0,  1.0,  1.0 },
			{  1.0, -1.0, -1.0 },
			{  1.0, -1.0,  1.0 },
			{  1.0,  1.0, -1.0 },
			{  1.0,  1.0,  1.0 }
		};
		//顶点颜色
		GLfloat  cubeColors[][3] = {
			{  0.0,  0.0,  0.0 },
			{  0.0,  0.0,  1.0 },
			{  0.0,  1.0,  0.0 },
			{  0.0,  1.0,  1.0 },
			{  1.0,  0.0,  0.0 },
			{  1.0,  0.0,  1.0 },
			{  1.0,  1.0,  0.0 },
			{  1.0,  1.0,  1.0 }
		};
		//顶点索引
		GLubyte  cubeIndices[] = {
			0, 1, 3, 2,
			4, 6, 7, 5,
			2, 3, 7, 6,
			0, 4, 5, 1,
			0, 2, 6, 4,
			1, 5, 7, 3
		};

		//绑定激活第一个顶点数组对象
		glBindVertexArray(VAO[Cube]);
		//修改缓冲对象里的数据
		glGenBuffers(NumVBOs, buffers);
		glBindBuffer(GL_ARRAY_BUFFER, buffers[vertices]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVerts), cubeVerts, GL_STATIC_DRAW);
		glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
		glEnableClientState(GL_VERTEX_ARRAY);

		glBindBuffer(GL_ARRAY_BUFFER, buffers[colors]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(cubeColors), cubeColors, GL_STATIC_DRAW);
		glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
		glEnableClientState(GL_COLOR_ARRAY);

		// GL_ELEMENT_ARRAY_BUFFER(表示索引数据),用索引数据初始化缓冲区对象
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[elements]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);

		primType[Cube] = GL_QUADS;      //图元类型,4个点画一个矩形
		numElements[Cube] = NumberOf(cubeIndices);
	}

	{
		int i, index;
		float  dTheta;

#define NumConePoints  36   //圆锥底面有36个点

		//增加一个顶点作为圆锥的尖端顶点(作为第一个顶点)
		GLfloat  coneVerts[NumConePoints+1][3] = {
			{0.0, 0.0, 10.0}     //相当于给数组赋了第一个顶点
		};
		GLfloat  coneColors[NumConePoints+1][3] = {
			{1.0, 1.0, 1.0}     //第一个顶点的颜色
		};
		GLubyte  coneIndices[NumConePoints+1];  //默认初始化0,即索引到第一个顶点

		dTheta = 2*M_PI / (NumConePoints - 1);  //所要绘制的三角形的夹角
		index = 1;
		for (i = 0; i < NumConePoints; ++i, ++index)
		{
			//这里的顶点坐标很好分析,画一个顶点在坐标原点的圆,36个顶点分别在圆上
			float theta = i*dTheta;
			coneVerts[index][0] = cos(theta);
			coneVerts[index][1] = sin(theta);
			coneVerts[index][2] = 0.0;

			coneColors[index][0] = cos(theta);
			coneColors[index][1] = sin(theta);
			coneColors[index][2] = 0.0;

			coneIndices[index] = index;

			cout << "( " << coneVerts[index][0] << ", " << coneVerts[index][1] << ")" << endl;
		}
		//激活绑定第二个顶点数组对象
		glBindVertexArray(VAO[Cone]);
		glGenBuffers(NumVBOs, buffers);
		glBindBuffer(GL_ARRAY_BUFFER, buffers[vertices]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(coneVerts), coneVerts, GL_STATIC_DRAW);
		glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
		glEnableClientState(GL_VERTEX_ARRAY);

		glBindBuffer(GL_ARRAY_BUFFER, buffers[colors]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(coneColors), coneColors, GL_STATIC_DRAW);
		glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
		glEnableClientState(GL_COLOR_ARRAY);

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[elements]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(coneIndices), coneIndices, GL_STATIC_DRAW);

		primType[Cone] = GL_TRIANGLE_FAN;       //以圆锥顶点为公共顶点画三角形
		numElements[Cone] = NumberOf(coneIndices);
	}

	glEnable(GL_DEPTH_TEST);
}

void display()
{
	int  i;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0, 0.0, 0.0);
	glPushMatrix();
	glRotatef(Angle, 0.0, 1.0, 0.0);    //初始旋转角度以及旋转轴
	gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);    //设置相机

	for (i = 0; i < NumVAOs; ++i) {
		glPushMatrix();
		glTranslatef(xForm[i].xlate.x, xForm[i].xlate.y, xForm[i].xlate.z);
		glRotatef(xForm[i].angle, xForm[i].axis.x, xForm[i].axis.y, xForm[i].axis.z);
		glBindVertexArray(VAO[i]);  //对相应的数组对象解引用
		glDrawElements(primType[i], numElements[i], GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
		glPopMatrix();
	}

	glPopMatrix();
	glutSwapBuffers();
}

void reshape(GLsizei w, GLsizei h)
{
	if(h == 0)
		h = 1;

	glViewport(0, 0, w, h);

	GLfloat fAspect = (GLfloat)w / (GLfloat)h;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();//将当前的用户坐标系的原点移动到了屏幕中心,类似一个复位操作

	gluPerspective(45.0f, fAspect, 1.0f, 100.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

}

int main(int args, char* argv[])
{
	glutInit(&args, argv);
	glutInitWindowPosition(200, 200);
	glutInitWindowSize(600, 600);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	//glewInit();//此初始化函数在init()函数中进行了调用
	glutCreateWindow("VAO");
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	init();
	glutMainLoop();

	return 0;
}



以下为程序的运行结果:



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值