多个glBindBuffer和glDrawXXX 需要glBindVertexArray VAO指定

一个VAO有多个VBO,它们之间也是通过上下文,只有唯一的激活VAO,在VAO后创建的VBO都属于该VAO。
关联VBO数据用 取得当前激活的缓存区对象偏移 来指定。

VAO是一个对象,其中包含一个或者更多的Vertex Buffer Objects。而VBO是Graphics Card中的一个内存缓冲区,用来保存顶点信息,颜色信息,法线信息,纹理坐标信息和索引信息等等。 VAO在Graphics Card线性的存储几个对象信息,替代了以前发送我们需要的数据到Graphics Card上,这也是Direct3D没有立即模式情况下工作的方法, 这就意味着应用程序不需要传输数据到Graphics Card上而得到较高的性能。


一、VAO和VBO创建关联步骤:

 1. Generate Vertex Array Object
 2. Bind Vertex Array Object
 
3. Generate Vertex Buffer Object
4. Bind Vertex Buffer Object
glGenVertexArrays(1, &vaoID[0]); // Create our Vertex Array Object  
glBindVertexArray(vaoID[0]); // Bind our Vertex Array Object so we can use it  
  
glGenBuffers(1, vboID); // Generate our Vertex Buffer Object  
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // Bind our Vertex Buffer Object  
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW  
  
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // Set up our vertex attributes pointer  
  
glEnableVertexAttribArray(0); // Disable our Vertex Array Object  
glBindVertexArray(0); // Disable our Vertex Buffer Object  

delete [] vertices; // Delete our vertices from memory


二、绘制步骤:

1. glBindVertexArray
2.glDrawXXX
glBindVertexArray(vaoID[0]); // Bind our Vertex Array Object  
glDrawArrays(GL_TRIANGLES, 0, 6); // Draw our square  

三、删除:

1.取消绑定
2.删除VBO对象
3.删除VAO对象
glBindVertexArray(0); // Unbind our Vertex Array Object
glDeleteVertexArrays(n, buffers); // 引用的VBO会变成未绑定的,但不会删除VBO数据块
glDeleteBuffers(n, buffers); // 删除VBO缓存区数据块


参考:
http://www.cppblog.com/init/archive/2012/02/21/166098.html
https://www.opengl.org/sdk/docs/man/html/glGenVertexArrays.xhtml
https://www.opengl.org/sdk/docs/man/html/glBindVertexArray.xhtml

#include <stdlib.h>
#include <stdio.h>
#define GLEW_STATIC
#include <GL/glew.h>
//#define FREEGLUT_STATIC
#include <GL/freeglut.h>
#define M_PI 3.1415926

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

