5

Part of my code stores the equivalent of a 4x3 matrix, by storing an xyz position, an xyz scale, and a quaternion. Code snippet below:

class tTransform
{

    // data
    tVector4f    m_Position;
    tQuaternion  m_Rotation;
    tVector4f    m_Scale;

};

I want to multiply 2 of these objects together, (as though it were a matrix multiply), and am wondering if there is a faster/better way to do it than to convert each to a matrix, do the multiply that way, and then extract the resulting position, rotation and scale back out again?

Hybrid
  • 396
  • 4
  • 20
  • Thanks for the response :) I couldn't help thinking that doing matrix-to-quat, quat-to-matrix, plus getting the lengths of the XYZ axes of the resulting matrix for the new scales wasn't the best way. I guess I can skip the scale part with a couple of checks though. – Hybrid Dec 21 '11 at 18:58
  • If you know a better solution by hand you can overload the multiply operator on matrix quaternion – ted Dec 21 '11 at 18:58
  • I think the lack of answers suggest I'm attacking my problem in completely the wrong way to begin with.. back to the drawing board I think! :) – Hybrid Dec 21 '11 at 19:07
  • @CharlesBeattie Interesting... I've reworked my implementation to not need a solution to this, but I'd still be curious to hear a solution? – Hybrid Dec 23 '11 at 08:45
  • There you go. I don't trust the scale much as I'm only used too skeletal animation. – Charles Beattie Jan 07 '12 at 16:58

3 Answers3

3

Health warning as this is from memory and completely untested. You need to define or replace operators for tQuaternions and tVector4s.

class tTransform
{

    // data
    tVector4f    m_Position;
    tQuaternion  m_Rotation;
    tVector4f    m_Scale;

public:
    // World = Parent * Local (*this == parent)
    tTransform operator * (const tTransform& localSpace)
    {
        tTransform worldSpace;
        worldSpace.m_Position = m_Position + 
                                m_Rotation * (localSpace.m_Position * m_Scale);
        worldSpace.m_Rotation = m_Rotation * localSpace.m_Rotation;
        worldSpace.m_Scale = m_Scale * (m_Rotation * localSpace.m_Scale);
        return worldSpace;
    }

    // Local = World / Parent (*this = World)
    tTransform operator / (const tTransform& parentSpace)
    {
        tTransform localSpace;
        tQuaternion parentSpaceConjugate = parentSpace.m_Rotation.conjugate(); 
        localSpace.m_Position = (parentSpaceConjugate * 
                                (m_Position - parentSpace.m_Position)) /
                                parentSpace.m_Scale;

        localSpace.m_Rotation = parentSpaceConjugate * m_Rotation;

        localSpace.m_Scale = parentSpaceConjugate *
                             (m_Scale / parentSpace.m_Scale);
        return localSpace;
    }
};
Charles Beattie
  • 5,739
  • 1
  • 29
  • 32
1

I gave an answer to Tomas's question, which I will copy here as well since it answers your question too. The answer is almost pseudo-code, so you should be able to apply it to your class. You didn't specify which order your matrices would get built with (TRS, or SRT) so I assumed TRS. (your vectors are columns)

transform transform::operator * (const transform &other) const
{
    // mat1 = T1 * R1 * S1; mat2 = T2 * R2 * S2
    // mat = mat1 * mat2; mat*v = mat1 * mat2 * v
    // assuming "this" is mat1, and other is mat2
    // alternatively "this" can be considered parent, and other child in a node hierarchy
    transform r;
    // R = R1 * R2
    r.orientation = orientation * other.orientation;
    // Note: I don't know how to implement inverse of quat in your lib
    // S = R2^-1 * (S1 * (R2 * S2))
    r.scale = inverse(other.orientation) * (scale * (other.orientation * other.scale));
    // T = T1 * (R1 * (S1 * T2))
    r.position = position + (orientation * (scale * other.position));
    return r;
}

You can learn how to rotate a vector by a quaternion here: https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion

Petar
  • 63
  • 1
  • 5
  • Do you know by any chance how to reverse the scale from world space to local space? I'm having trouble resolving the equation for `S2 =`. – Cyphall Mar 09 '21 at 22:53
  • I think I found it: `LS = LR^-1 * ((LR * WS) / PS)` with LS=LocalScale, LR=LocalRotation, WS=WorldScale and PS=ParentScale. Posting it here for future reference. – Cyphall Mar 12 '21 at 00:14
0

I am told that this is not possible in general case. See https://gamedev.stackexchange.com/questions/167287/combine-two-translation-rotation-scale-triplets-without-matrices

The problem is that the structure cannot represent shear, which might be needed after combining rotations and non-uniform scaling.

Please, correct me if I am wrong.

Tomas
  • 105
  • 7