[OpenGL]OpenGL中VAO、VBO、EBO概念及應用

1.VBO(頂點緩衝對象 Vertex Buffer Objects ,VBO)

VBO:頂點緩衝對象,是在顯卡存儲空間中開闢出的一塊內存緩存區,用於存儲頂點的各類屬性信息,如頂點座標,頂點向量,頂點顏色數據等。在渲染時,可以直接從VBO取出頂點的各類屬性數據,由於VBO在顯存而不是在內存中,不需要從CPU傳輸數據,處理效率更高。

可以開闢很多個VBO,每個VBO在OpenGL中有它的唯一標識ID,這個ID對應這具體的VBO的顯存地址,通過這個ID可以對特定的VBO內的數據進行存取操作

(1)創建VBO 開闢顯存空間並分配VBO的ID

GLuint vboid;
glGenBuffers(1, &vboid);

原型: void glGenBuffers(GLsizei n​, GLuint * buffers​);
n:指定要生成的緩衝區對象名稱的數量
buffers:指定存儲生成的緩衝區對象名稱的數組

(2)創建的VBO可用來保存不同類型的頂點數據,創建之後需要通過分配的ID綁定製定的VBO,對於同一類型的頂點數據一次只能綁定一個VBO。綁定操作通過glBindBuffer來實現;

glBindBuffer(GL_ARRAY_BUFFER, vboId);

原型: void glBindBuffer(GLenum target​, GLuint buffer​);
target:表示目標緩衝類型
buffer:緩衝對象名字

target分類:

    GL_ARRAY_BUFFER,  
    GL_ATOMIC_COUNTER_BUFFER, 
    GL_COPY_READ_BUFFER,  
    GL_COPY_WRITE_BUFFER, 
    GL_DRAW_INDIRECT_BUFFER, 
    GL_DISPATCH_INDIRECT_BUFFER,  
    GL_ELEMENT_ARRAY_BUFFER,  
    GL_PIXEL_PACK_BUFFER,  
    GL_PIXEL_UNPACK_BUFFER,  
    GL_QUERY_BUFFER,  
    GL_SHADER_STORAGE_BUFFER,  
    GL_TEXTURE_BUFFER,  
    GL_TRANSFORM_FEEDBACK_BUFFER, 
    GL_UNIFORM_BUFFER

注:以上類型,根據不同的OpenGL版本使用,我們今天用的是GL_ARRAY_BUFFER,用於頂點數組綁定,其他類型具體什麼用法,在這不做多解釋,想要更多瞭解的同學請移步OpenGL WIKI文檔,會有更詳細的解釋https://www.khronos.org/opengl/wiki/Main_Page

(3)調用glBufferData把用戶的數據傳輸到當前綁定的顯存緩衝區

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

原型:void glBufferData(GLenum target​, GLsizeiptr size​, const GLvoid * data​, GLenum usage​);
targe:VBO類型同上
size:VBO的大小
data:制定需要傳遞的數據,可以爲空
usage:制定VBO的存儲方式

usage類型主要是:

    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

STREAM:數據存儲內容將修改一次,最多使用幾次;
STATIC:數據存儲內容將被修改一次並多次使用;
DYNAMIC:數據存儲內容將被反覆修改和多次使用;
DRAW:應用程序修改數據存儲內容,並將其用作GL繪圖和圖像規範命令的源;
READ:通過從GL讀取數據來修改數據存儲內容,並在應用程序查詢時返回該數據;
COPY:通過從GL中讀取數據來修改數據存儲內容,並將其用作GL繪圖和圖像規範命令的源;

在這我們使用GL_STATIC_DRAW,其他的用法,可參考OpenGL WIKI文檔

(4)調用glVertexAttribPointer 告訴OpenGL怎麼解釋這些頂點數據

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

原型:

void glVertexAttribPointer(GLuint index​, GLint size​, GLenum type​, GLboolean normalized​, GLsizei stride​, const GLvoid * pointer​);
 void glVertexAttribIPointer(GLuint index​, GLint size​, GLenum type​, GLsizei stride​, const GLvoid * pointer​);
 void glVertexAttribLPointer(GLuint index​, GLint size​, GLenum type​, GLsizei stride​, const GLvoid * pointer​);

index:指定頂點屬性位置,與頂點着色器中layout(location = 0)對應
size:頂點屬性大小
type:參數指定數據類型
stride:步長,指定在連續的頂點屬性之間的間隔
pointer:我們的位置數據在緩衝區起始位置的偏移量

2.VAO(頂點數組對象 Vertex Array Object ,VAO)

VAO:保存了所有頂點數據屬性的狀態結合,它存儲了頂點數據的格式以及頂點數據所要的VBO的引用

(1)VAO的創建和配置

GLuint vaoId;
glGenVertexArrays(1, &vaoId);
glBindVertexArray(vaoId);

執行VAO綁定之後,後面你的所有VBO配置都是這個VAO對象的一部分,可以說VBO是對頂點屬性信息的綁定,VAO是對多個VBO綁定

