In newer OpenGL it's encouraged to use shaders and pass the model-view-projection as parameters. But what if I drew a complex object, and wanted to translate/rotate it and draw many copies?

For example I wanted to do something like this :

glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
{

glm::mat4 projectionMatrix = glm::perspective(20.0f, (float)SCRWIDTH/(float)SCRHEIGHT, 0.0f, 100.0f);
glm::mat4 viewMatrix = glm::lookAt(
glm::vec3(0, 0, 2),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
glm::mat4 modelMatrix = glm::toMat4(quaternion);
glm::mat4 MVP = projectionMatrix * viewMatrix * modelMatrix;
glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, &MVP[0][0]);

glTranslatef(1,0,0);
gluSphere(...);
glTranslatef(2,0,0);
gluSphere(...);

}
glBindFramebuffer(GL_FRAMEBUFFER, 0);


But my experiment shows that the glTranslatef doesn't work here, all the spheres are rendered at (0,0,0). I don't want to call the shader 100 times, each time calculating a different MVP matrix. Is there any easy way around this?

The vertex shader looks like this :

#version 330 core

uniform mat4 MVP;
in vec3 in_Position;

void main(void) {
gl_Position = MVP * vec4(in_Position, 1.0);
}

• This can be achieved through instancing and it's cheap. As in you won't be communicating with the cpu and back and forth hundred times. learnopengl.com/Advanced-OpenGL/Instancing Aug 13 '19 at 7:14

Update the uniform and draw again.

auto tMVP = glm::translate(MVP, glm::vec3(1,0,0));
glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, &tMVP[0][0]);
gluSphere(...);

tMVP = glm::translate(MVP, glm::vec3(2,0,0));
glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, &MVP[0][0]);
gluSphere(...);


Using glTranslate would have done the exact same thing behind the scenes.

You can instead use instancing instead where you upload all the transforms into a buffer and then tell the gpu to use that.

However the more portable way involves allocating a vertex attribute for the data. This involves using glVertexAttribDivisor.

So a full mat4 would need 4 vertex attributes. You can decrease that to 2 by separating out the translation as a vec3 and the rotation as a quaternion and pass the view-perspective as a uniform and combining it all in the vertex shader.

• Cool!, I didn't know that the variables could be different for each vertices in the same pass. This worked for me. Aug 13 '19 at 10:32
• Can you answer one more question? Does this work will depth culling? I drew 100 spheres near and far, but the far ones can sometimes block the near ones. Aug 13 '19 at 14:57
• you need a depth buffer to do proper per fragment depth testing. Aug 13 '19 at 15:46
• Found the culprit. It's because my perspective zNear was set to 0. Aug 13 '19 at 18:17