<p>Update the uniform and draw again.</p>

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

tMVP = glm::translate(MVP, glm::vec3(2,0,0));
glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, &amp;MVP[0][0]);
gluSphere(...);
</code></pre>

<p>Using <code>glTranslate</code> would have done the <em>exact same thing</em> behind the scenes.</p>

<hr>

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

<p>However the more portable way involves allocating a vertex attribute for the data. This involves using <code>glVertexAttribDivisor</code>.</p>

<p>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.</p>

CC BY-SA 4.0
2019-08-13T10:32:55.080Z
Cool!, I didn't know that the variables could be different for each vertices in the same pass. This worked for me.
seilgu
CC BY-SA 4.0
2019-08-13T14:57:27.837Z
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.
seilgu
CC BY-SA 4.0
2019-08-13T15:46:49.400Z
you need a depth buffer to do proper per fragment depth testing.
ratchet freak
CC BY-SA 4.0
2019-08-13T18:17:13.733Z
Found the culprit. It's because my perspective zNear was set to 0.
seilgu
CC BY-SA 4.0
2019-08-13T08:45:07.247Z
2019-08-13T08:45:07.247Z
ratchet freak
<p>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? </p>

<p>For example I wanted to do something like this :</p>

<pre><code>glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
{
    shader.bind();

    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;
    GLint loc_MVP = glGetUniformLocation(shader.id(), "MVP");    
    glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, &amp;MVP[0][0]);

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

    shader.unbind();
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
</code></pre>

<p>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?</p>

<p>The vertex shader looks like this :</p>

<pre><code>#version 330 core

uniform mat4 MVP;
in vec3 in_Position;

void main(void) {
    gl_Position = MVP * vec4(in_Position, 1.0);
}
</code></pre>

CC BY-SA 4.0
2019-08-13T07:14:29.650Z
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. https://learnopengl.com/Advanced-OpenGL/Instancing
gallickgunner
<opengl><shader><transformations>
Use glTranslatef and shaders?
seilgu
# Use glTranslatef and shaders?

(Asked by: username_0 on 2019-08-13)

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);
{
    shader.bind();

    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;
    GLint loc_MVP = glGetUniformLocation(shader.id(), "MVP");    
    glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, &MVP[0][0]);

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

    shader.unbind();
}
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);
}

```

**Tags:** opengl, shader, transformations

> **Comments:**
> **username_1**: 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. https://learnopengl.com/Advanced-OpenGL/Instancing  

---

## 1 answers

### Answer by username_2 on 2019-08-13. Score: 1 | Accepted answer

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.

> **Comments:**
> **username_0**: Cool!, I didn't know that the variables could be different for each vertices in the same pass. This worked for me.  
> **username_0**: 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.  
> **username_2**: you need a depth buffer to do proper per fragment depth testing.  
> **username_0**: Found the culprit. It's because my perspective zNear was set to 0.  

---

