Матрица lookAt модели - C++, OpenGL

Мне удалось успешно реализовать матрицу lookAt для камеры, поскольку есть много источников, описывающих это.

Я пытался перевести это из lookAt камеры в lookAt модели. Я не могу заставить его работать, и я предполагаю, что у меня есть небольшое непонимание того, как строится матрица. Я полагаю, что мне не нужно изменять перевод для модели, чтобы посмотреть на точку, так как ее положение должно оставаться неизменным.

Прежде всего, вот соответствующий код. Функция lookAtRadians должна смотреть на указанную точку в той же системе координат, что и перевод (т.е. at - position = direction). Однако есть некоторые проблемы, которые я покажу на скриншотах. Он не проверяет, что direction.y() равен 1.0f или -1.0f, но это тривиально.

void TransformMatrix3D::lookAtRadians(float atX, float atY, float atZ, float toZRadians)
{
    Vector3D direction(atX - x(), atY - y(), atZ - z());
    direction.normalize();

    Vector3D up(0.0f, 1.0f, 0.0f);

    Vector3D right(direction.crossProduct(up));
    right.normalize();
    up = direction.crossProduct(right);

    mMatrix[0] = right.x();
    mMatrix[4] = right.y();
    mMatrix[8] = right.z();
    mMatrix[1] = up.x();
    mMatrix[5] = up.y();
    mMatrix[9] = up.z();
    mMatrix[2] = direction.x();
    mMatrix[6] = direction.y();
    mMatrix[10] = direction.z();
}

Вот функции cross product и normalize, на случай, если они неверны.

Vector3D Vector3D::crossProduct(const Vector3D& rightVector) const
{
    const float NEW_X(y() * rightVector.z() - z() * rightVector.y());
    const float NEW_Y(z() * rightVector.x() - x() * rightVector.z());
    const float NEW_Z(x() * rightVector.y() - y() * rightVector.x());

    return Vector3D(NEW_X, NEW_Y, NEW_Z);
}


void Vector3D::normalize()
{
    float length(x() * x() + y() * y() + z() * z());

    if(fabs(length) == 1.0f)
        return;

    length = 1.0f / sqrt(length);
    moveTo(x() * length, y() * length, z() * length);
}

Вот несколько скриншотов для описания моей проблемы. Белая сфера указывает на точку lookAt.

Я создал куб, сдвинутый на -10.0f вниз по оси Z (это установит mMatrix[12], mMatrix[13] и mMatrix[14] на 0.0f, 0.0f, -10.0f соответственно. Остальная часть матрицы идентична. Я проверил, что это так), который я буду использовать для демонстрации проблем.

Скриншот: Нет вращения

Если я перемещаю точку lookAt только по осям X и Y, lookAt работает правильно.

Снимок экрана: Ось X (вращение по Y)

Скриншот: Ось Y (вращение по X)

Однако, когда я комбинирую эти два варианта (т.е. перемещаю точку lookAt так, чтобы X и Y не были равны 0.0f), применяется вращение по Z, чего не должно происходить, поскольку UP x DIRECTION всегда должно приводить к тому, что RIGHT.y() будет 0.0f. Вращение по Z будет применено с помощью toZRadians (который еще не реализован).

Скриншот: Добавлено вращение по Z

Также я обнаружил, что если затем переместить точку lookAt вниз по оси Y, модель все еще следует за точкой lookAt, но на самом деле она вращается вокруг глобальной оси X (или эквивалентно ей, по крайней мере).

Снимок экрана: Глобальное вращение X

Теперь, когда точка lookAt перемещается в -Z, модель имеет правильное вращение по Y, но вращение по X инвертировано. Я проверил свои векторы в этой точке и обнаружил, что UP.y() отрицательный, что не должно быть возможным (он может быть 0.0f, но не отрицательным), поскольку DIRECTION и RIGHT всегда должны вращаться одинаково (т.е. по часовой стрелке от DIRECTION к RIGHT). Единственный способ, при котором UP.y() может быть отрицательным, это если RIGHT на самом деле является LEFT.

Скриншот: Инвертированное вращение по X

Модель по-прежнему вращается вокруг глобальной оси X, как это было, когда точка lookAt была +Z.

Снимок экрана: Глобальный поворот X (lookAt -Z)

Как я уже говорил, это, скорее всего, непонимание того, как работают матрицы, но это может быть и что-то другое. Я искал несколько дней и, похоже, смог найти только функции lookAt, основанные на камере. Любые источники, объясняющие оси, содержащиеся в матрице, привели к коду, представленному в этом сообщении.

5
задан Charlie Wilkinson 16 January 2012 в 04:52
поделиться