我正在使用当前方向(四元数)及其当前位置为我的相机创建视图矩阵。
void Camera::updateViewMatrix()
{
view = glm::gtx::quaternion::toMat4(orientation);
// Include rotation (Free Look Camera)
view[3][0] = -glm::dot(glm::vec3(view[0][0], view[0][1], view[0][2]), position);
view[3][1] = -glm::dot(glm::vec3(view[1][0], view[1][1], view[1][2]), position);
view[3][2] = -glm::dot(glm::vec3(view[2][0], view[2][1], view[2][2]), position);
// Ignore rotation (FPS Camera)
//view[3][0] = -position.x;
//view[3][1] = -position.y;
//view[3][2] = -position.z;
view[3][3] = 1.0f;
}
这有一个问题,我不相信矩阵计算的四元数给出了正确的答案。翻译相机按预期工作,但旋转它会导致不正确的行为。
我使用当前鼠标位置和屏幕中心之间的差异旋转相机(每帧重置鼠标位置)
int xPos;
int yPos;
glfwGetMousePos(&xPos, &yPos);
int centreX = 800 / 2;
int centreY = 600 / 2;
rotate(xPos - centreX, yPos - centreY);
// Reset mouse position for next frame
glfwSetMousePos(800 / 2, 600 / 2);
旋转发生在此方法
中void Camera::rotate(float yawDegrees, float pitchDegrees)
{
// Apply rotation speed to the rotation
yawDegrees *= lookSensitivity;
pitchDegrees *= lookSensitivity;
if (isLookInverted)
{
pitchDegrees = -pitchDegrees;
}
pitchAccum += pitchDegrees;
// Stop the camera from looking any higher than 90 degrees
if (pitchAccum > 90.0f)
{
//pitchDegrees = 90.0f - (pitchAccum - pitchDegrees);
pitchAccum = 90.0f;
}
// Stop the camera from looking any lower than 90 degrees
if (pitchAccum < -90.0f)
{
//pitchDegrees = -90.0f - (pitchAccum - pitchDegrees);
pitchAccum = -90.0f;
}
yawAccum += yawDegrees;
if (yawAccum > 360.0f)
{
yawAccum -= 360.0f;
}
if (yawAccum < -360.0f)
{
yawAccum += 360.0f;
}
float yaw = yawDegrees * DEG2RAD;
float pitch = pitchDegrees * DEG2RAD;
glm::quat rotation;
// Rotate the camera about the world Y axis (if mouse has moved in any x direction)
rotation = glm::gtx::quaternion::angleAxis(yaw, 0.0f, 1.0f, 0.0f);
// Concatenate quaterions
orientation = orientation * rotation;
// Rotate the camera about the world X axis (if mouse has moved in any y direction)
rotation = glm::gtx::quaternion::angleAxis(pitch, 1.0f, 0.0f, 0.0f);
// Concatenate quaternions
orientation = orientation * rotation;
}
我是否正确连接四元数以获得正确的方向?
音高积累也存在问题,因为它将我的视野限制在〜±5度而不是±90度。可能是什么原因?
编辑:
我已经解决了音高积累的问题,因此它的范围是[-90,90]。事实证明,glm使用度数而不是轴角度的向量,并且四元数级联的乘法顺序不正确。
// Rotate the camera about the world Y axis
// N.B. 'angleAxis' method takes angle in degrees (not in radians)
rotation = glm::gtx::quaternion::angleAxis(yawDegrees, 0.0f, 1.0f, 0.0f);
// Concatenate quaterions ('*' operator concatenates)
// C#: Quaternion.Concatenate(ref rotation, ref orientation)
orientation = orientation * rotation;
// Rotate the camera about the world X axis
rotation = glm::gtx::quaternion::angleAxis(pitchDegrees, 1.0f, 0.0f, 0.0f);
// Concatenate quaterions ('*' operator concatenates)
// C#: Quaternion.Concatenate(ref orientation, ref rotation)
orientation = rotation * orientation;
剩下的问题是视图矩阵旋转似乎旋转绘制的对象而不像普通的FPS相机一样环顾四周。
我已将视频上传到YouTube以演示此问题。我移动鼠标来改变相机的方向,但三角形似乎旋转了。
YouTube video demonstrating camera orientation problem
编辑2:
void Camera::rotate(float yawDegrees, float pitchDegrees)
{
// Apply rotation speed to the rotation
yawDegrees *= lookSensitivity;
pitchDegrees *= lookSensitivity;
if (isLookInverted)
{
pitchDegrees = -pitchDegrees;
}
pitchAccum += pitchDegrees;
// Stop the camera from looking any higher than 90 degrees
if (pitchAccum > 90.0f)
{
pitchDegrees = 90.0f - (pitchAccum - pitchDegrees);
pitchAccum = 90.0f;
}
// Stop the camera from looking any lower than 90 degrees
else if (pitchAccum < -90.0f)
{
pitchDegrees = -90.0f - (pitchAccum - pitchDegrees);
pitchAccum = -90.0f;
}
// 'pitchAccum' range is [-90, 90]
//printf("pitchAccum %f \n", pitchAccum);
yawAccum += yawDegrees;
if (yawAccum > 360.0f)
{
yawAccum -= 360.0f;
}
else if (yawAccum < -360.0f)
{
yawAccum += 360.0f;
}
orientation =
glm::gtx::quaternion::angleAxis(pitchAccum, 1.0f, 0.0f, 0.0f) *
glm::gtx::quaternion::angleAxis(yawAccum, 0.0f, 1.0f, 0.0f);
}
EDIT3:
以下相乘顺序允许相机绕自己的轴旋转但面向错误的方向:
glm::mat4 translation;
translation = glm::translate(translation, position);
view = glm::gtx::quaternion::toMat4(orientation) * translation;
EDIT4:
以下内容将起作用(根据旋转后的位置应用平移矩阵)
// Rotation
view = glm::gtx::quaternion::toMat4(orientation);
// Translation
glm::mat4 translation;
translation = glm::translate(translation, -position);
view *= translation;
我无法获得每个方向轴的点积,但
// Rotation
view = glm::gtx::quaternion::toMat4(orientation);
glm::vec3 p(
glm::dot(glm::vec3(view[0][0], view[0][1], view[0][2]), position),
glm::dot(glm::vec3(view[1][0], view[1][1], view[1][2]), position),
glm::dot(glm::vec3(view[2][0], view[2][1], view[2][2]), position)
);
// Translation
glm::mat4 translation;
translation = glm::translate(translation, -p);
view *= translation;
答案 0 :(得分:4)
为了给你一个明确的答案,我认为我们需要的代码显示你实际上如何向OpenGL提供view
矩阵和顶点。但是,症状听起来非常典型,不正确的矩阵顺序。
考虑一些变量:
V 表示相机当前方向(四元数)的倒数
T 表示保持相机位置的平移矩阵。这应该是一个单位矩阵,否定相机在第四列的位置(假设我们是右向乘以列向量)。
U 表示方向变化的倒数
p 表示世界空间中的顶点
注意:所有矩阵都是逆矩阵,因为变换将应用于顶点,而不是摄像机,但最终结果是相同的。
默认情况下,OpenGL摄像头位于负z轴向下的原点。当视图不变( U == I )时,顶点从世界坐标到相机坐标的变换应为: p'= TVp 。首先定位摄像机(通过沿相反方向旋转世界),然后将摄像机平移到位(通过向相反方向移动世界)。
现在有几个地方可以放 U 。如果我们将 U 放在 V 的右侧,那么我们就会得到第一人称视角的行为。向上移动鼠标时,当前视图中的任何内容都会在相机周围向下旋转。向右移动鼠标时,视图中的任何内容都会在相机周围向左旋转。
如果我们在 T 和 V 之间放置 U ,则相机会相对于世界的轴而不是相机进行转动。这是一种奇怪的行为。如果 V 碰巧将相机关闭到一侧,那么上下移动鼠标将使世界看起来“滚动”而不是“俯仰”或“偏航”。
如果我们在 T 左侧放置 U ,则相机会绕着世界各地的世界轴旋转。这甚至可能更奇怪,因为它使摄像机离原点越远,相机飞得更快。但是,由于旋转位于原点附近,如果相机恰好看着原点,那么物体就会出现转动。这是你所看到的,因为您正在采取旋转相机位置的点积。
您检查以确保pitchAccum
保持在[-90,90]范围内,但您已注释掉将利用该事实的部分。这对我来说似乎很奇怪。
你离开的方式 - 乘以音高但右向乘以偏航使得你的四元数对你没有太大作用。他们只是抱着你的欧拉角。除非来自其他地方的方向更改,否则您可以简单地说orientation = glm::gtx::quaternion::angleAxis(pitchAccum*DEG2RAD, 1.0f, 0.0f, 0.0f) * glm::gtx::quaternion::angleAxis(yawAccum*DEG2RAD, 0.0f, 1.0f, 0.0f);
并完全覆盖旧方向。