Матричное умножение с компонентами положения, кватерниона и масштаба

Часть моего кода хранит эквивалент матрицы 4x3, сохраняя позицию xyz, масштаб xyz и кватернион. Фрагмент кода ниже:

class tTransform
{

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

};

Я хочу умножить 2 из этих объектов вместе (как если бы это было умножение матрицы), и мне интересно, есть ли более быстрый/лучший способ сделать это, чем преобразовать каждый в матрицу, выполнить умножение таким образом, а затем извлечь полученное положение, повернуть и снова уменьшить масштаб?


person Hybrid    schedule 21.12.2011    source источник
comment
Спасибо за ответ :) Я не мог отделаться от мысли, что делать матрицу-в-квадрат, кватер-в-матрицу, плюс получать длины осей XYZ результирующей матрицы для новых масштабов было не лучшим способом. Думаю, я могу пропустить часть масштаба с парой проверок.   -  person Hybrid    schedule 21.12.2011
comment
Если вы знаете лучшее решение вручную, вы можете перегрузить оператор умножения на матричный кватернион.   -  person ted    schedule 21.12.2011
comment
Я думаю, что отсутствие ответов предполагает, что я атакую ​​свою проблему совершенно неправильным образом с самого начала ... вернемся к чертежной доске, я думаю! :)   -  person Hybrid    schedule 21.12.2011
comment
@CharlesBeattie Интересно ... Я переработал свою реализацию, чтобы не нуждаться в решении этой проблемы, но мне все равно было бы любопытно услышать решение?   -  person Hybrid    schedule 23.12.2011
comment
Ну вот. Я не очень доверяю масштабу, так как использую слишком скелетную анимацию.   -  person Charles Beattie    schedule 07.01.2012


Ответы (3)


Предупреждение о вреде для здоровья, так как это из памяти и полностью не проверено. Вам необходимо определить или заменить операторы для tQuaternions и 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;
    }
};
person Charles Beattie    schedule 07.01.2012

Я дал ответ на вопрос Томаса, который я также скопирую сюда, поскольку он также отвечает на ваш вопрос. Ответ почти псевдокод, поэтому вы сможете применить его к своему классу. Вы не указали порядок построения ваших матриц (TRS или SRT), поэтому я предположил TRS. (ваши векторы - столбцы)

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

Вы можете узнать, как повернуть вектор на кватернион, здесь: https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion

person Petar    schedule 22.04.2020
comment
Вы случайно не знаете, как изменить масштаб с мирового пространства на локальное? У меня возникли проблемы с решением уравнения для S2 =. - person Cyphall; 10.03.2021
comment
Кажется, я нашел это: LS = LR^-1 * ((LR * WS) / PS) с LS=LocalScale, LR=LocalRotation, WS=WorldScale и PS=ParentScale. Публикация здесь для дальнейшего использования. - person Cyphall; 12.03.2021

Мне говорят, что это невозможно в общем случае. См. https://gamedev.stackexchange.com/questions/167287/combine-two-translation-rotation-scale-triples-without-matrices

Проблема в том, что структура не может представлять сдвиг, который может понадобиться после объединения поворотов и неравномерного масштабирования.

Пожалуйста, поправьте меня, если я ошибаюсь.

person Tomas    schedule 28.07.2019
comment
Хотите объяснить отрицательный голос? Я бы очень хотел подтверждения, какой ответ правильный? - person Tomas; 17.09.2019