Итак, я в настоящее время пытаюсь создать функцию, которая возьмет две 3D точки A и B, и предоставит мне кватернион, представляющий поворот, требуемый для точки A, для "точки зрения B" (такой, что точка A локальная Z ось проходит через точку B, если вы это сделаете).
Я изначально нашел этот пост, верхний ответ которого, казалось, дал мне хорошую отправную точку. Я продолжал реализовывать следующий код; вместо того, чтобы предполагать ориентацию по умолчанию (0, 0, -1), как показывает исходный ответ, я пытаюсь извлечь единичный вектор, представляющий фактическую ориентацию камеры.
void Camera::LookAt(sf::Vector3<float> Target)
{
///Derived from pseudocode found here:
////info/485290/quaternion-rotate-to
//Get the normalized vector from the camera position to Target
sf::Vector3<float> VectorTo(Target.x - m_Position.x,
Target.y - m_Position.y,
Target.z - m_Position.z);
//Get the length of VectorTo
float VectorLength = sqrt(VectorTo.x*VectorTo.x +
VectorTo.y*VectorTo.y +
VectorTo.z*VectorTo.z);
//Normalize VectorTo
VectorTo.x /= VectorLength;
VectorTo.y /= VectorLength;
VectorTo.z /= VectorLength;
//Straight-ahead vector
sf::Vector3<float> LocalVector = m_Orientation.MultVect(sf::Vector3<float>(0, 0, -1));
//Get the cross product as the axis of rotation
sf::Vector3<float> Axis(VectorTo.y*LocalVector.z - VectorTo.z*LocalVector.y,
VectorTo.z*LocalVector.x - VectorTo.x*LocalVector.z,
VectorTo.x*LocalVector.y - VectorTo.y*LocalVector.x);
//Get the dot product to find the angle
float Angle = acos(VectorTo.x*LocalVector.x +
VectorTo.y*LocalVector.y +
VectorTo.z*LocalVector.z);
//Determine whether or not the angle is positive
//Get the cross product of the axis and the local vector
sf::Vector3<float> ThirdVect(Axis.y*LocalVector.z - Axis.z*LocalVector.y,
Axis.z*LocalVector.x - Axis.x*LocalVector.z,
Axis.x*LocalVector.y - Axis.y*LocalVector.x);
//If the dot product of that and the local vector is negative, so is the angle
if (ThirdVect.x*VectorTo.x + ThirdVect.y*VectorTo.y + ThirdVect.z*VectorTo.z < 0)
{
Angle = -Angle;
}
//Finally, create a quaternion
Quaternion AxisAngle;
AxisAngle.FromAxisAngle(Angle, Axis.x, Axis.y, Axis.z);
//And multiply it into the current orientation
m_Orientation = AxisAngle * m_Orientation;
}
Это почти работает. Случается, что камера, похоже, поворачивает половину расстояния до целевой точки. Если я повторю попытку вращения, он выполняет половину оставшегося вращения до бесконечности, так что если я удерживаю кнопку "Look-at-Button", ориентация камеры становится все ближе и ближе к прямому прицелу, но также постоянно замедляя его вращение, чтобы он никогда не попадал туда.
Обратите внимание: я не хочу прибегать к gluLookAt(), так как мне также понадобится этот код, чтобы указать объекты, отличные от камеры друг на друга, а мои объекты уже используют кватернионы для их ориентации. Например, я мог бы создать глазное яблоко, которое отслеживает положение чего-то движущегося перед ним, или снаряда, который обновляет свою ориентацию, чтобы искать свою цель.