1
votes

I am woring on a C++ OpengL program and GLSL Vertex and Fragment shaders.

I am creating several instances of the same object. I just have to change object position between instances.

Here is what i've done: I am working with an uniform variable which is an array of transformation matrix. Each matrix stands for an object instance.

MVP is a transformation matrix too but MVP is set by camera position, orientation and properties.

Here is my vertex shader:

    #version 330 core
    layout(location = 0) in vec3 vertex_position;
    layout(location = 1) in vec3 vertex_color;

    uniform mat4 object_positions[20];
    out vec3 fragment_color;
    uniform mat4 MVP;

    void main()
    {
        gl_Position = object_positions[gl_InstanceID] * MVP * vec4(vertex_position,1.0);
        fragment_color = vertex_color;
    }

Here is what i have to do in C++ program to set objects positions:

    glm::mat4 object_positions[20];
    object_positions[0] = glm::translate(glm::mat4(1), glm::vec3(0.4f,0.2f,0.0f));
    object_positions[1] = glm::translate(glm::mat4(1), glm::vec3(0.5f,1.4f,0.0f));
    ...
    object_positions[19] = glm::translate(glm::mat4(1), glm::vec3(-10.6f,0.2f,0.0f)); 
    GLuint object_positions_id = glGetUniformLocation(program_id, "object_positions");
    ...
    glUniformMatrix4fv(object_positions_id, 7, GL_FALSE, glm::value_ptr(object_positions[0]));

The vec3 you see as second argument of glm::translate contains each object position. Every thing works fine at this point.

What i want to do is to compute of glm::translte in shader. What i want in fact is to send a vec3 instead of a mat4 for each position. I want the GPU to compute the transformation matrix instead of the CPU. Everything i tried does not work.

Thanks

3
No it does not work. It is exactly the same result. object_positions should be a transformation matrix in this case, not a positionBob5421
Why do you want a matrix when just adding the offset is much simpler and faster?Nico Schertler
Yes this is a great idea but what should i put in w ?Bob5421
This is strange, i tried to add this w=0 and the positions seems to be divide per 2Bob5421
Why would you want to set w=0? You leave w alone. Your input w is guaranteed to be 1.0 with that shader anyway, so you can directly apply an offset in xyz.derhass

3 Answers

4
votes

A 4*4 matrix looks like this:

  c0  c1  c2  c3            c0  c1  c2  c3
[ Xx  Yx  Zx  Tx ]        [  0   4   8  12 ]     
[ Xy  Yy  Zy  Ty ]        [  1   5   9  13 ]     
[ Xz  Yz  Zz  Tz ]        [  2   6  10  14 ]     
[  0   0   0   1 ]        [  3   7  11  15 ] 

In GLSL the columns of a mat4 m; are addressed like this:

vec4 c0 = m[0].xyzw;
vec4 c1 = m[1].xyzw;
vec4 c2 = m[2].xyzw;
vec4 c3 = m[3].xyzw;

You can set up a mat4 in the vertex shader like this:

#version 330 core
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec3 vertex_color;

out vec3 fragment_color;
uniform mat4 MVP;

uniform vec3 object_positions[20];

void main()
{
    mat4 posMat = mat4(
        vec4( 1.0, 0.0, 0.0, 0.0),
        vec4( 0.0, 1.0, 0.0, 0.0),
        vec4( 0.0, 0.0, 1.0, 0.0),
        vec4( object_positions[gl_InstanceID], 1.0) );

    gl_Position = MVP * posMat * vec4(vertex_position,1.0);
    fragment_color = vertex_color;
}


But if you only want to manipulate the vertex position by an offset, then you don't need a transformation matrix. You can simply add the offset to the vertex position (provided the offset is an cartesian coordinate and not a homogeneous coordinate, as in your case):

void main()
{
    gl_Position = MVP * vec4(object_positions[gl_InstanceID] + vertex_position, 1.0);
    fragment_color = vertex_color;
}


And you have to set up the uniform like this:

glm::vec3 object_positions[20];
object_positions[0] = glm::vec3(0.4f,0.2f,0.0f);
object_positions[1] = glm::vec3(0.5f,1.4f,0.0f);
...
object_positions[19] = glm::vec3(-10.6f,0.2f,0.0f); 
GLuint object_positions_id = glGetUniformLocation(program_id, "object_positions");
...
glUniform3fv(object_positions_id, 20, glm::value_ptr(object_positions[0]));


See further:

1
votes

For OpenGL transformation matrix is just one dimensional array of 16 entries (Speaking of 4X4 matrix) . In this matrix 13th, 14th ,15th entry defines your translation component. So If you are storing matrices in row major form 4th row 0th,1st and 2nd entry should be the vector x, y, z component you are sending to shader. You can build your translation matrix in shader this way. Please be sure If you are having row major matrix then to transform vertex you premultiply by matrix to see the effect of translation.

   gl_Position = Translation Matrix * gl_Vertex;

If your matrix is column major you will post multiply.

0
votes

You absolutely cannot do object_positions[gl_InstanceID] * MVP * vec4(vertex_position,1.0); (even if the object_positions were matrices) because that would be translating AFTER the projection matrix has been applied.

If you're not doing any rotation of the instances, there's no reason not to just do this

 gl_Position = MVP * vec4(vertex_position + object_positions[gl_InstanceID],1.0);