Мне удалось успешно реализовать матрицу 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();
}
Вот перекрестные произведения и функции нормализации, если они неверны.
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);
}
Вот несколько скриншотов, чтобы описать мою проблему. Белая сфера указывает точку взгляда.
Я создал куб, переведенный на -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 всегда должен приводить к ПРАВУ. y () = 0.0f. Вращение Z будет применено с использованием toZRadians
(что еще не реализовано).
Снимок экрана: Добавлено вращение по Z
Также я обнаружил, что если я затем переместлю точку lookAt вниз по оси Y, модель все равно будет следовать точке lookAt, но на самом деле она будет вращаться вокруг глобальной оси X (или, по крайней мере, равноценно этому).
Снимок экрана: Глобальное вращение X
Теперь, когда точка lookAt перемещается в -Z, модель имеет правильное вращение Y, но ее вращение X инвертировано. В этот момент я проверил свои векторы и обнаружил, что UP.y () отрицателен, что не должно быть возможным (это может быть 0.0f, но не отрицательно), поскольку DIRECTION и RIGHT всегда должны вращаться одинаково (то есть по часовой стрелке от НАПРАВЛЕНИЕ НА ПРАВО). Единственный способ, которым UP.y () может быть отрицательным, это если RIGHT на самом деле ЛЕВЫЙ.
Снимок экрана: Перевернутое вращение X
Модель все еще вращается вокруг глобальной оси X, как это было, когда точка lookAt была + Z.
Снимок экрана: Глобальное вращение X (lookAt -Z)
Как я уже говорил, это, вероятно, неправильное понимание того, как работают матрицы, но это может быть что-то другое. Я смотрел вокруг в течение нескольких дней, и мне кажется, что я могу только найти функции lookAt на основе камеры. Любые источники, объясняющие оси, содержащиеся в матрице, приводят к коду, представленному в этом посте.