Kamisama
Kamisama

Reputation: 63

glm::decompose and then compose back again

I use glm::decompose (https://glm.g-truc.net/0.9.6/api/a00204.html) in a way similar to the following:

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

Now I would like to compose the matrix back again using all above properties. The thing is simple if all I have in my matrix are scale, rotation and translation (glm::scale, glm::rotate, glm::translate) but what interests me the most is the "skew" property. How can I apply all transformation to a new matrix so that after computation I would get the "matrix" back again?

Upvotes: 4

Views: 1779

Answers (2)

Thomas Perl
Thomas Perl

Reputation: 2348

Based on Bob's answer, a glm::recompose() would look something like this (with variable names from the question):

    glm::mat4 m = glm::mat4(1.f);

    m[0][3] = perspective.x;
    m[1][3] = perspective.y;
    m[2][3] = perspective.z;
    m[3][3] = perspective.w;

    m *= glm::translate(translation);
    m *= glm::mat4_cast(rotation);

    if (skew.x) {
        glm::mat4 tmp { 1.f };
        tmp[2][1] = skew.x;
        m *= tmp;
    }

    if (skew.y) {
        glm::mat4 tmp { 1.f };
        tmp[2][0] = skew.y;
        m *= tmp;
    }

    if (skew.z) {
        glm::mat4 tmp { 1.f };
        tmp[1][0] = skew.z;
        m *= tmp;
    }

    m *= glm::scale(scale);

Upvotes: 1

Bob
Bob

Reputation: 14654

As mentioned in the comments, the answer is in the source code, the last function in the file b, cited in a

Bring the function recompose

void TransformationMatrix::recompose(const DecomposedType& decomp)
{
    makeIdentity();
    
    // first apply perspective
    m_matrix[0][3] = (float) decomp.perspectiveX;
    m_matrix[1][3] = (float) decomp.perspectiveY;
    m_matrix[2][3] = (float) decomp.perspectiveZ;
    m_matrix[3][3] = (float) decomp.perspectiveW;
    
    // now translate
    translate3d((float) decomp.translateX, 
                (float) decomp.translateY, 
                (float) decomp.translateZ);
    
    // apply rotation
    double xx = decomp.quaternionX * decomp.quaternionX;
    double xy = decomp.quaternionX * decomp.quaternionY;
    double xz = decomp.quaternionX * decomp.quaternionZ;
    double xw = decomp.quaternionX * decomp.quaternionW;
    double yy = decomp.quaternionY * decomp.quaternionY;
    double yz = decomp.quaternionY * decomp.quaternionZ;
    double yw = decomp.quaternionY * decomp.quaternionW;
    double zz = decomp.quaternionZ * decomp.quaternionZ;
    double zw = decomp.quaternionZ * decomp.quaternionW;
    
    // Construct a composite rotation matrix from the quaternion values
    TransformationMatrix rotationMatrix(
      1 - 2 * (yy + zz), 2 * (xy - zw)    , 2 * (xz + yw)    , 0, 
      2 * (xy + zw)    , 1 - 2 * (xx + zz), 2 * (yz - xw)    , 0,
      2 * (xz - yw)    , 2 * (yz + xw)    , 1 - 2 * (xx + yy), 0,
      0                , 0                , 0                , 1);
    
    multLeft(rotationMatrix);
    //////////////////////////////////////////
    // THIS IS WHAT YOU ARE INTERESTED      //
    //////////////////////////////////////////
    // now apply skew
    if (decomp.skewYZ) {
        TransformationMatrix tmp;
        tmp.setM32((float) decomp.skewYZ);
        multLeft(tmp);
    }
    
    if (decomp.skewXZ) {
        TransformationMatrix tmp;
        tmp.setM31((float) decomp.skewXZ);
        multLeft(tmp);
    }
    
    if (decomp.skewXY) {
        TransformationMatrix tmp;
        tmp.setM21((float) decomp.skewXY);
        multLeft(tmp);
    }
    
    // finally, apply scale
    scale3d((float) decomp.scaleX, 
            (float) decomp.scaleY, 
            (float) decomp.scaleZ);

}

Upvotes: 1

Related Questions