Question

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?

Was it helpful?

Solution 2

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

OTHER TIPS

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

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

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

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.

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);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top