Разница между двумя кватернионами

решаемая

Я создаю систему трехмерного портала в моем движке (как игра Portal). Каждый из порталов имеет свою ориентацию, сохраненную в кватернионе. Для рендеринга виртуальной сцены на одном из порталов мне нужно вычислить разницу между двумя кватернионами и использовать результат для поворота виртуальной сцены.

При создании первого портала на левой стене и второго на правой стене вращение от одного к другому будет происходить только по одной оси, но, например, когда первый портал будет создан на полу, а второй - на правой стене вращение от одного к другому может происходить по двум осям, и это проблема, потому что вращение идет не так.

Я думаю, что проблема существует, потому что ориентация, например,X ось иZ Оси хранятся вместе в одном кватернионе, и мне нужно отдельно, чтобы вручную умножитьX * Z (или жеZ * X), но как это сделать только с одним кватернионом (разница кватернионов)? Или есть другой способ исправить поворот сцены?

РЕДАКТИРОВАТЬ:

Здесь на этом рисунке два портала P1 и P2, стрелки показывают, как они вращаются. Поскольку я смотрю в P1, я увижу то, что видит P2. Чтобы найти вращение, в котором мне нужно повернуть основную сцену, чтобы она была похожа на виртуальную сцену на этом рисунке, я делаю следующее:

Получение разности от кватерниона P2 к кватерниону P1Результат поворота на 180 градусов по оси Y (портал вверх)Использование результата для поворота виртуальной сцены

Этот метод выше работает только тогда, когда разница имеет место только по одной оси. Когда один портал будет находиться на полу или на потолке, это не будет работать, поскольку разностный кватернион встроен более чем в одну ось. Как и предполагалось, я пытался умножить кватернион P1 на кватернион P2, и наоборот, но это не работает.

РЕДАКТИРОВАТЬ 2:

Чтобы найти разницу от P2 до P1, я делаю следующее:

Quat q1 = P1->getOrientation();
Quat q2 = P2->getOrientation();

Quat diff = Quat::diff(q2, q1);  // q2 * diff = q1 //

Вот функция Quat :: diff:

GE::Quat GE::Quat::diff(const Quat &a, const Quat &b)
{
    Quat inv = a;
    inv.inverse();
    return inv * b;
}

Inverse:

void GE::Quat::inverse()
{
    Quat q = (*this);
    q.conjugate();
    (*this) = q / Quat::dot((*this), (*this));
}

Сопряженные:

void GE::Quat::conjugate()
{
    Quat q;
    q.x = -this->x;
    q.y = -this->y;
    q.z = -this->z;
    q.w = this->w;

    (*this) = q;
}

Скалярное произведение:

float GE::Quat::dot(const Quat &q1, const Quat &q2)
{
    return q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
}

Оператор *:

const GE::Quat GE::Quat::operator* ( const Quat &q) const
{
    Quat qu;
    qu.x = this->w*q.x + this->x*q.w + this->y*q.z - this->z*q.y;
    qu.y = this->w*q.y + this->y*q.w + this->z*q.x - this->x*q.z;
    qu.z = this->w*q.z + this->z*q.w + this->x*q.y - this->y*q.x;
    qu.w = this->w*q.w - this->x*q.x - this->y*q.y - this->z*q.z;
    return qu;
}

Оператор /:

const GE::Quat GE::Quat::operator/ (float s) const
{
    Quat q = (*this);
    return Quat(q.x / s, q.y / s, q.z / s, q.w / s);
}

Все это работает, потому что я проверил это сGLM библиотека

Ответы на вопрос(5)

Ваш ответ на вопрос