glDrawElements 使用了错误的 VBO?

glDrawElements using the wrong VBO?

我正在尝试在屏幕上渲染两个不同的对象。据我所知,问题是 OpenGL 使用了错误的顶点缓冲区,但使用了正确的索引缓冲区,但我不太确定我目前正在做的任何事情,因为我已经开始重新学习 OpenGL。

这是当前显示的内容:http://puu.sh/ekhd7/cca60981ab.jpg

如果对对象使用 类 是个坏主意,或者应该如何完成,请告诉我 - 我什么都不做。

struct point4{
vec4 vertex;
vec4 color;
};


class Pyramid
{
public:
//Variables and Contructor here 
void init(){
    glGenBuffers( 1, &Arraybufferx );
    glBindBuffer( GL_ARRAY_BUFFER, Arraybufferx );
    glBufferData( GL_ARRAY_BUFFER, sizeof(point4)*16, NULL, GL_STATIC_DRAW );
    glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(left), left );
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(left)  , sizeof(right), right );               
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(left)*2, sizeof(back), back );
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(left)*3, sizeof(front), front );
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(left)*4, sizeof(bottom), bottom );

    glGenBuffers( 1, &IndexBuffer );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IndexBuffer );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(gIndices), gIndices, GL_STATIC_DRAW );
}

void display(GLint tr,GLint theta, GLfloat rt1[], GLfloat Theta1[]){

    glBindBuffer( GL_ARRAY_BUFFER, Arraybufferx );      
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IndexBuffer );

    glUniform3fv( tr, 1,  rt1 );
    glUniform3fv( theta, 1, Theta1 );   

    glDrawElements( GL_TRIANGLES, sizeof(gIndices), GL_UNSIGNED_INT, 0 );

    glBindBuffer( GL_ARRAY_BUFFER, 0 );     
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
}
};

class cube{
 public:
//Variables and Contructor here     
void init(){
    glGenBuffers( 1, &Arraybuffer );
    glBindBuffer( GL_ARRAY_BUFFER, Arraybuffer );
    glBufferData( GL_ARRAY_BUFFER, sizeof(left)*6, NULL, GL_STATIC_DRAW );
    glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(left), left );
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(point4)*4, sizeof(right), right );
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(point4)*8, sizeof(top), top );
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(point4)*12, sizeof(bottom), bottom );
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(point4)*16, sizeof(back), back );
    glBufferSubData( GL_ARRAY_BUFFER, sizeof(point4)*20, sizeof(front), front );    

    glGenBuffers( 1, &IndexBuffer );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IndexBuffer );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(gIndices), gIndices, GL_STATIC_DRAW );
}

void display(GLint tr,GLint theta, GLfloat rt1[], GLfloat Theta1[]){

    glBindBuffer( GL_ARRAY_BUFFER, Arraybuffer );       
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IndexBuffer );

    glUniform3fv( tr, 1,  rt1 );
    glUniform3fv( theta, 1, Theta1 );       

    glDrawElements( GL_TRIANGLES, sizeof(gIndices), GL_UNSIGNED_INT, 0 );   
    glBindBuffer( GL_ARRAY_BUFFER, 0 );     
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
}
};

void init()
{
  // Create a vertex array object
  GLuint vao;
  glGenVertexArrays( 1, &vao );
  glBindVertexArray( vao );

  pyramid.init();
  Cube.init();  

  GLuint program = InitShader( "vshader36.glsl", "fshader36.glsl" );
  glUseProgram( program );

  GLuint vPosition = glGetAttribLocation( program, "vPosition" );
  glEnableVertexAttribArray( vPosition );    

  GLuint vColor = glGetAttribLocation( program, "vColor" ); 
  glEnableVertexAttribArray( vColor );    

  model_view = glGetUniformLocation(program, "model_view");
  GLuint projection = glGetUniformLocation(program, "projection");

  glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, sizeof(point4), 0 );  

  glVertexAttribPointer(vColor,4,GL_FLOAT,GL_FALSE,sizeof(point4),(void*)sizeof(vec4));

  // Create and send the model view matrix
  mat4 mv = LookAt(eye, at, up);
  glUniformMatrix4fv(model_view, 1, GL_TRUE, mv);

  theta = glGetUniformLocation( program, "theta" );

  tr = glGetUniformLocation( program, "tr" );   

  glEnableClientState (GL_VERTEX_ARRAY);    
  mat4 p = Frustum(-1.0, 1.0, -1.0, 1.0, 10.0, -20.0);
  glUniformMatrix4fv(projection, 1, GL_TRUE, p);

  glEnable( GL_DEPTH_TEST );
  glClearColor( 1.0, 1.0, 1.0, 1.0 );    
}
//----------------------------------------------------------------------------
void display( void )
{
    mat4 mv = LookAt(eye, at, up);
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glUniformMatrix4fv(model_view, 1, GL_TRUE, mv);

    Cube.display(tr,theta,Translate1,Theta);
    pyramid.display(tr,theta,Translate2,Theta);

    glutSwapBuffers();
}

您误解了顶点数组指针(和 VAO)的工作原理。 glDraw*() 命令 从不 关心当前的 GL_ARRAY_BUFFER 绑定。该绑定在 glVertexAtrrib*Pointer() 调用时 是相关的 - 对当前绑定 GL_ARRARY_BUFFER 的引用成为 的一部分 属性指针。这也意味着您可以将每个属性设置为从不同的缓冲区中获取。

因此,您的代码将仅使用 cube 对象的 VBO,因为这是在您设置顶点属性指针时绑定的对象。

当你想绘制不同的对象时,你必须切换 顶点属性指针,所以它看起来像这样:

drawObject() {
    glBindBuffer(GL_ARRAY_BUFFER,vbo_for_attr0);
    glVertexAttribPointer(0,...);
    glBindBuffer(GL_ARRAY_BUFFER,vbo_for_attr1);
    glVertexAttribPointer(1,...);
    [...]
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glDrawElements(...);

(假设您对所有对象使用相同的属性。如果不是这种情况,您可能还必须 enable/disable 此函数中的属性数组)。

这就是 VAO 发挥作用的地方。 VAO 是容器对象,存储每个属性的完整顶点数组指针状态(包括缓冲区绑定和 enable/disable 状态),以及 GL_ELEMENT_ARRAY 缓冲区绑定。从概念上讲,您可以为每个对象创建一个 VAO,并将顶点指针设置移动到您的 init() 函数,将绘制代码减少到

drawObject() {
    glBindVertexArray(vao);
    glDrawElements(...);

所以从概念上讲,它看起来像这样: