我在使用下面的代码限制摄像机俯仰角(在-90º和90º之间)时遇到了很大的问题。这有点是this question的后续行动。
问题似乎是相机旋转超过-90º或超过+90º,当发生这种情况时,我会向下看(或向上看),但视线只围绕Y轴旋转180º。
示例:我正朝北看地平线,然后我开始往下看,直到我不能再往下走了(受下面的代码限制)。然后我开始仰视,我将面向南方。
void Camera::Rotate(Vector3D angle) {
angle = angle * CAMERA_ROTATION_SPEED;
accumPitchAngle += angle.x;
if(accumPitchAngle > 90.0f) {
angle.x = 90.0f - (accumPitchAngle - angle.x);
accumPitchAngle = 90.0f;
}
if(accumPitchAngle < -90.0f) {
angle.x = -90.0f - (accumPitchAngle - angle.x);
accumPitchAngle = -90.0f;
}
// Rotate along the WORLD_SKY_VECTOR axis (yaw/heading rotation)
// WORLD_SKY_VECTOR = (0.0f, 1.0f, 0.0f)
if(angle.y != 0.0f) {
Reference = RotateArbitraryAxis(Reference, WORLD_SKY_VECTOR, angle.y);
RightVector = Vector3D::CrossProduct(Reference, WORLD_SKY_VECTOR);
UpVector = Vector3D::CrossProduct(RightVector, Reference);
}
// Rotate along the x axis (pitch rotation)
if(angle.x != 0.0f) {
Reference = RotateArbitraryAxis(Reference, RightVector, angle.x);
UpVector = Vector3D::CrossProduct(RightVector, Reference);
}
// Makes sure all vectors are perpendicular all the time
Reference.Normalize();
RightVector = Vector3D::CrossProduct(Reference, UpVector);
RightVector.Normalize();
UpVector = Vector3D::CrossProduct(RightVector, Reference);
UpVector.Normalize();
}
Vector3D Camera::RotateArbitraryAxis(const Vector3D v, Vector3D u, double angle) {
Vector3D result;
u.Normalize();
double scalar = Vector3D::DotProduct(v, u);
double c = cos(Math::DegreesToRadians(angle));
double s = sin(Math::DegreesToRadians(angle));
double a = 1.0f - c;
result.x = u.x * scalar * a + (v.x * c) + ((-u.z * v.y) + (u.y * v.z)) * s;
result.y = u.y * scalar * a + (v.y * c) + (( u.z * v.x) - (u.x * v.z)) * s;
result.z = u.z * scalar * a + (v.z * c) + ((-u.y * v.x) + (u.x * v.y)) * s;
return result;
}
问题可能在if(angle.y != 0.0f)
语句中,如果我对该代码块进行评论,则该问题根本不存在。它与WORLD_SKY_VECTOR
有关,但该代码就像允许我旋转标题并保持相机水平。如果我使用UpVector
代替,问题就解决了。但这只适用于飞行模拟器,我需要保持地平线,这就是WORLD_SKY_VECTOR
背后的原因。但是,当我直接指向相机时,似乎是“侧面切换”的原因。
根据以下评论的要求......这是第一人(和第三人,但我还没有开始实施那部分)相机,当我直视,-90º(或直线上升,+ 90º)当角度从-89º到-91º(或+89º到+91º)时,我希望相机防止这种情况发生,并且不要超过-90º,+90º限制。当它达到那个极限时,我需要相机能够返回(如果我在-90º则向上,如果我在+90º则向下)。现在这只会有效,有时我会面对另一种方式,而不是我最初看的方式。
答案 0 :(得分:2)
问题1:代码belew“//确保所有矢量始终垂直”确保您的UP摄像机矢量实际上是正确的(相对于WORLD_SKY_VECTOR)。所以:
低头看你的胸部。你的头顶实际上已经下降了。如果你想从同一个角度看同样的事情,但是你的头顶向上,你必须旋转它(不可能,不可思议)
问题2:与上述相同。 CrossProduct(参考,WORLD_SKY_VECTOR)给出了交叉(向上,向下),这并不意味着什么,只是尝试在纸上。
如果您希望能够“颠倒”:
所以:
yaw += whatever;
pitch += whatever;
FrontVector = SphericalToCartesian(yaw, pitch);
RightVector = SphericalToCartesian(yaw + PI/2.0f, 0.0);
UpVector = cross(RightVector, FrontVector);
使用SphericalToCartesian,如if(pitch = 0,yaw = 0)意味着向南看:
x = cos(pitch) * sin(yaw)
y = sin(pitch)
z = cos(pitch) * cos(yaw)
答案 1 :(得分:1)
您无法获取两个平行向量的叉积。我认为这是失败的地方,即当accumPitchAngle为±90°时。
您可能希望将其限制为-89.999°〜+ 89.999°。
编辑:要从头开始,您要转换音高和音高。偏向gluLookAt()
的前向矢量和向上矢量,对吧?然后我建议:
1)使用yaw
(仅限yaw
)创建一个与地面平行的right
向量。
2)交叉right
和WORLD_SKY_VECTOR
以获得偏航正确但不在俯仰中的forward
向量。
3)将forward
绕right
旋转至pitch
度,以获得在俯仰和偏航方面均正确的前向矢量。 (我想你已经走到了这一步。)
4)交叉forward
和right
以获取适用于所有情况的相机up
向量。
答案 2 :(得分:1)
在我提出一个非常简单明了的解决方案之后。就像在答案和评论中多次说过的那样,问题出在前向向量(我的Reference
)向上或向下看,这意味着这个向量与WORLD_SKY_VECTOR
平行,这就是它的原因变得一团糟。
我在这个解决方案背后的想法是,当我直视(或向上)并且我想向左或向右旋转时,这实际上是围绕前向矢量的滚动旋转。当俯仰角为-90º或90°时,为什么不执行侧倾运动?
把它放在一起,我通过简单地用以下代码替换偏航/航向旋转来解决问题:
if(angle.y != 0.0f) {
if(abs(accumPitchAngle) == 90.0f) {
RightVector = RotateArbitraryAxis(RightVector, Reference, -angle.y);
UpVector = Vector3D::CrossProduct(RightVector, Reference);
} else {
Reference = RotateArbitraryAxis(Reference, WORLD_SKY_VECTOR, angle.y);
RightVector = Vector3D::CrossProduct(Reference, WORLD_SKY_VECTOR);
UpVector = Vector3D::CrossProduct(RightVector, Reference);
}
}
这似乎是一个相当简单和直接的工作解决方案,我可能会将我的答案标记为已被接受,除非有人指出任何针对此实现的强烈问题,我可能不会考虑。我会等几个小时才能做到这一点,以便之前的答案得出某种结论。