OpenGL 顶点数组与缓冲区对象进行渲染(含纹理贴图)

本文介绍了OpenGL中如何利用顶点数组和缓冲区对象提高渲染效率。顶点数组对象避免了重复设置顶点属性,而缓冲区对象减少了数据读写的开销。通过结合使用这两个特性,可以在大场景渲染中实现高效切换和数据管理。文章还提供了一个使用Qt的QImage数据结构的三维场景渲染实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、顶点数组,顶点数组对象和缓冲区对象

顶点数组及顶点数组对象可以有效地解决渲染过程中的数据冗余以及大量的添加额外信息的问题,而缓冲区对象则避免渲染过程中反复的读写数据导致的效率损耗。二者结合可以大幅度的提高渲染的效率。

1、顶点数组的使用步骤:

(1) 激活数组。这些数组描述了图元的几何属性,例如,顶点坐标,表面法线,RGBA颜色,辅助颜色,颜色索引,雾坐标,纹理坐标,多边形边界标志等。

 
glEnableClientState(GLenum array)

(2)把数据放入数组中。 其他属性采用 glColorPointer(...), glTextureCoordPointer(...)等等,不一一列举。

 glVertexPointer(GLint sizei, GLenum type, GLsizei stride, const GLvoid * pointer)

(3) 绘制几何图元。

glDrawElements(GLenum Mode, GLsizei count, GLenum type, const GLvoid* indices) 

在大场景渲染过程中,通常多个对象之间的顶点属性并不相同,这时候需要频繁调用glVetexPointer这些函数。而顶点数组对象则对这些调用进行集合。简单点来讲,针对每个需要渲染的对象创建一个顶点数组对象,此时该顶点数组对象包含了该对象所有的属性,在渲染的过程中,只需要调用该对象的顶点数组对象,便可以在多个对象之间进行切换,从而避免了glVetexPointer函数的反复调用。

2、顶点数组对象相关的函数:

(1)创建顶点数组对象

glGenVertexArray(GLsizei n, GLuint* arrarys)

(2)初始化新对象

glBindVertexArray(GLuint array) 

 3、使用缓冲区对象的基本步骤:

(1) 创建缓冲区对象

glGenBuffers(GLsizei n, GLuint *buffers)

(2)激活缓冲区对象

glBindBuffers(GLenum target, GLuint buffer) 

(3)用数据分配和初始化缓冲区对象

glBufferData*GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) 

二、下面结合一个三维场景渲染的实例具体介绍函数的用法。代码中采用了Qt的图像数据结构QImage.

1.全局变量

GLuint element_num[2];//存储顶点和面片的个数
GLuint arrayIndex;// 顶点数组对象的索引</span>

2.设置场景数据

