OpenGL单个VAO关联多对象独立VBO的绘制实现问询
核心问题:单个VAO关联多个独立Buffer实现多对象绘制
问题背景
我尝试将多个Buffer关联到单个Vertex Array Object (VAO),每个Buffer对应一个对象模型(比如顶点、法线、纹理数据)。为简化示例,我创建了两个仅含单个三角形(3个顶点)及对应颜色的对象:ArrayBuffer1存储第一个三角形的齐次顶点坐标与RGBA颜色向量,ArrayBuffer2存储第二个三角形的对应数据。
着色器代码
顶点着色器
#version 400 core layout( location = 0 ) in vec4 vPosition; layout( location = 1 ) in vec4 vColor; out vec4 color; void main() { color= vColor; gl_Position = vPosition; }
片段着色器
#version 450 core in vec4 color; out vec4 fColor; void main() { fColor = color; }
客户端初始化与渲染代码
初始化代码
enum VertexDim { xDim, yDim, zDim, wDim, NumDim}; enum VAO_IDs { Triangles, NumVAOs }; enum Buffer_IDs { ArrayBuffer1, ArrayBuffer2, NumBuffers }; enum Attrib_IDs { vPosition = 0, vColor=1 }; GLuint VAOs[NumVAOs]; GLuint Buffers[NumBuffers]; const GLuint NumVertices = 6; const GLuint curDim= NumDim; // first triangle GLfloat static_vertices1[NumVertices/2][NumDim] = { { -0.90f, -0.90f, 0.5f, 1}, { 0.85f, -0.90f, 0.3f, 1 }, { -0.90f, 0.85f, 0.0f, 1 } // Triangle 1 }; // second triangle GLfloat static_vertices2[NumVertices/2][NumDim] = { { 0.90f, -0.85f, -0.1f, 1 }, { 0.90f, 0.90f, -0.5f, 1 }, { -0.85f, 0.90f, -0.8f, 1 } // Triangle 2 }; // a base color from which to compute different vertex colors GLfloat infColor_value[4]= {0.9f, 0.7f, 0.5f, 1.0f}; //---------------------------------------------------------------------------- // // init // void init( void ) { const unsigned int n=NumVertices/2; GLfloat infColor_values1[n][curDim]; GLfloat infColor_values2[n][curDim]; // compute different vertex colors from base color infColor_value // .. loop over infColor_values1 and infColor_values2 ShaderInfo shaders[] = { { GL_VERTEX_SHADER, "media/shaders/triangles/triangles2.vert" }, { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles2.frag" }, { GL_NONE, NULL } }; // LoadShaders is a wrapper to load, compile code and link shaders GLuint program = LoadShaders( shaders ); if( program == 0) { std::cerr<<"shader program failed to build" << std::endl; } glUseProgram( program ); glGenVertexArrays( NumVAOs, VAOs ); glBindVertexArray( VAOs[Triangles] ); glCreateBuffers( NumBuffers, Buffers ); // vertex 1 glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer1] ); glNamedBufferData( Buffers[ArrayBuffer1], sizeof(static_vertices1)+sizeof(infColor_values1) , NULL, GL_STATIC_DRAW); glNamedBufferSubData( Buffers[ArrayBuffer1], 0, sizeof(static_vertices1), static_vertices1); glNamedBufferSubData( Buffers[ArrayBuffer1], sizeof(static_vertices1), sizeof(infColor_values1), infColor_values1); GLuint64 offset = 0; glVertexAttribPointer( vPosition, NumDim, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); glEnableVertexAttribArray( vPosition ); offset = sizeof(static_vertices1); glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)offset ); glEnableVertexAttribArray( vColor ); // vertex 2 glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer2] ); glNamedBufferData( Buffers[ArrayBuffer2], sizeof(static_vertices2)+sizeof(infColor_values2) , NULL, GL_STATIC_DRAW); glNamedBufferSubData( Buffers[ArrayBuffer2], 0, sizeof(static_vertices2), static_vertices1); glNamedBufferSubData( Buffers[ArrayBuffer2], sizeof(static_vertices2), sizeof(infColor_values2), infColor_values2); offset = 0; glVertexAttribPointer( vPosition, NumDim, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); glEnableVertexAttribArray( vPosition ); offset = sizeof(static_vertices2); glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)offset ); glEnableVertexAttribArray( vColor ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glBindVertexArray(0); }
渲染代码
void display( void ) { static const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; glClearBufferfv(GL_COLOR, 0, black); glBindVertexArray( VAOs[Triangles] ); glDrawArrays( GL_TRIANGLES, 0, NumVertices ); glBindVertexArray(0); }
核心疑问
如何将每个对象的顶点属性存储在独立的单个Buffer中,同时实现多个对象的正确绘制?我可以将所有数据放入同一子缓冲,但无法找到分离对象渲染的方案,且未在相关资料中找到针对性答案。
问题分析与解决方案
你的代码存在两个关键问题:
- VAO状态覆盖:单个VAO只能记录一组顶点属性配置。你在初始化时先绑定ArrayBuffer1并配置vPosition和vColor,之后又绑定ArrayBuffer2重新配置这两个属性,这会覆盖VAO中之前的配置。最终VAO只关联了ArrayBuffer2的属性,且你还写错了
static_vertices1作为第二个Buffer的顶点数据(应该是static_vertices2)。 - 绘制逻辑错误:单个
glDrawArrays无法同时使用两个不同的Buffer数据,因为VAO只能绑定一组属性对应的Buffer。
方案一:为每个对象创建独立VAO(推荐)
每个对象对应一个VAO,各自绑定自己的Buffer并配置顶点属性,渲染时分别绑定对应的VAO并绘制:
// 修改枚举定义 enum VAO_IDs { Triangle1, Triangle2, NumVAOs }; GLuint VAOs[NumVAOs]; // 初始化流程调整 glGenVertexArrays( NumVAOs, VAOs ); // 初始化第一个三角形 glBindVertexArray( VAOs[Triangle1] ); glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer1] ); glVertexAttribPointer( vPosition, NumDim, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); glEnableVertexAttribArray( vPosition ); GLuint64 offset = sizeof(static_vertices1); glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)offset ); glEnableVertexAttribArray( vColor ); // 初始化第二个三角形 glBindVertexArray( VAOs[Triangle2] ); glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer2] ); // 修正数据错误:传入static_vertices2而非static_vertices1 glNamedBufferSubData( Buffers[ArrayBuffer2], 0, sizeof(static_vertices2), static_vertices2); glVertexAttribPointer( vPosition, NumDim, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); glEnableVertexAttribArray( vPosition ); offset = sizeof(static_vertices2); glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)offset ); glEnableVertexAttribArray( vColor ); // 渲染函数修改 void display(void) { static const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; glClearBufferfv(GL_COLOR, 0, black); glBindVertexArray( VAOs[Triangle1] ); glDrawArrays( GL_TRIANGLES, 0, 3 ); glBindVertexArray( VAOs[Triangle2] ); glDrawArrays( GL_TRIANGLES, 0, 3 ); glBindVertexArray(0); }
方案二:使用单个VAO,渲染时切换Buffer并重新配置属性(不推荐)
如果坚持用单个VAO,需要在渲染时分别绑定每个对象的Buffer,重新配置顶点属性后再绘制:
void display(void) { static const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; glClearBufferfv(GL_COLOR, 0, black); glBindVertexArray( VAOs[Triangles] ); // 绘制第一个三角形 glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer1] ); glVertexAttribPointer( vPosition, NumDim, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); glEnableVertexAttribArray( vPosition ); GLuint64 offset = sizeof(static_vertices1); glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)offset ); glEnableVertexAttribArray( vColor ); glDrawArrays( GL_TRIANGLES, 0, 3 ); // 绘制第二个三角形 glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer2] ); // 修正数据错误:确保Buffer内是static_vertices2的数据 glVertexAttribPointer( vPosition, NumDim, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) ); glEnableVertexAttribArray( vPosition ); offset = sizeof(static_vertices2); glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)offset ); glEnableVertexAttribArray( vColor ); glDrawArrays( GL_TRIANGLES, 0, 3 ); glBindVertexArray(0); }
这种方案效率较低,因为每次绘制都要重新配置顶点属性,违背了VAO的设计初衷,所以优先推荐方案一。
内容的提问来源于stack exchange,提问作者pascal sautot
相关产品推荐
相关产品推荐

