您的位置:首页 > 编程语言 > VB

OpenGL进阶(九) - GLSL中VAO和VBO的使用

2013-08-01 10:15 567 查看

回顾

Vertex Shader : 基于GLSL的语法写的一种类C的代码,可以用来控制顶点的特性,比如位置,颜色还有纹理坐标等。
Fragment Shader:用于计算每个片段的颜色,可用于实现光照还有真实感的贴图。
还有一种Shader 叫做Geometry Shader,用于添加顶点。
使用结合了GLSL的OpenGL程序的渲染管线就变成了这样:



VAO和VBO

VBO: 显卡存储空间里的一块缓存区(Buffer),用于记录顶点的信息,包括法线,问路坐标等,这个Buffer有它的名字(VBO的ID),OpenGL在GPU的某处记录着这个ID和对应的显存地址(或者地址偏移,类似内存)。

VAO:是一个对象,其中包含一个或者更多的Vertex Buffer Objects,用于记录渲染对象的完整信息。
使用步骤如下:
1.生成VAO
void glGenVertexArrays( GLsizei n,GLuint *arrays);
- generate vertex array object names

Parameters
n:指定要生成VAO的数量
arrays:指定VAO名字生成的位置

2.绑定VAO
void glBindVertexArray(GLuint array);
- generate vertex array object names

Parameters
array:执行要绑定的数组

3.产生VBOs
void glGenBuffers( GLsizei n,GLuint * buffers);
- generate buffer object names

Parameters
n:生成VBO的名字的个数
buffers:生成VBO名字的位置

4.绑定VBOS
void glBindBuffer( GLenum target, GLuint buffer);
- bind a named buffer object

Parameters
target
Specifies the target to which the buffer object is bound.

buffer
Specifies the name of a buffer object.

5.给VBO分配数据
void glBufferData( GLenum target,GLsizeiptr size,const GLvoid * data,GLenum usage);
creates and initializes a buffer object's data store.

Parameters
target
Specifies the target buffer object.

size
Specifies the size in bytes of the buffer object's new data store.

data
Specifies a pointer to data that will be copied into the data store for initialization, or NULL if no data is to be copied.

usage
Specifies the expected usage pattern of the data store.

6.给对应的顶点属性数组指定数据
void glVertexAttribPointer( GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const GLvoid * pointer);
- define an array of generic vertex attribute data
Parameters

index
Specifies the index of the generic vertex attribute to be modified.

size
Specifies the number of components per generic vertex attribute. Must be 1, 2, 3, 4. Additionally, the symbolic constant GL_BGRA is accepted by glVertexAttribPointer. The initial value is 4.

type
Specifies the data type of each component in the array. The symbolic constants GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, and GL_UNSIGNED_INT are accepted by glVertexAttribPointer and glVertexAttribIPointer. Additionally GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, GL_FIXED, GL_INT_2_10_10_10_REV, GL_UNSIGNED_INT_2_10_10_10_REV and GL_UNSIGNED_INT_10F_11F_11F_REV are accepted by glVertexAttribPointer. GL_DOUBLE is also accepted by glVertexAttribLPointer and is the only token accepted by the type parameter for that function. The initial value is GL_FLOAT.

normalized
For glVertexAttribPointer, specifies whether fixed-point data values should be normalized (GL_TRUE) or converted directly as fixed-point values (GL_FALSE) when they are accessed.

stride
Specifies the byte offset between consecutive generic vertex attributes. If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.

pointer
Specifies a offset of the first component of the first generic vertex attribute in the array in the data store of the buffer currently bound to the GL_ARRAY_BUFFER target. The initial value is 0.

7.设置Attribute变量,传递给shader
void glBindAttribLocation( GLuint program,GLuint index,const GLchar *name);
-Associates a generic vertex attribute index with a named attribute variable

Parameters

program
Specifies the handle of the program object in which the association is to be made.

index
Specifies the index of the generic vertex attribute to be bound.

name
Specifies a null terminated string containing the name of the vertex shader attribute variable to which index is to be bound.

利用VAO、VBO绘制图形

下面是一个绘制的实例。
basic.vert