#define BUFFER_OFFSET(offset) ((const GLubyte *) NULL + offset)  
#define NumberOf(array) (sizeof(array)/sizeof(array[0]))  
typedef struct {
	GLfloat x, y, z;
} vec3;
typedef struct {
	vec3 xlate; /* Translation */
	GLfloat angle;
	vec3 axis;
} XForm;
enum { Cube, Cone, NumVAOs };
GLuint VAO[NumVAOs];
GLenum PrimType[NumVAOs];
GLsizei NumElements[NumVAOs];
XForm Xform[NumVAOs] = {
	{ { -2.0, 0.0, 0.0 }, 0.0,{ 0.0, 1.0, 0.0 } },
	{ { 0.0, 0.0, 2.0 }, 0.0,{ 1.0, 0.0, 0.0 } }
};
GLfloat Angle = 0.0;
void
init()
{
	enum { Vertices, Colors, Elements, NumVBOs };
	GLuint buffers[NumVBOs];
	// VAO是一个对象,其中包含一个或者更多的Vertex Buffer Objects。而VBO是Graphics Card中的一个内存缓冲区,用来保存顶点信息,颜色信息,法线信息,纹理坐标信息和索引信息等等。
	//  VAO在Graphics Card线性的存储几个对象信息,替代了以前发送我们需要的数据到Graphics Card上,这也是Direct3D没有立即模式情况下工作的方法,
	// 这就意味着应用程序不需要传输数据到Graphics Card上而得到较高的性能。
	// 在缓存区中生成顶点数组对象名字,该名字标记可能不是连续的,但是一定是没有使用的,用顶点数组集合的默认状态来初始化。
	// generate vertex array object names
	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,一旦VAO绑定后,使glGenBuffers 创建一个Vertex Buffer Object, 当然仍然需要使用glBindBuffer绑定VBO;
		// 使用glBufferData来初始化和用刚VAO创建的数据分配数据给VBO,再告诉VBO的数据是从VAO而来,需要清理Vertex Attributr Array和Vertex Array Object
		// bind a vertex array object,
		// array is the name of a vertex array object previously returned from a call to glGenVertexArrays, 
		// or zero to break the existing vertex array object binding.
		//  If the bind is successful no change is made to the state of the vertex array object, and any previous vertex array object binding is broken.
		glBindVertexArray(VAO[Cube]);
		
		glGenBuffers(NumVBOs, buffers);
		// When a buffer object is bound to a target, the previous binding for that target is automatically broken.
		glBindBuffer(GL_ARRAY_BUFFER, buffers[Vertices]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVerts),
			cubeVerts, GL_STATIC_DRAW);
		// 要清楚关联a buffer object和 a vertex attribute并不发生在glBindBuffer(GL_ARRAY_BUFFER),而是发生在glVertexAttribPointer();当你调用glVertexAttribPointer() ,OpenGL 获取缓冲区绑定到GL_ARRAY_BUFFER 并且关联顶点属性,想象一下GL_ARRAY_BUFFER就像一个全局指针。
		glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
		glEnableClientState(GL_VERTEX_ARRAY);
		
		// 前面的GL_ARRAY_BUFFER绑定失效,GL_ARRAY_BUFFER就像一个全局指针
		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);
		
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
			buffers[Elements]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER,
			sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);
		PrimType[Cube] = GL_QUADS;
		NumElements[Cube] = NumberOf(cubeIndices);
	}

	{
		int i, idx;
		float dTheta;
#define NumConePoints 36  
		/* We add one more vertex for the cone's apex */
		GLfloat coneVerts[NumConePoints + 1][3] = {
			{ 0.0, 0.0, 1.0 }
		};
		GLfloat coneColors[NumConePoints + 1][3] = {
			{ 1.0, 1.0, 1.0 }
		};
		GLubyte coneIndices[NumConePoints + 1];
		dTheta = 2 * M_PI / (NumConePoints - 1);
		idx = 1;
		for (i = 0; i < NumConePoints; ++i, ++idx) {
			float theta = i*dTheta;
			coneVerts[idx][0] = cos(theta);
			coneVerts[idx][1] = sin(theta);
			coneVerts[idx][2] = 0.0;
			coneColors[idx][0] = cos(theta);
			coneColors[idx][1] = sin(theta);
			coneColors[idx][2] = 0.0;
			coneIndices[idx] = idx;
		}
		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 mouse(int button, int state, int x, int y) {
	switch (button)
	{
	case GLUT_LEFT_BUTTON:
		if (state == GLUT_DOWN) {
			glutIdleFunc(NULL);
		}
		break;
	case GLUT_RIGHT_BUTTON:
		if (state == GLUT_DOWN) {
			glutIdleFunc(NULL);
		}
		break;
	default:
		break;
	}
}

void display()
{
	int i;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPushMatrix();
	glRotatef(Angle, 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时候,就需要用glBindVertexArray绑定VAO对象,告知绘图函数调用那个顶点数组的索引缓存和顶点缓存
		glDrawElements(PrimType[i], NumElements[i],
			GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
		glPopMatrix();
	}
	glPopMatrix();
	glutSwapBuffers();
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(250, 250);

	glutInitWindowPosition(100, 100);
	glutInitContextVersion(3, 1);

	glutCreateWindow("hello");
	glewInit();
	init();
	glutDisplayFunc(display);
	//glutReshapeFunc(reshape);
	glutMouseFunc(mouse);
	//glutMotionFunc(move);
	//glutKeyboardFunc(keyboardfunc);
	glutMainLoop();

	return 0;
}


   

你可能感兴趣的:(多个glBindBuffer和glDrawXXX 需要glBindVertexArray VAO指定)