Silverlan
Silverlan

Reputation: 2911

glm - Decompose mat4 into translation and rotation?

For purposes of lerping I need to decompose a 4x4 matrix into a quaternion and a vec3. Grabbing the quaternion is simple, as you can just pass the matrix into the constructor, but I can't find a way to grab the translation. Surely there must be a way?

Upvotes: 31

Views: 41178

Answers (6)

tuket
tuket

Reputation: 3941

I made my own decompose function that doesn't need "skew" and "perspective" components.

void decomposeMtx(const glm::mat4& m, glm::vec3& pos, glm::quat& rot, glm::vec3& scale)
{
    pos = m[3];
    for(int i = 0; i < 3; i++)
        scale[i] = glm::length(vec3(m[i]));
    const glm::mat3 rotMtx(
        glm::vec3(m[0]) / scale[0],
        glm::vec3(m[1]) / scale[1],
        glm::vec3(m[2]) / scale[2]);
    rot = glm::quat_cast(rotMtx);
}

If you don't need scale either, it can be further simplified:

void decomposeMtx(const glm::mat4& m, glm::vec3& pos, glm::quat& rot)
{
    pos = m[3];
    rot = glm::quat_cast(m);
}

Upvotes: 8

valmo
valmo

Reputation: 1174

It looks like glm 0.9.6 supports matrix decomposition http://glm.g-truc.net/0.9.6/api/a00204.html

#include <glm/gtx/matrix_decompose.hpp>

glm::mat4 transformation; // your transformation matrix.
glm::vec3 scale;
glm::quat rotation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(transformation, scale, rotation, translation, skew, perspective);

Upvotes: 37

Michael IV
Michael IV

Reputation: 11436

Sorry for being late. Actually the reason you have to conjugate the result quat is wrong substraction order of matrix components when calculating x,y,z components of the quaternion.

Here is an explanation and sample code of how it should be.

So basically in glm, decompose() method, matrix_decompose.inl file:

We have :

    orientation.x = root * (Row[1].z - Row[2].y);
    orientation.y = root * (Row[2].x - Row[0].z);
    orientation.z = root * (Row[0].y - Row[1].x);

When it should be:

    orientation.x = root * (Row[2].y - Row[1].z);
    orientation.y = root * (Row[0].z - Row[2].x);
    orientation.z = root * (Row[1].x - Row[0].y);

Also see this impl which looks very close to the one found in GLM,but which is correct one.

Upvotes: 3

Travis Vroman
Travis Vroman

Reputation: 374

I figured I'd post an updated and complete answer for 2019. Credit where it's due, this is based off valmo's answer, includes some items from Konstantinos Roditakis's answer as well as some additional info I ran into.

Anyway, as of version 0.9.9 you can still use the experimental matrix decomposition: https://glm.g-truc.net/0.9.9/api/a00518.html

First, and the part I am adding because I don't see it anywhere else, is that you will get an error unless you define the following before the include below:

#define GLM_ENABLE_EXPERIMENTAL

Next, you have to include:

#include <glm/gtx/matrix_decompose.hpp>

Finally, an example of use:

glm::mat4 transformation; // your transformation matrix.
glm::vec3 scale;
glm::quat rotation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(transformation, scale, rotation, translation, skew,perspective);

Also, the Quaternion, as stated in Konstantinos Roditakis's answer, is indeed incorrect and can be fixed by applying the following:

rotation = glm::conjugate(rotation);

Upvotes: 12

Konstantinos Roditakis
Konstantinos Roditakis

Reputation: 605

At version glm-0.9.8.1 you have to include:

#include <glm/gtx/matrix_decompose.hpp>

To use it:

glm::mat4 transformation; // your transformation matrix.
glm::vec3 scale;
glm::quat rotation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(transformation, scale, rotation, translation, skew,perspective);

Keep in mind that the resulting quaternion in not correct. It returns its conjugate!

To fix this add this to your code:

rotation=glm::conjugate(rotation);

Upvotes: 23

kerim
kerim

Reputation: 2512

glm::vec3(m[3]) is the position vector(assuming m is glm::mat4)

Upvotes: 40

Related Questions