2

注意:我已经编辑了下面的问题,它与我的实际问题比下面的文字更相关,如果你可以跳过这个,但出于历史原因,我会把它留在这里。

看看我是否正确,floatC 中的 a 与弧度中的值相同,对吗?我的意思是,360º = 6.28318531 弧度,我刚刚在我的 OpenGL 应用程序上注意到一个完整的旋转从 0.0 到 6.28,这似乎是正确的。我只是想确保我做对了。

我正在使用从 0.0 到 360.0 的float(让我们称之为anglePitch)(它更容易以度数读取并且避免一直转换intfloat),并且我在网络上看到的所有代码都使用某种DEG2RAD()定义为DEG2RAD 3.141593f / 180. 最后它会是这样的:

anglePitch += direction * 1; // direction will be 1 or -1
refY = tan(anglePitch * DEG2RAD);

这确实做了一个完整的旋转,但完整的旋转将是 whenanglePitch = 180anglePitch * DEG2RAD = 3.14,但完整的旋转应该是 360|6.28。如果我将宏更改为以下任何一项:

#define DEG2RAD 3.141593f / 360
#define DEG2RAD 3.141593f / 2 / 180

它按预期工作,当anglePitch = 360.

我在这里遗漏了什么,我应该用什么来正确地将角度转换为弧度/浮点数?

重要编辑(真正的问题):
我现在理解了我在网络上随处可见的关于 的代码DEG2RAD,我只是在数学上太笨了(是的,我知道,在处理这类东西时很重要)。所以我要改写我的问题:

我现在已将此添加到我的代码中:

#define PI         3.141592654f
#define DEG2RAD(d) (d * PI / 180)

现在,当以度为单位工作俯仰/打哈欠角度时floats,再次,为了避免一直投射,我只使用DEG2RAD宏,度值将正确转换为弧度。这些值将被传递给 sin/cos/tan 函数,并将返回正确的值以在 GLUT 相机中使用。

现在是真正的问题,我之前真的很困惑,但无法更好地解释自己:

angleYaw += direction * ROTATE_SPEED;
refX = sin(DEG2RAD(angleYaw));
refZ = -cos(DEG2RAD(angleYaw));

当我按下 LEFT/RIGHT 键时,将执行此代码,相机将相应地沿 Y 轴旋转。一个完整的旋转从 0º 到 360º。

anglePitch += direction * ROTATE_SPEED;
refY = tan(DEG2RAD(anglePitch));

这是类似的代码,将在我按下 UP/DOWN 键时执行,相机将沿 X 轴旋转。但是在这种情况下,一个完整的旋转从 0º 到 180º 度,这让我很困惑。我确定它与切线函数有关,但我无法理解它。

有没有办法我可以使用 sin/cos(就像我在打哈欠代码中所做的那样)来实现相同的旋转?什么是正确的方法,我可以添加/修复的最简单的代码,以及创建从 0º 到 360º 的完整俯仰旋转更有意义的方法是什么?

4

3 回答 3

3

'float' 是一种类型,如 int 或 double。弧度和度数是度量单位,两者都可以用你想要的任何精度来表示。即,没有理由不能有 22.5 度,并将该值保持在浮点数中。

以弧度为单位的完整旋转为 2*pi,大约为 6.283,而以度为单位的完整旋转为 360。您可以通过除以起始单位的完整圆,然后乘以所需单位的完整圆来在它们之间进行转换。

例如,要从 90 度到弧度,首先将度数分开。360 上的 90 为 0.25(注意此值以“转数”为单位)。现在将 0.25 乘以 6.283 得到 1.571 弧度。

跟进

你看到你的音调周期比它应该快两倍的原因正是因为你正在使用 tan(pitch) 来计算 Y 分量。您应该拥有的是 Y 分量取决于 sin(pitch)。即,尝试改变

refY = tan(DEG2RAD(anglePitch));

refY = sin(DEG2RAD(anglePitch));

一个技术细节:进入外观矩阵的数字都应该在 -1 到 +1 的范围内,如果你要检查你提供给 refY 的值,并且在 -45 到 + 之间运行你的音调45度,你会看到问题;tan() 在 +/-90 度处运行到无穷大。

