我一直在尝试模拟gluLookAt功能,但使用四元数。我的每个游戏对象都有一个翻译组件。该组件存储对象的位置(glm::vec3
),旋转(glm::quat
)和比例(glm::vec3
)。摄像机在每次刻度时计算其位置,执行以下操作:
// UP = glm::vec3(0,1,0);
//FORWARD = glm::vec3(0,0,1);
cameraPosition = playerPosition - (UP * distanceUP) - (FORWARD * distanceAway);
这个位置代码是按扩展工作的,摄像机放置在玩家身后 3 米处,向上 1 米处。现在,相机的四元数设置为以下内容:
//Looking at the player's feet
cameraRotation = quatFromToRotation(FORWARD, playerPosition);
渲染引擎现在采用这些值并生成 ViewMatrix(相机)和模型矩阵(播放器),然后渲染场景。代码如下所示:
glm::mat4 viewTranslationMatrix =
glm::translate(glm::mat4(1.0f), cameraTransform->getPosition());
glm::mat4 viewScaleMatrix =
glm::scale(glm::mat4(1.0f), cameraTransform->getScale());
glm::mat4 viewRotationMatrix =
glm::mat4_cast(cameraTransform->getRotation());
viewMatrix = viewTranslationMatrix * viewRotationMatrix * viewScaleMatrix;
quatFromToRotation(glm::vec3 from, glm::vec3 to) 定义为:
glm::quat quatFromToRotation(glm::vec3 from, glm::vec3 to)
{
from = glm::normalize(from); to = glm::normalize(to);
float cosTheta = glm::dot(from, to);
glm::vec3 rotationAxis;
if (cosTheta < -1 + 0.001f)
{
rotationAxis = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), from);
if (glm::length2(rotationAxis) < 0.01f)
rotationAxis = glm::cross(glm::vec3(1.0f, 0.0f, 0.0f), from);
rotationAxis = glm::normalize(rotationAxis);
return glm::angleAxis(180.0f, rotationAxis);
}
rotationAxis = glm::cross(from, to);
float s = sqrt((1.0f + cosTheta) * 2.0f);
float invis = 1.0f / s;
return glm::quat(
s * 0.5f,
rotationAxis.x * invis,
rotationAxis.y * invis,
rotationAxis.z * invis
);
}
我遇到的问题是相机旋转设置不正确。无论玩家身在何处,摄像机的前进方向始终为 (0,0,-1)
你的问题出在这条线上
//Looking at the player's feet
cameraRotation = quatToFromRotation(FORWARD, playerPosition);
您需要从摄像机位置看向玩家的脚 - 而不是从"玩家上方一米"(假设玩家最初执行此操作时处于 (0,0,0) 处)。将FORWARD
替换为cameraPosition
:
cameraRotation = quatToFromRotation(cameraPosition, playerPosition);
编辑我相信您的quatToFromRotation
函数也有错误。 请参阅 https://stackoverflow.com/a/11741520/1967396 以获取四元数旋转的非常好的解释(和一些伪代码)。