#version 400 // in_Position was bound to attribute index 0 and in_Color was bound to attribute index 1 in  vec2 in_Position; in  vec3 in_Color;   // We output the ex_Color variable to the next shader in the chain out vec3 ex_Color; void main(void) {     // Since we are using flat lines, our input only had two points: x and y.     // Set the Z coordinate to 0 and W coordinate to 1       gl_Position = vec4(in_Position.x, in_Position.y, 0.0, 1.0);       // GLSL allows shorthand use of vectors too, the following is also valid:     // gl_Position = vec4(in_Position, 0.0, 1.0);     // We're simply passing the color through unmodified       ex_Color = in_Color; }


basic.frag
#version 400 precision highp float;   in  vec3 ex_Color; out vec4 gl_FragColor;   void main(void) {     // Pass through our original color with full opacity.     gl_FragColor = vec4(ex_Color,1.0); }

main.c
/***************************************************************************** Copyright: 2013, ustc All rights reserved. contact:k283228391@126.com File name: main.c Description:Using VAO and VBO in opengl. Author:Silang Quan Version: 1.0 Date: 2013.8.1 *****************************************************************************/ #include <SDL/SDL.h> #include <GL/glew.h> #include <GL/gl.h> #include <GL/glu.h> #include <stdio.h> #include <stdlib.h>   const int SCREEN_WIDTH = 800; const int SCREEN_HEIGHT =800; const int SCREEN_BPP = 32; SDL_Surface *screen; //Whether the window is windowed or not bool windowed; //Whether the window is fine bool windowOK; //Handler for GLSL program GLuint programHandle; GLuint vShader; GLuint fShader; GLuint vao, vbo[2];  void quit( int code ) {     SDL_Quit( );     /* Exit program. */     exit( code ); }  char *textFileRead(char *fn) {       FILE *fp;     char *content = NULL;       int count=0;       if (fn != NULL) {         fp = fopen(fn,"rt");           if (fp != NULL) {         fseek(fp, 0, SEEK_END);       count = ftell(fp);       rewind(fp);               if (count > 0) {                 content = (char *)malloc(sizeof(char) * (count+1));                 count = fread(content,sizeof(char),count,fp);                 content[count] = '\0';             }             fclose(fp);         }     }     return content; }  void toggle_fullscreen() { 	//If the screen is windowed 	if( windowed == true ) 	{ 		//Set the screen to fullscreen 		screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_OPENGL|SDL_RESIZABLE| SDL_FULLSCREEN );  		//If there's an error 		if( screen == NULL ) 		{ 			windowOK = false; 			return; 		}  		//Set the window state flag 		windowed = false; 	} 	//If the screen is fullscreen 	else if( windowed == false ) 	{ 		//Window the screen 		screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_OPENGL|SDL_RESIZABLE );  		//If there's an error 		if( screen == NULL ) 		{ 			windowOK = false; 			return; 		}  		//Set the window state flag 		windowed = true; 	} }  void handleKeyEvent( SDL_keysym* keysym ) {     switch( keysym->sym ) 	{     case SDLK_ESCAPE:         quit( 0 );         break;     case SDLK_SPACE:         break;     case SDLK_F1: 		toggle_fullscreen(); 		break;     default:         break;     } }  void resizeGL(int width,int height) {     if ( height == 0 )     {         height = 1;     }     //Reset View     glViewport( 0, 0, (GLint)width, (GLint)height );     //Choose the Matrix mode     glMatrixMode( GL_PROJECTION );     //reset projection     glLoadIdentity();     //set perspection     gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 );     //choose Matrix mode     glMatrixMode( GL_MODELVIEW );     glLoadIdentity(); }  void handleEvents() {     // Our SDL event placeholder.     SDL_Event event;     //Grab all the events off the queue.     while( SDL_PollEvent( &event ) ) {         switch( event.type ) {         case SDL_KEYDOWN:             // Handle key Event             handleKeyEvent( &event.key.keysym );             break;         case SDL_QUIT:             // Handle quit requests (like Ctrl-c).             quit( 0 );             break;         case SDL_VIDEORESIZE: 			//Handle resize event             screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 16,                                       SDL_OPENGL|SDL_RESIZABLE);             if ( screen )             {                 resizeGL(screen->w, screen->h);             }             break;         }     } }  void initSDL(int width,int height,int bpp,int flags) {     // First, initialize SDL's video subsystem.     if( SDL_Init( SDL_INIT_VIDEO ) < 0 )     {         fprintf( stderr, "Video initialization failed: %s\n",                  SDL_GetError( ) );         quit( 1 );     }     atexit(SDL_Quit); 	//Set some Attribute of OpenGL in SDL     SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );     SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );     SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );     SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );     SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );      //Set the video mode     screen= SDL_SetVideoMode( width, height, bpp,flags);     if(!screen )     {         fprintf( stderr, "Video mode set failed: %s\n",SDL_GetError( ) );         quit( 1 );     windowed=false; 	} 	else windowed=true;     resizeGL(screen->w, screen->h);     //Set caption     SDL_WM_SetCaption( "OpenGL Shading Language Test", NULL );       }  void initShader() { //Init VAO and VBO   /* We're going to create a simple diamond made from lines */      const GLfloat diamond[4][2] = {     {  0.0,  1.0  }, /* Top point */     {  1.0,  0.0  }, /* Right point */     {  0.0, -1.0  }, /* Bottom point */     { -1.0,  0.0  } }; /* Left point */       const GLfloat colors[4][3] = {     {  1.0,  0.0,  0.0  }, /* Red */     {  0.0,  1.0,  0.0  }, /* Green */     {  0.0,  0.0,  1.0  }, /* Blue */     {  1.0,  1.0,  1.0  } }; /* White */       /* These pointers will receive the contents of our shader source code files */     GLchar *vertexsource, *fragmentsource;       /* These are handles used to reference the shaders */     GLuint vertexshader, fragmentshader;       /* This is a handle to the shader program */     GLuint shaderprogram;           /* Allocate and assign a Vertex Array Object to our handle */     glGenVertexArrays(1, &vao);       /* Bind our Vertex Array Object as the current used object */     glBindVertexArray(vao);       /* Allocate and assign two Vertex Buffer Objects to our handle */     glGenBuffers(2, vbo);       /* Bind our first VBO as being the active buffer and storing vertex attributes (coordinates) */     glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);          glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), diamond, GL_STATIC_DRAW);            /* Specify that our coordinate data is going into attribute index 0, and contains two floats per vertex */     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);       /* Enable attribute index 0 as being used */     glEnableVertexAttribArray(0);       /* Bind our second VBO as being the active buffer and storing vertex attributes (colors) */     glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);          glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), colors, GL_STATIC_DRAW);       /* Specify that our color data is going into attribute index 1, and contains three floats per vertex */     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);       /* Enable attribute index 1 as being used */     glEnableVertexAttribArray(1); 	 	vShader = glCreateShader( GL_VERTEX_SHADER ); 	fShader = glCreateShader( GL_FRAGMENT_SHADER ); 	printf("Here\n"); 	if(0 == vShader || 0 == fShader) 	{ 		fprintf(stderr, "Error creating vertex shader.\n"); 		quit(1); 	} 	 	GLchar* vShaderCode = textFileRead("basic.vert"); 	GLchar* fShaderCode = textFileRead("basic.frag"); 	const GLchar* vCodeArray[1] = {vShaderCode}; 	const GLchar* fCodeArray[1] = {fShaderCode}; 	glShaderSource(vShader, 1, vCodeArray, NULL); 	glShaderSource(fShader, 1, fCodeArray, NULL); 	 	glCompileShader(vShader); 	glCompileShader(fShader); 	free(vShaderCode); 	free(fShaderCode); 	//const GLchar* codeArray[] = {shaderCode}; 	//Check the compile result 	GLint logLen; 	glGetShaderiv(vShader, GL_INFO_LOG_LENGTH, &logLen); 	if(logLen > 0) 	{ 		char *log = (char *)malloc(logLen); 		GLsizei written; 		glGetShaderInfoLog(vShader, logLen, &written, log); 		printf("Shader compile error log: %s\n",log); 		free(log); 	} 	 	programHandle = glCreateProgram(); 	if(0 == programHandle) 	{ 		fprintf(stderr, "Error creating programHandle.\n"); 		quit(1); 	} 	 	glAttachShader(programHandle, vShader); 	glAttachShader(programHandle, fShader); 	 	 	glBindAttribLocation(programHandle, 0, "in_Position"); 	glBindAttribLocation(programHandle, 1, "in_Color"); 	 	glLinkProgram(programHandle); 	//glUseProgram(programHandle); }  void freeShader() { 	glDisableVertexAttribArray(0);     glDisableVertexAttribArray(1); 	glDetachShader(programHandle, fShader); 	glDetachShader(programHandle, vShader); 	//glDeteteProgram(programHandle); 	glDeleteShader(fShader); 	glDeleteShader(vShader); 	glDeleteBuffers(2, vbo);     glDeleteVertexArrays(1, &vao); } void renderGL() { 	/* These are to calculate our fps */     static GLint T0     = 0; 	static GLint Frames = 0;     // Clear the color and depth buffers.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );     // We don't want to modify the projection matrix. */     glMatrixMode( GL_MODELVIEW );     glLoadIdentity( );     // Move down the z-axis.     glTranslatef( 0.0, 0.0, -5.0 );                     	//Draw a square 	int i;     glUseProgram(programHandle);  	for (i=2; i <= 4; i++)     {         /* Make our background black */         glClearColor(0.0, 0.0, 0.0, 1.0);         glClear(GL_COLOR_BUFFER_BIT);           /* Invoke glDrawArrays telling that our data is a line loop and we want to draw 2-4 vertexes */         glDrawArrays(GL_TRIANGLE_FAN, 0, i);       }           // Unbind shader     glUseProgram(0);    	SDL_GL_SwapBuffers( );          /* Gather our frames per second */     Frames++;     { 	GLint t = SDL_GetTicks(); 	if (t - T0 >= 5000) { 	    GLfloat seconds = (t - T0) / 1000.0; 	    GLfloat fps = Frames / seconds; 	    printf("%d frames in %g seconds = %g FPS\n", Frames, seconds, fps); 	    T0 = t; 	    Frames = 0; 	}     } }  void initGL( int width, int height ) {     float ratio = (float) width / (float) height;     // Our shading model--Gouraud (smooth).     glShadeModel( GL_SMOOTH );     // Set the clear color.     glClearColor( 0, 0, 0, 0 );     // Setup our viewport.     glViewport( 0, 0, width, height );     //Change to the projection matrix and set our viewing volume.     glMatrixMode( GL_PROJECTION );     glLoadIdentity();     gluPerspective( 60.0, ratio, 1.0, 100.0 ); }  int main( int argc, char* argv[] ) {  	// Color depth in bits of our window. 	int flags= SDL_OPENGL|SDL_RESIZABLE; 	//Set the SDL 	initSDL(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,flags); 	if(glewInit() != GLEW_OK) exit(EXIT_FAILURE); 	//Init vertext shader 	initShader(); 	//Set the OpenGL 	initGL(SCREEN_WIDTH, SCREEN_HEIGHT );      //main loop     while(true) 	{         /* Process incoming events. */         handleEvents( );         /* Draw the screen. */         renderGL( );     }     // Free Shader     freeShader();     return 0; }

编译
g++ main.c -o main -lSDL -lglut -lGLU -lGLEW



程序解释:
主要看initShader函数。
首先时定义了二维坐标数组dimond和三维的颜色数组colors,然后,通过 glGenVertexArrays生成VAO,通过glGenBuffers生成VBO。Vao中包含着顶点的信息和数据的连接信息。 glVertexAttribPointer用于定义数据的index,存在buffer中的数据格式,在shader中会用到。
接下来时初始化shader,这个在上面说了。
initShader 就是做shader render之前的准备工作。
接下来的renderGL函数,用到glClear 清除color buffer,绘制使用的函数是glDrawArray。

参考

Tutorial2: VAOs, VBOs, Vertex and Fragment Shaders (C / SDL) - http://www.opengl.org/wiki/Tutorial2:_VAOs,_VBOs,_Vertex_and_Fragment_Shaders_(C_/_SDL)
【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形 - http://blog.csdn.net/xiajun07061225/article/details/7628146
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: