Reputation: 9153
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
Upvotes: 2
Views: 3832
Reputation: 872
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.
Upvotes: 1
Reputation: 211166
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:
Upvotes: 6
Reputation: 29240
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);
Upvotes: 0