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?
In a composite transformation, the order of the individual transformations is important. For example, if you first rotate, then scale, then translate, you get a different result than if you first translate, then rotate, then scale.
Basics of Transformations You are affecting its coordinate system. So a rotation rotates the x and y axes. If you have a transform that rotates 45 degrees and then apply a translate 100 pixels to the right, the translation will not go to the true right.
A rotation matrix and a translation matrix can be combined into a single matrix as follows, where the r's in the upper-left 3-by-3 matrix form a rotation and p, q and r form a translation vector. This matrix represents rotations followed by a translation.
Coordinate systems can also be translated and rotated in space: In a translation, the origin is simply shifted in the x, y and z directions. The associated (x,y,z) number is called translation vector. In a rotation, the coordinate system is rotated around the x, y and z axes.
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);
}
/* ... */
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With