多个对象绘制(OpenGL)

17

问题在于我无法正确绘制两个对象,因为我的另一个对象没有被绘制。

以下是主代码:

GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint VertexArrayID2;
glGenVertexArrays(1, &VertexArrayID2);
glBindVertexArray(VertexArrayID2);

GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" );

GLuint MatrixID = glGetUniformLocation(programID, "MVP");
GLuint MatrixID2 = glGetUniformLocation(programID, "MVP2");

glm::mat4 Projection = glm::perspective(45.0f, 5.0f / 4.0f, 0.1f, 100.0f);
glm::mat4 View       = glm::lookAt(
    glm::vec3(4*2,3*2,8*2),
    glm::vec3(0,0,0),
    glm::vec3(0,1,0)
);
glm::mat4 Model      = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
glm::mat4 MVP        = Projection * View * Model;

glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);

glm::mat4 Model2      = glm::translate(glm::mat4(1.0f), glm::vec3(-5.0f, 0.0f, 0.0f));
glm::mat4 MVP2        = Projection * View * Model2;

glUniformMatrix4fv(MatrixID2, 1, GL_FALSE, &MVP2[0][0]);

static const GLfloat g_vertex_buffer_data[] = {
    -1.0f,-1.0f,-1.0f,
    -1.0f,-1.0f, 1.0f,
             (plenty of floats) 
     1.0f,-1.0f, 1.0f
};

static const GLfloat g_vertex_buffer_data2[] = { 
    -1.0f, -1.0f, 3.0f,
     (plenty of floats)
     0.0f,  1.0f, 2.0f,
};


GLuint vertexbuffer; 
glGenBuffers(1, &vertexbuffer); 
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); 
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

GLuint vertexbuffer2;
glGenBuffers(1, &vertexbuffer2);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data2), g_vertex_buffer_data2, GL_STATIC_DRAW);

do{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(programID);

    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
    glUniformMatrix4fv(MatrixID2, 1, GL_FALSE, &MVP2[0][0]);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);

    glDrawArrays(GL_TRIANGLES, 0, 12*3);        

    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
    glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,0,(void*)0);

    glDrawArrays(GL_TRIANGLES, 0, 4*3);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(2);

    glfwSwapBuffers(window);
    glfwPollEvents();

  }

着色器:

layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 2) in vec3 vertexPosition_modelspace2;

uniform mat4 MVP;
uniform mat4 MVP2;

void main(){

gl_Position =  MVP * vec4(vertexPosition_modelspace,1);
gl_Position =  MVP2 * vec4(vertexPosition_modelspace2,1);
}

我注意到只有最后一个物体被绘制了,因此问题在于“gl_Position”覆盖了它的值,但我应该如何找出原因?


请在以下链接中查看包含完整代码的示例:https://stackoverflow.com/questions/23165584/how-to-draw-multiple-objects-by-glm-opengl/49180827#49180827 - Charly Nicolini
请查看以下链接,其中包含C++的完整示例:https://stackoverflow.com/a/49180827/9463926 - Charly Nicolini
1个回答

18
gl_Position =  MVP * vec4(vertexPosition_modelspace,1);
gl_Position =  MVP2 * vec4(vertexPosition_modelspace2,1);

这不是图形管线的工作方式。您无法同时绘制两个对象。只有最后一次写入gl_Position才有效,并且您的第一个对象将被完全忽略。在最基本的变体中,您想要绘制两个完全独立的对象,因此您需要进行两个绘制调用 - 就像您在代码中所做的那样。

但是,在这样做时,您不需要两个不同的顶点属性。您的着色器只处理顶点,在您的情况下,这些顶点仅具有verexPosition_modelspace属性。因此,您可以将该属性用于要绘制的所有对象。如果属性表示相同的含义,则使用不同的属性绘制不同的对象是没有意义的。

让我们看一下您的绘图代码:

glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);

在这里,您将顶点属性0设置为指向第一个缓冲区的顶点数据,并启用属性数组。因此,该数据将不作为vertexPosition_modelspace的源使用。

glDrawArrays(GL_TRIANGLES, 0, 12*3);        

现在您要绘制对象。但正如我们之前所看到的,您的着色器只真正使用了 vertexPosition_modelspace2,对此您没有设置指针或启用数组。由于该数组被禁用,GL将使用属性2的当前值-对于所有顶点。因此,在三角形的情况下,您使用所有点相同的三角形-得到表面积为0且无论属性2的实际值如何,都是不可见的。

glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);

现在您正在做一件奇怪的事情:您启用了属性2数组,但却没有为其设置指针!您应该重新指定属性0的指针,以指向您的第二个模型。

glDrawArrays(GL_TRIANGLES, 0, 4*3);

现在您需要同时启用属性 0 和 2 进行绘制。属性 0 包含您想要的数据,但被着色器忽略。而属性 2 只是指向某个位置,并且您会得到未定义的行为 - 它可能会崩溃,但也可能显示奇怪的东西或根本没有内容。

为了使此工作正常,请完全删除着色器中的vertexPosition_modelspace2。同时只使用一个MVP矩阵。 在绘制任何对象时,您必须:

  1. 设置该对象的MVP统一矩阵
  2. 设置属性 0 的属性指针
  3. 启用属性 0 的属性数组(或确保其已启用)
  4. 发出绘制调用

您可以对任意数量的对象执行此操作。


glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2); glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);哦,这是个打字错误,非常抱歉。 我本来想写的是 glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,0,(void*)0); 就像我的实际代码一样但是如何只使用一个MVP矩阵独立地转换对象呢? - RevanReborn
@RevanReborn:在绘制对象之前更改/更新矩阵(请参见我的步骤1)。 - derhass
是的!现在它能工作了!所以我只是删除了所有不必要的“2”,并且重新组织了MVP转换,使其在循环内正确排序。非常感谢你的帮助! - RevanReborn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接