Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL rotation and translation done correctly

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?

like image 899
CSharpie Avatar asked Dec 29 '12 17:12

CSharpie


People also ask

Does it matter what order you translate and rotate?

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.

Does rotation affect translation?

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.

How do you combine translation and rotation?

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.

How do you translate and rotate a coordinate system?

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.


1 Answers

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:

  • model
  • view
  • projection

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.

Update due to comment

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);
    }

/* ... */

}
like image 102
datenwolf Avatar answered Oct 21 '22 06:10

datenwolf