Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do i display 2 or more objects in openGL (model - view - projection matrices and shaders)

It's all ok when i want to draw one object, for example a cube. I create vertices for cube, i create the buffer, i create the MVP matrix and send it to shader and it works nice.

But, what to do when i want to draw 2 or more objects, for example both cube and a triangle? I believe that View and Projection matrices should be same both for triangle and cube, i only need different Model matrix, right? So that means that i will have two MVPs?

//Example (using GLM):

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

So what do i do with those two now? This is the vertex shader that works good for cube

//vertex shader
#version 330 core

layout(location = 0) in vec3 verticesCube;

uniform mat4 MVPC;

void main(){

     gl_Position =  MVPC * vec4(verticesCube,1);

}

And what should i do with MVPT (triangle) in shader, i tried messing around with different things, but i can't get it to work, i can't display both the cube and the triangle at the same time.

like image 676
IanDess Avatar asked Feb 29 '12 17:02

IanDess


2 Answers

The confusion comes from thinking that the shader controls multiple vertex arrays at once, when it should be thought of as a universal entity. A vertex array is passed to the shader, then the object is drawn. And the process is repeated.

For example, let's say we assign the variable matrixID to the uniform MVP:

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

When we're ready to draw an object, we set matrixID to the object's MVP:

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

Then bind the vertex buffer, set the attribute pointer, and draw it:

    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

Now we move on to the triangle and repeat the process - set matrixID to the object's MVP, bind the vertex buffer, set the attribute pointer, and draw it:

    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

The corresponding vertex shader code:

#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);
}
like image 143
codesnip3r Avatar answered Oct 05 '22 10:10

codesnip3r


OpenGL is not a scene graph. It draws things according to the current state and then forgets about it.

So if you want to draw different geometries, with different transformations just set the corresponding transformation matrix (uniform), draw the object and repeat this for each object you want to draw. After geometry has been drawn, the following operations will have no further effect on it, other than it might be overdrawn.

like image 26
datenwolf Avatar answered Oct 05 '22 10:10

datenwolf