How to display 2 or more objects in openGL (model - representation - projection matrices and shaders)

Everything is fine when I want to draw a single object, such as a cube. I create vertices for the cube, create a buffer, create an MVP matrix and send it to the shader, and it works well.

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

//Example (using GLM): glm::mat4 MVPC = Projection * View * ModelCube; glm::mat4 MVPT = Projection * View * ModelTriangle; 

So what am I doing with these two now? This is a vertex shader that works well for a 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 the MVPT (triangle) in the shader, I tried to mess with different things, but I can’t make it work, I can not display the cube and the triangle at the same time.

+6
source share
4 answers

The confusion comes from the fact that the shader controls several arrays of vertices immediately when it should be considered as a universal entity. The vertex array is passed to the shader, then the object is drawn. And the process is repeated.

For example, suppose we assign the variable matrixID to uniform MVP:

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

When we are ready to draw an object, we set matrixID to an MVP object:

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

Then bind the vertex buffer, set the pointer to the attribute 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 go to the triangle and repeat the process - set the matrixID to the MVP object, 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 

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); } 
+7
source

OpenGL is not a scene graph. He 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 an object and repeat this for each object that you want to draw. After the geometry is drawn, the following operations will not have any further effect on it, except that it can be overloaded.

+3
source

An alternative that might also work would be to do the calculation of the "ModelViewProjection" matrix in the vertex shader. You can do this by creating single variable matrixes of the model , view and projection in the vertex shader. Then you can globally calculate the view matrices and projections and send them to the shader. Then you can simply calculate the model matrix for your cube and triangle (or any objects that need to be visualized) individually, and send these matrix models to the shader.


View and calculate matrix matrix; it can be in a separate class "camera":

 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); 

Calculation of the model matrix; this code can go in a separate class, and you can create it for each object that you want to display:

 // 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); 

New vertex shader:

 //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); } 
+2
source

They have two vertex arrays. Let's say array1 for a cube, array2 for a circle. Create 2 vaos and 2 vbos. vao1 and vbo1 for the cube. vao2 and vbo2 for the circle.

Bind vao1, bind vbo1, fill the buffer vbo1 with array1. glUserProgram (program), which is a program for shaders, configure vertexattripointer.

call glDrawArray ()

Do the same for other vao and vbo.

0
source

Source: https://habr.com/ru/post/909660/


All Articles