如何在openGL中显示2个或更多对象(模型 - 视图 - 投影矩阵和着色器)

时间:2012-02-29 17:32:57

标签: opengl glsl shader

当我想绘制一个对象(例如立方体)时,这一切都很好。我为立方体创建顶点,我创建缓冲区,我创建MVP矩阵并将其发送到着色器,它工作得很好。

但是,当我想绘制2个或更多个物体时该做什么,例如立方体和三角形?我认为三角形和立方体的视图和投影矩阵应该相同,我只需要不同的模型矩阵,对吧? 那么这意味着我将拥有两个MVP?

//Example (using GLM):

glm::mat4 MVPC = Projection * View * ModelCube; 
glm::mat4 MVPT = Projection * View * ModelTriangle; 

那我现在该怎么办?这是适用于立方体

的顶点着色器
//vertex shader
#version 330 core

layout(location = 0) in vec3 verticesCube;

uniform mat4 MVPC;

void main(){

     gl_Position =  MVPC * vec4(verticesCube,1);

}

我应该如何处理着色器中的MVPT(三角形),我尝试弄乱不同的东西,但我不能让它工作,我不能同时显示立方体和三角形。

4 个答案:

答案 0 :(得分:7)

混淆来自于认为着色器一次控制多个顶点数组,而它应该被视为一个通用实体。将顶点数组传递给着色器,然后绘制对象。然后重复这个过程。

例如,假设我们将变量 matrixID 分配给统一 MVP

    // get handle for our "MVP" uniform
    GLuint matrixID = glGetUniformLocation(programID, "MVP");

当我们准备绘制对象时,我们将 matrixID 设置为对象的MVP:

    glUniformMatrix4fv(matrixID, 1, GL_FALSE, &cubeMVP[0][0]);

然后绑定顶点缓冲区,设置属性指针并绘制它:

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVerteciesBuffer);

    glVertexAttribPointer(
            0,      // shader layout location
            3,
            GL_FLOAT,
            GL_FALSE,
            0,
            (void *)0
    );
    glDrawArrays(GL_TRIANGLES, 0, 12*3);    // draw cube

现在我们转到三角形并重复该过程 - 将 matrixID 设置为对象的MVP,绑定顶点缓冲区,设置属性指针并绘制它:

    glUniformMatrix4fv(matrixID, 1, GL_FALSE, &triMVP[0][0]);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, triangleVerteciesBuffer);

    glVertexAttribPointer(
            0,      // shader layout location
            3,
            GL_FLOAT,
            GL_FALSE,
            0,
            (void *)0
    );
    glDrawArrays(GL_TRIANGLES, 0, 3);   // draw triangle

相应的顶点着色器代码:

#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertecies_modelspace;

uniform mat4 MVP;

void main(){
    gl_Position = MVP * vec4(vertecies_modelspace, 1);
}

答案 1 :(得分:3)

OpenGL不是场景图。它根据当前状态绘制内容,然后忘记它。

因此,如果要绘制不同的几何图形,使用不同的变换只需设置相应的变换矩阵(均匀),绘制对象并对要绘制的每个对象重复此操作。绘制几何体后,除了可能透支之外,以下操作对它没有进一步的影响。

答案 2 :(得分:2)

可能也有效的替代方法是在顶点着色器中进行“ModelViewProjection”矩阵计算。您可以通过在顶点着色器中生成统一的模型视图投影矩阵变量来实现此目的。然后,您可以全局计算视图投影矩阵,并将它们发送到着色器。然后,您可以单独计算立方体和三角形(或任何需要渲染的对象)的模型矩阵,并将这些模型矩阵也发送到着色器。

视图和投影矩阵计算;这可能是一个单独的“相机”类:

glm::mat4 viewMatrix = glm::lookAt(
  glm::vec3(0, -5, 0), // camera location in world
  glm::vec3(0, 0, 0), // point camera is looking at
  glm::vec3(0, 1, 0) // orientation of camera, change 1 to -1 to flip camera upside down
);

glm::mat4 projectionMatrix = glm::perspective(35.0f, displayWidth / displayHeight, 0.1f, 100.0f);

// send view and projection matrices to the shader
glUseProgram(shaderProgram);
GLint viewMatrixId = glGetUniformLocation(shaderProgram, "view");
GLint projectionMatrixId = glGetUniformLocation(shaderProgram, "projection");

glUniformMatrix4fv(viewMatrixId, 1, GL_FALSE, &viewMatrix[0][0]);
            glUniformMatrix4fv(projectionMatrixId, 1, GL_FALSE, &projectionMatrix[0][0]);
glUseProgram(0);

模型矩阵计算;此代码可以放在一个单独的类中,您可以为要呈现的每个对象实例化它:

// this can go after where you initialize your cube or triangle vertex information
glUseProgram(shaderProgram);
modelMatrixId = glGetUniformLocation(shaderProgram, "model"); //modelMatrixId can be a global GLint
glUniformMatrix4fv(modelMatrixId, 1, GL_FALSE, &modelMatrix[0][0]); //modelMatrix can be a global glm::mat4
glUseProgram(0);

//use this for every render frame
glUseProgram(shaderProgram);
glUniformMatrix4fv(modelMatrixId, 1, GL_FALSE, &modelMatrix[0][0]);

// code to bind vertices and draw you objects goes here

glUseProgram(0);

新顶点着色器:

//vertex shader
#version 330 core

layout(location = 0) in vec3 vertices;

uniform mat4 model, view, projection;

void main(){

     gl_Position =  projection * view * model * vec4(vertices, 1.0);

}

答案 3 :(得分:0)

有两个顶点数组。让我们说array1 for cube,array2 for circle。 创建2个vaos和2个vbos。 vao1和vbo1 for cube。圆圈的vao2和vbo2。

绑定vao1,绑定vbo1,用array1填充vbo1缓冲区。 glUserProgram(program)是着色器程序,设置vertexattripointer。

调用glDrawArray()

对其他vao和vbo做同样的事情。