不能使用向量在OpenGL中限制[-90º,90º]之间的摄像机俯仰角! [英] Can't limit the camera pitch angle between [-90º, 90º] in OpenGL using vectors!

查看:246
本文介绍了不能使用向量在OpenGL中限制[-90º,90º]之间的摄像机俯仰角!的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个大问题,用下面的代码限制相机俯仰角(在-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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