(2)OpenGL中所有的圖形都是通過分解成三角形的方式進行繪製,glDrawArrays函數把模型繪製出來,它使用當前激活的着色器,當前VAO對象中的VBO頂點數據和屬性配置來繪製圖形

void glDrawArrays(GLenum mode​, GLint first​, GLsizei count​);

mode:基本圖元類型包括GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLES_ADJACENCY , GL_PATCHES

first:指定緩存中的哪一位開始繪製,一般定義爲0
count:指定繪製的頂點數量

3.EBO(索引緩衝對象,Element Buffer Object,EBO)

EBO:索引緩衝對象EBO相當於OpenGL中頂點數組的概念,爲了解決同一個頂點多次重複調用的問題,可以減少內存浪費,提高效率。需要用重複的頂點的時候,通過頂點的位置索引來調用頂點。

EBO中存儲的內容就是位置的索引,EBO跟VBO很像,也是顯存中的一部分內存緩衝器

(1)創建EBO並綁定,用glBufferData,以GL_ELEMENT_ARRAY_BUFFER作爲參數,把索引存儲到EBO中

GLuint EBO;
glGenBuffers(1,&EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

(2)當用EBO綁定頂點索引的方式繪製模型時,需要使用glDrawElements

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

原型:void glDrawElements(GLenum mode​, GLsizei count​, GLenum type​, const GLvoid * indices​);
mode:基本圖元類型,GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLES_ADJACENCY ,GL_PATCHES
count:繪製的頂點個數
type:頂點數據類型,必須是GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, , GL_UNSIGNED_INT
indices:可選的EBO中偏移量設定

4.應用:

1.用VBO_VAO畫正方形

#include <GL/glew.h>
#include<gl\glut.h>
void MyInit();
void reshape(int w, int h);
void display();

GLuint vboId;
GLuint vaoId;

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(512, 512);
	glutCreateWindow("VBO_VAO_RECTANGLE");
	glewInit();
	MyInit();
	glutReshapeFunc(&reshape);
	glutDisplayFunc(&display);
	glutMainLoop();
	return 0;
}

void MyInit()
{
	glClearColor(0.0,0.0, 0.0,0.0);
	const GLfloat vertices[] = {
		-0.5f,-0.5f,0.0f,1.0f,
		0.5f,-0.5f,0.0f,1.0f,
		0.5f,0.5f,0.0f,1.0f,
		-0.5f,0.5f,0.0f,1.0f,
	};

	//創建VAO對象
	glGenVertexArrays(1, &vaoId);
	glBindVertexArray(vaoId);

	//創建VBO對象
	glGenBuffers(1, &vboId);
	glBindBuffer(GL_ARRAY_BUFFER, vboId);
	//傳入VBO數據
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	//解除VBO綁定
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}


void reshape(int w, int h)
{
	glViewport(0, 0,(GLsizei)w, (GLsizei)h);
}

void display()
{
	glClear(GL_COLOR_BUFFER_BIT);

	//綁定VBO
	glBindBuffer(GL_ARRAY_BUFFER, vboId);
	glEnableVertexAttribArray(0);

	//解釋頂點數據方式
	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

	//繪製模型
	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glDisableVertexAttribArray(0);
    glutSwapBuffers();
}

我們來看下效果
在這裏插入圖片描述

2.VEO畫正方形

#include <GL/glew.h>
#include<gl\glut.h>
#include<iostream>
void MyInit();
void reshape(int w, int h);
void display();

GLuint vboId;
GLuint vaoId;
GLuint eboId;

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(512, 512);
	glutCreateWindow("EBO_VBO_VAO_RECTANGLE");
	glewInit();
	MyInit();
	glutReshapeFunc(&reshape);
	glutDisplayFunc(&display);
	glutMainLoop();
	return 0;
}

void MyInit()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	const GLfloat vertices[] = {
		-0.5f,-0.5f,0.0f,1.0f,
		0.5f,-0.5f,0.0f,1.0f,
		0.5f,0.5f,0.0f,1.0f,
		-0.5f,0.5f,0.0f,1.0f,
	};

	GLshort indices[] = {
		0, 1, 3,  // 第一個三角形
		1, 2, 3   // 第二個三角形
	};

	//創建VAO對象
	glGenVertexArrays(1, &vaoId);
	glBindVertexArray(vaoId);

	//創建VBO對象
	glGenBuffers(1, &vboId);
	glBindBuffer(GL_ARRAY_BUFFER, vboId);

	//傳入VBO數據
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//創建EBO對象
	glGenBuffers(1, &eboId);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);

	//傳入EBO對象
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	//解釋頂點數據方式
	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);

	//解除VAO綁定
	glBindVertexArray(0);

	//解除VBO綁定
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	//解除EBO綁定
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}


void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}

void display()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glBindVertexArray(vaoId);
	//繪製模型
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
	glutSwapBuffers();
}

看下效果
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章