不能使用向量在OpenGL中限制[-90º,90º]之间的摄像机俯仰角! [英] Can't limit the camera pitch angle between [-90º, 90º] in OpenGL using vectors!
问题描述
我有一个大问题,用下面的代码限制相机俯仰角(在-90º和90º之间)。这有点遵循这个问题。
I'm having a big problem limiting the camera pitch angle (between -90º and 90º) with the code below. This is somewhat a follow up to this question.
问题似乎是相机旋转超过-90º或大于+90º当这发生时,我会向下看(或向上),但是视图只是围绕Y轴旋转180º。
The problem, it seems, is that the camera rotates more than -90º or more than +90º and when that happens, I'll be looking down (or up) but but the view just rotated 180º around the Y axis.
示例:地平线和我开始往下看,直到我不能再下去了(由下面的代码限制)。
Example: I'm facing north looking at the horizon and I start to look down until I can't go down anymore (limited by the code below). Then I start to look up and I'll be facing south.
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
背后的原因。但是,当我将相机垂直向下时,这似乎是侧面切换的原因。
The problem is probably in the if(angle.y != 0.0f)
statement, if I comment that code block, the problem doesn't exist at all. It has something to do with WORLD_SKY_VECTOR
, but that code is like that to allow me to rotate the heading and keep the camera leveled. If I used the UpVector
instead, problem solved. But that is only good for a flight simulator, I need to keep the horizon leveled, that's the reason behind WORLD_SKY_VECTOR
. But it seems that's the cause of "side switching" when I point the camera straight down.
根据下面的评论请求...这是第一个人(和第三人,但我还没有开始实现那部分)相机,当我直视,-90º(或直上,+90º),当角度从-89º到-91º(或从+89º到+91º)我想要相机防止这种情况,不要超过-90º,+90º的极限。当它达到这个限制,我需要相机能够回去(如果我在-90º或向上,如果我在+90º)。现在这只有时有效,其他时候我会面对另一种方式,而不是我最初看的方式。
As per requested on a comment below... This is for a first person (and third person but I haven't started implementing that part yet) camera and when I look straight down, -90º (or straight up, +90º) and when the angle goes from -89º to -91º (or from +89º to +91º) I want the camera to prevent that and don't go beyond the -90º, +90º limit. When it reaches that limit I need the camera to be able to go back (either up if I'm at -90º or down if I'm at +90º). Right now this only works sometimes, other times I'll be facing the other way instead of the way I was initially looking at.
推荐答案
p>之后,我想出了一个非常简单和直接的解决方案。像在答案和评论中说的很多次,问题出在正向向量(我的引用
)看起来正直或向下,这意味着这个向量是平行的 WORLD_SKY_VECTOR
这就是为什么它变得乱七八糟。
After while I come up with a solution which is pretty simple and straightforward. Like it was said many times in the answers and comments, the problem lies when the forward vector (my Reference
) is looking straight up or down, which means this vector is parallel to WORLD_SKY_VECTOR
and that's reason it gets all messy.
这个解决方案背后的想法是,向下(或向上),我想向左或向右旋转,这实际上是围绕向前向量的滚动旋转。当俯仰角为-90°或90°时,为什么不执行侧倾运动?
My thought behind this solution is that when I'm looking straight down (or up) and I want to rotate left or right, this is actually a roll rotation around the forward vector. Why not execute a roll movement when the pitch angle is at -90º or 90º instead?
将这些组合在一起,我通过简单地替换偏航/以下代码:
Putting that together, I solved the problem by simply replacing the yaw/heading rotation with the following code:
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);
}
}
这看起来是一个相当简单和直接的工作解决方案,可能会将我的答案标记为接受,除非有人指出任何强烈的问题反对这个实现,我可能没有考虑。我会等几个小时后再做,以便以前的答案得出一些结论。
This seems a fairly simple and straightforward working solution, I'll probably be marking my answer as accepted unless someone points out any strong problem against this implementation that I may not be considering. I'll wait a few hours before doing it, so that the previous answers reach some sort of conclusion.
这篇关于不能使用向量在OpenGL中限制[-90º,90º]之间的摄像机俯仰角!的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!