void GLViewer::makeObjects()
{
	// 采用Qt加载纹理图像 
	QImage tex;
	tex = convertToGLFormat(*g_texture_image_);
	glGenTextures(1, &g_texture_id_);// 生成纹理对象
        
	glBindTexture(GL_TEXTURE_2D, g_texture_id_);//激活当前纹理
	glTexImage2D(GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


        //***********************************************************************//
	glewInit();// OpenGL的扩扩展库glew中的函数,这句必须调用,否则运行不通
        //************************************************************************//


	glGenVertexArrays(1, &arrayIndex); //1. 生成顶点数组对象,可以理解成每个顶点数组对应一个需要渲染的对象
	enum{ Verices, TexCoords, Colors, Elements, NumAttris }; // 顶点数组的属性
	GLuint buffers[NumAttris];

	GLfloat *vertices = new GLfloat [element_num[0]*3]; //顶点坐标
        GLfloat *texturecoords = new GLfloat [element_num[0]*3];// 纹理坐标
	GLfloat *colors = new GLfloat[element_num[0] * 3]; //颜色
        GLuint * facets = new GLuint [element_num[1] * 3];// 面片索引信息    
        //********************************************************************//
        //*  vertices, texturecoords, colors, facets  需要进行初始化        *//
          
         NumElements = (GLsizei)g_element_num_[1] * 3;       
        //**********************************************************************//
         // 这里需要注意的是 
         // GLfloat * a = new GLfloat[3];
         // GLfloat b[3];
         // sizeof(a) 和 sizeof(b) 大小是不相同的 
       //***********************************************************************//
         glBindVertexArray(arrayIndex);// 2.激活顶点数组
         glGenBuffers(NumAttris, buffers);//3. 生成缓冲区对象,每个属性对应一个缓冲区对象 // 针对每个属性将数据放到对应的缓冲区中

        //VERTEX
        glBindBuffer(GL_ARRAY_BUFFER, buffers[Verices]);//4. 激活对应的缓冲区对象
        glBufferData(GL_ARRAY_BUFFER, element_num[0] * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);//5 缓冲区数据分配,缓冲区大小不能直接用sizeof(vertices)
        glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));// 6 把数据放入顶点数组中
        glEnableClientState(GL_VERTEX_ARRAY);// 7. 激活顶点数组属性 // 其他属性的设置方式类似

       //COLOR
         glBindBuffer(GL_ARRAY_BUFFER, buffers[Colors]);
         glBufferData(GL_ARRAY_BUFFER, element_num[0] * 3 * sizeof(GLfloat), colors, GL_STATIC_DRAW);
         glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));glEnableClientState(GL_COLOR_ARRAY);

       //TEXTURE COORDS
       for (int i = 0; i < g_element_num_[0]; i++)
       {g_texture_coords_[i * 2 + 1] = 1 - g_texture_coords_[i * 2 + 1];}
       glBindBuffer(GL_ARRAY_BUFFER, buffers[TexCoords]);
       glBufferData(GL_ARRAY_BUFFER, element_num[0] * 2 * sizeof(GLfloat), texturecoords, GL_STATIC_DRAW);
       glTexCoordPointer(2, GL_FLOAT, 0, BUFFER_OFFSET(0));glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        //Face ELEMENT
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[Elements]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, element_num[1] * 3 * sizeof(GLuint),facets, GL_STATIC_DRAW);

       


 

3.渲染过程

渲染过程中可以调用glPolygonMode(Glenum face, GLenum mode) 将场景渲染成,顶点,火柴架,和面片的形式。

void GLViewer::draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glDisable(GL_LIGHTING);
	glShadeModel(GL_FLAT);

	// display mesh vertices
	if (g_display_vertices_ == true){

		glBindVertexArray(arrayIndex); //激活当前顶点数组对象,本例中只有一个顶点数组对象
		glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 将场景的前后面渲染成定点的形式
		glDrawElements(GL_TRIANGLES, NumElements, GL_UNSIGNED_INT, BUFFER_OFFSET(0));// 渲染
               //****************************************************************//
               // 注意数据的格式 GL_UNSIGNED_INT 应该和保持一致
               //****************************************************************//
	}

	// display mesh in wire frame mode 
	if (g_display_wire_frame_ == true){

		glBindVertexArray(arrayIndex);
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glDrawElements(GL_TRIANGLES, NumElements, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
	}

	// display mesh in Flat Mode
	if (g_display_flat_ == true){

		glBindVertexArray(arrayIndex);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glDrawElements(GL_TRIANGLES, NumElements, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
	}

	// draw mesh with texture
	if (g_display_texture_ == true){

           //******************************************************************//
           //*  启用纹理贴图模式, 非常重要 !! *//
		glEnable(GL_TEXTURE_2D); 

		glBindVertexArray(arrayIndex);
		glBindTexture(GL_TEXTURE_2D, g_texture_id_);// 激活当前纹理

           //*****************************************************************//    
           //*纹理渲染的过程中禁用颜色属性,顶点数组可以根据需要禁用相应的属性
             glDisableClientState(GL_COLOR_ARRAY);
         
             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
             glDrawElements(GL_TRIANGLES, NumElements, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
             glEnableClientState(GL_COLOR_ARRAY);
             glDisable(GL_TEXTURE_2D);
            }
       glFlush();
  }

 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值