pixartist
pixartist

Reputation: 1155

Can't identify error in my matrix calculation?

So, I tried to use matrices in OpenTK, my "Transform" class has a Rotation (a quaternion) and a Vector3 for the position. It offers the folling fields:

    public virtual Vector3 Right
    {
        get
        {
            
            return Vector3.Transform(Vector3.UnitX, Rotation);
        }
    }
    public virtual Vector3 Forward
    {
        get 
        {
            return Vector3.Transform(-Vector3.UnitZ, Rotation);
        }
    }
    public virtual Vector3 Up
    {
        get
        {
            return Vector3.Transform(Vector3.UnitY, Rotation);
        }
    }

This is how the view and model matrices are creates:

    public virtual Matrix4 GetMatrix()
    {
        Matrix4 translation = Matrix4.CreateTranslation(Position);
        Matrix4 rotation = Matrix4.CreateFromQuaternion(Rotation);
        return translation * rotation;
    }

Projection:

    private void SetupProjection()
    {
        if(GameObject != null)
        {
            AspectRatio = GameObject.App.Window.Width / (float)GameObject.App.Window.Height;
            projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)((Math.PI * Fov) / 180), AspectRatio, ZNear, ZFar);
            
        }
    }

Matrix multiplication:

    public Matrix4 GetModelViewProjectionMatrix(Transform model)
    {
        return  model.GetMatrix()* Transform.GetMatrix() * projectionMatrix;
    }

Shader:

[Shader vertex]
#version 150 core

in vec3 pos;
in vec4 color;
uniform float _time;
uniform mat4 _modelViewProjection;

out vec4 vColor;

void main() {
    gl_Position = _modelViewProjection * vec4(pos, 1);
    vColor = color;
}

OpenTK matrices are transposed, thus the multiplication order.

The problem with this setup is, that all axis and the direction vectors as well object position are mixed up, mirrored and turned upside down.

Now after a lot of fiddling, I managed to get a useful transformation and ended up with the following:

I had to invert the quaternion for the directions:

    public virtual Vector3 Right
    {
        get
        {
            
            return Vector3.Transform(Vector3.UnitX, Rotation.Inverted());
        }
    }
    public virtual Vector3 Forward
    {
        get
        {
            return Vector3.Transform(-Vector3.UnitZ, Rotation.Inverted());
        }
    }
    public virtual Vector3 Up
    {
        get
        {
            return Vector3.Transform(Vector3.UnitY, Rotation.Inverted());
        }
    }

And I had to modify the view matrix construction like this:

    public virtual Matrix4 GetMatrixView()
    {
        Matrix4 translation = Matrix4.CreateTranslation(Position*2).Inverted();
        Matrix4 rotation = Matrix4.CreateFromQuaternion(Rotation);
        return translation * rotation;
    }

As you can see, I had to invert the translation matrix and multiply the position by two, to make the camera space match the worldspace. What the F ?

Edit: look at this. With the default/intuitional setup I get this:

[LOG]: (0; 0; 10) ->

[LOG]: FW(0; 0; -1)

[LOG]: R(-1; 0; 0)

[LOG]: UP(0; 1; 0)

Okay, I'm at Z 10, looking at 0,0,0. Forward is x -1, as expected. Up is Y 1, also okay. But the horizontal axis goes to the LEFT ? What kind of coordinate system is this ?

Upvotes: 4

Views: 779

Answers (1)

kbirk
kbirk

Reputation: 4022

You mention that the matrices are transposed, hence why the multiplication order is reversed. For example your MVP calc is:

model.GetMatrix()* Transform.GetMatrix() * projectionMatrix;

But your translation * rotation concatenation is in wrong order:

Matrix4 translation = Matrix4.CreateTranslation(Position);
Matrix4 rotation = Matrix4.CreateFromQuaternion(Rotation);
return translation * rotation;

With non-transposed matrices the correct multiplcation order is:

translation * rotation * scale

So with your transposed matrices, it should be reversed to:

scale * rotation * translation

So your code should be:

Matrix4 translation = Matrix4.CreateTranslation(Position);
Matrix4 rotation = Matrix4.CreateFromQuaternion(Rotation);
return rotation * translation;

Upvotes: 2

Related Questions