另外,请注意,将值从 int 转换为 float绝不会在度数和弧度之间转换。铸造只是为您提供新存储类型中最接近的等效值。例如,如果将整数 22 转换为浮点数,则得到 22.0f,而如果将 33.3333f 转换为 int 类型,则剩下 33。使用角度时,您真的应该坚持使用浮点数,除非您受到使用嵌入式处理器或其他东西的限制。这对于弧度尤其重要,其中整数增量表示(大约)57.3 度的跳跃。

于 2011-03-06T13:22:30.090 回答
3

360° = 2 * Pi, Pi = 3.141593…</p>

弧度由沿半径为 1 的圆的角的弧长定义。圆的周长为 2*r*Pi,因此单位圆上一整圈的弧长为 2*Pi = 6.28……</ p>

以度数为单位的角度度量源于这样一个事实,即通过对齐 6 个等边三角形,您可以跨越一整圈。所以我们有 6 个三角形,每个三角形都占一圈的 6 个,所以古老的巴比伦人将一个圆圈分成 1/(6*6) = 1/36 的部分,为了进一步细化,它被细分为 10。这就是为什么我们最终以 360° 旋转一圈。不过,这个数字是任意选择的。

所以如果有 2*Pi/360° 这使得 Pi/180° = 3.141593…/180° 这是从度到弧度的转换因子。倒数,180°/Pi = 180/3.141593…</p>

为什么在地球上旧的 OpenGL 函数 glRotate 和 GLU 的 gluPerspective 使用度数而不是弧度,我无法理解。从数学的角度来看,只有弧度才有意义。我认为欧拉方程最完美地证明了这一点

e^(i*Pi) - 1 = 0

有了它,所有重要的数学数字都在一个方程式中。这和角度有什么关系?好:

e^(i*alpha) = cos(alpha) + i * sin(alpha), alpha is in radians!

编辑,关于修改后的问题:

你的角度是浮动的一切都很好。为什么你甚至会认为 degress 是我无法理解的整数。通常您不必自己定义 PI,它在 math.h 中预定义,通常称为 M_PI、M_2PI 和 M_PI2,用于 Pi、2*Pi 和 Pi/2。你也应该改变你的宏,它现在的写法会产生奇怪的效果。

#define DEG2RAD(d) ( (d) * M_PI/180. )

GLUT 根本没有相机。GLUT 是一个相当愚蠢的 OpenGL 框架,我不建议使用。您可能指的是gluLookAt

那些障碍让我们看看你在那里做什么。请记住,三角函数在单位圆上运行。让角度 0 指向右侧,角度逆时针递增。然后将sin(a)定义为向右和cos(a)的数量以及向前到达单位圆上角度 a 的点的数量。这就是refXandrefZ被分配的内容。

refY但是这样写没有意义。tan = sin/cos所以当我们接近 n*pi/2(即 90°)时,它会发散到 +/- 无穷大。至少它解释了您的 pi/180° 循环范围,因为那是tan的周期。

我首先认为tan可能已用于标准化方向向量,但也没有任何意义。系数应该是 1./sqrt(sin²(Pitch) + 1) 我仔细检查了一遍:使用 tan 是正确的。

EDIT2:我看不出你的问题出在哪里:俯仰角是-90°到+90°,这很有意义。去拿一个地球仪(地球):东西坐标(经度)从-180°到+180°,南北坐标(纬度)从-90°到+90°。想一想:任何更大的坐标范围都会产生歧义。

我给你的唯一好建议是:拿一些数学教科书,围绕球坐标弯曲你的思想!很抱歉这样告诉你。无论您拥有什么都可以正常工作,您只需要了解螺旋几何即可。

您正在使用术语 Yaw 和 Pitch。这些通常用于欧拉角。现在不幸的是,起初引人注目的欧拉角后来会引起严重的麻烦(例如万向节锁定)。你根本不应该使用它们。如果您使用一些铅笔/棍子/任何东西来分解您打算用手来理解它们的机制的旋转,这也可能是一个好主意。


顺便说一句:也有非整数度数。只需跳到http://maps.google.com就可以看到它们的实际效果(只需选择某个地方,然后让http://maps.google.com为您提供指向它的链接)。

于 2011-03-06T13:37:27.993 回答
1

假设您的 ref 组件旨在用作您的查看向量,我认为您需要的是

refY = sin(DEG2RAD(anglePitch)); 
XZfactor = cos(DEG2RAD(anglePitch));
refX = XZfactor*sin(DEG2RAD(angleYaw));
refZ = -XZfactor*cos(DEG2RAD(angleYaw));
于 2011-03-06T17:09:54.583 回答