Im a bit stuck when it comes to rotation and translation in OpenGL.
I got 3 Matrices, projection, view and model.
My VertexShader:
gl_Position = projection * model * view * vec4(vertexData, 1);
What is the best way to translate and rotate objects?
Either multiply my model matrix with a translation and or rotation matrix, or pass data (rotation and translation) to the shader and to the math there?
Also I need to know "the final object position" for my mousepicking implementation.
What I did so far was something like this:
object.Transformation = Matrix.CreateTransLation(x,y,z) * Matrix.CreateRotation(x,y,z);
...
ForEach object to Draw
{
modelMatrix.Push();
modelMatrix.Mult(object.Transformation); // this also updates the matrix for the shader
object.Draw();
modelMatrix.Pop();
}
This works, but it doesnt feel right. What the best way to do this?
This
gl_Position = projection * model * view * vec4(vertexData, 1);
is wrong. Matrix multiplication is not commutative, i.e. the order of operations matters. The transformations on a vertex' position, in order are:
Matrix multiplication for column vectors as used by OpenGL is left associative, i.e. goes from right to left. Hence the expression in the R side of the statement should be
gl_Position = projection * view * model * vec4(vertexPosition, 1);
However you can contract view and model transform into a compound modelview (first model, then view) transform. This saves a full matrix multiplication
gl_Position = projection * modelview * vec4(vertexPosition, 1);
The projection should be kept separate as other shading steps may require the eye space position of the vertex which is the result of modelview * position
without projection applied.
BTW: You're transforming the vertex position, not the data. A vertex consists a larger number of attributes (not just the position) hence calling it "Data" is semantically wrong.
What is the best way to translate and rotate objects?
Those are part of the modelview transform. You should create a transformation matrix exactly one time on the CPU and pass it to the GPU. Doing this in the shader would force the GPU to redo the whole calculation for each and every vertex. You don't want to do this.
Let's say you're using my →linmath.h. Then in your drawing function you'd have set up the scaffolding for your scene, i.e. set the viewport, built projection and view matrices
#include <linmath.h>
/* ... */
void display(void)
{
mat4x4 projection;
mat4x4 view;
glClear(…),
glViewport(…);
mat4x4_frustum(projection, …);
// linmath.h doesn't have a look_at function... yet
// I'll add it soon
mat4x4_look_at(view, …);
Then for each object you have a position and a orientation (translation and rotation). Orientations are stored most conveniently in a quaternion, but for processing vectors a matrix representation works better. So we iterate over the objects in the scene
for(int i_object = 0; i_object < scene->n_objects; i++) {
Object * const obj = scene->objects + i;
mat4x4 translation, orientation, model_view;
mat4x4_translate(translation, obj->pos.x, obj->pos.y, obj->pos.z);
mat4x4_from_quat(orientation, obj->orientation);
mat4x4_mul(model_view, translation, orientation);
model_view
now contains the model matrix. Next we multiply the view
matrix on it. Remember, matrix multiplication is right to left (mat4x4_mul can output onto one of its input operands).
mat4x4_mul(model_view, view, model_view);
Now model_view
contains the full compount model orientation and translation and view matrix. All we need to do now is binding the shader program used for the object
glUseProgram(obj->shader->program);
Set the uniforms
glUniformMatrix4f(obj->shader->location.projection, 1, GL_FALSE, projection);
glUniformMatrix4f(obj->shader->location.modelview, 1, GL_FALSE, model_view);
// and a few others...
And draw the object
object_draw(obj);
}
/* ... */
}