四边形的二维旋转
2D rotation of a quad
我正在使用 C++ 开发一个基本的模拟程序,并且我有一个使用 OpenGL 的渲染器。我在屏幕上渲染四边形,它们在模拟中具有动态位置。我的目标是在模拟中移动时更改四边形的方向。对于每个四边形,我有一个变量 (m_Rotation) 保存它的当前旋转,我使用三角函数计算所需的旋转并将值放入一个变量 (m_ProjectedRotation)。在渲染循环中,我使用以下代码来改变运动中的方向:
if(abs(m_ProjectedRotation - m_Rotation)>5.0f)
{
if ((360.0f - m_Rotation + m_ProjectedRotation) > (m_ProjectedRotation - m_Rotation))
{
m_Rotation += 5.0f;
if (m_Rotation > 360)
{
m_Rotation = fmod(m_Rotation, 360);
}
}
else
{
m_Rotation -= 5.0f;
}
}
我希望四边形根据最近的角度自行旋转(例如,如果当前角度为 330,而目标角度为 30,则四边形应增加其角度直到达到 30 而不是减小达到 30 后的角度。因为它有一个较小的角度可以旋转 )。在某些情况下,即使顺时针旋转较短,我的四边形也会逆时针旋转,反之亦然。我相信轮换的条件:
(360.0f - m_Rotation + m_ProjectedRotation) > (m_ProjectedRotation - m_Rotation)
应该有所不同以显示所需的行为。但是,我想不通。我应该如何更新此代码以获得我想要的内容?
我认为正确的解决方案应该如下:
我们称这两个角为from
和to
。根据您的问题,我认为两者都处于正数。有两种情况:
- 绝对距离
|to - from|
小于180
这意味着 to - from
的度数比另一个方向的度数要少, 是您应该选择的方式。
在这种情况下,您应该旋转 sign(to-from) * deltaRotation
,其中如果 x > 0 则 sign(x)
= 1,否则为 -1。要了解符号函数的必要性,请查看以下 2 个示例,其中 |to - from|
< 180:
- from = 10, to = 20. to - from = 10 > 0,所以你应该增加旋转。
- from = 20, to = 10. to - from = -10 < 0, 你应该减少旋转。
|to - from|
大于180,这种情况下,方向应该是反的,要旋转- sign(to-form) * deltaRotation
,注意负号。您也可以将其表示为 sign(from-to) * deltaRotation
,交换 from
和 to
,但为了明确起见,我像以前一样保留它们。
- from = 310, to = 10。然后,to - from = -300 < 0,你应该increase rotation (Formally, -sign(to-from) = -符号(-300) = -(-1) = 1)
- from = 10, to = 310。然后,to - from = 300 > 0,你应该减少旋转(正式地,-sign(to-from) = -sign (300) = -1)
用C++写这个你可以把这个逻辑封装在这样一个函数中:
int shorterRotationSign(float from, float to) {
if(fabs(to - from) <= 180) {
return to - from > 0 ? 1 : -1;
}
return to - from > 0 ? -1 : 1;
}
您将像这样使用:
m_Rotation += 5.0f * shorterRotationSign(m_Rotation, m_ProjectedRotation);
m_Rotation = fmod(m_Rotation + 360, 360);
最后一行的目标是归一化负角和大于 360 的角。
(IMO 这更像是一个数学问题,而不是关于 opengl 的问题。)
我会这样做:
auto diff = abs(m_ProjectedRotation - m_Rotation);
if(diff > 5.0f)
{
diff = fmod(diff, 360.0f);
auto should_rotate_forward = (diff > 180.0f) ^ (m_ProjectedRotation > m_Rotation);
auto offset = 360.0f + 5.0f * (should_rotate_forward ? 1.0f : -1.0f);
m_Rotation = fmod(m_Rotation + offset, 360.0f);
}
diff
是你旋转的绝对角度。然后你把它放在 [0; 360) 范围 diff = fmod(diff, 360.0f)
.
should_rotate_forward
确定您应该减小还是增大当前角度。注意 ^
是异或运算
offset
基本上是 -5.0
或 5.0
,具体取决于条件,但也有 +360.0f
,例如 m_Rotation == 1.0
和 offset == -5.0
所以 fmod(m_Rotation + offset, 360.0f)
将是 -4.0
而你想要 356.0
,所以你添加完整的 360 度旋转并且在 fmod
之后一切都是积极的并且在 [0; 360) 范围
我正在使用 C++ 开发一个基本的模拟程序,并且我有一个使用 OpenGL 的渲染器。我在屏幕上渲染四边形,它们在模拟中具有动态位置。我的目标是在模拟中移动时更改四边形的方向。对于每个四边形,我有一个变量 (m_Rotation) 保存它的当前旋转,我使用三角函数计算所需的旋转并将值放入一个变量 (m_ProjectedRotation)。在渲染循环中,我使用以下代码来改变运动中的方向:
if(abs(m_ProjectedRotation - m_Rotation)>5.0f)
{
if ((360.0f - m_Rotation + m_ProjectedRotation) > (m_ProjectedRotation - m_Rotation))
{
m_Rotation += 5.0f;
if (m_Rotation > 360)
{
m_Rotation = fmod(m_Rotation, 360);
}
}
else
{
m_Rotation -= 5.0f;
}
}
我希望四边形根据最近的角度自行旋转(例如,如果当前角度为 330,而目标角度为 30,则四边形应增加其角度直到达到 30 而不是减小达到 30 后的角度。因为它有一个较小的角度可以旋转 )。在某些情况下,即使顺时针旋转较短,我的四边形也会逆时针旋转,反之亦然。我相信轮换的条件:
(360.0f - m_Rotation + m_ProjectedRotation) > (m_ProjectedRotation - m_Rotation)
应该有所不同以显示所需的行为。但是,我想不通。我应该如何更新此代码以获得我想要的内容?
我认为正确的解决方案应该如下:
我们称这两个角为from
和to
。根据您的问题,我认为两者都处于正数。有两种情况:
- 绝对距离
|to - from|
小于180
这意味着to - from
的度数比另一个方向的度数要少, 是您应该选择的方式。
在这种情况下,您应该旋转sign(to-from) * deltaRotation
,其中如果 x > 0 则sign(x)
= 1,否则为 -1。要了解符号函数的必要性,请查看以下 2 个示例,其中|to - from|
< 180:- from = 10, to = 20. to - from = 10 > 0,所以你应该增加旋转。
- from = 20, to = 10. to - from = -10 < 0, 你应该减少旋转。
|to - from|
大于180,这种情况下,方向应该是反的,要旋转- sign(to-form) * deltaRotation
,注意负号。您也可以将其表示为sign(from-to) * deltaRotation
,交换from
和to
,但为了明确起见,我像以前一样保留它们。- from = 310, to = 10。然后,to - from = -300 < 0,你应该increase rotation (Formally, -sign(to-from) = -符号(-300) = -(-1) = 1)
- from = 10, to = 310。然后,to - from = 300 > 0,你应该减少旋转(正式地,-sign(to-from) = -sign (300) = -1)
用C++写这个你可以把这个逻辑封装在这样一个函数中:
int shorterRotationSign(float from, float to) {
if(fabs(to - from) <= 180) {
return to - from > 0 ? 1 : -1;
}
return to - from > 0 ? -1 : 1;
}
您将像这样使用:
m_Rotation += 5.0f * shorterRotationSign(m_Rotation, m_ProjectedRotation);
m_Rotation = fmod(m_Rotation + 360, 360);
最后一行的目标是归一化负角和大于 360 的角。
(IMO 这更像是一个数学问题,而不是关于 opengl 的问题。)
我会这样做:
auto diff = abs(m_ProjectedRotation - m_Rotation);
if(diff > 5.0f)
{
diff = fmod(diff, 360.0f);
auto should_rotate_forward = (diff > 180.0f) ^ (m_ProjectedRotation > m_Rotation);
auto offset = 360.0f + 5.0f * (should_rotate_forward ? 1.0f : -1.0f);
m_Rotation = fmod(m_Rotation + offset, 360.0f);
}
diff
是你旋转的绝对角度。然后你把它放在 [0; 360) 范围 diff = fmod(diff, 360.0f)
.
should_rotate_forward
确定您应该减小还是增大当前角度。注意 ^
是异或运算
offset
基本上是 -5.0
或 5.0
,具体取决于条件,但也有 +360.0f
,例如 m_Rotation == 1.0
和 offset == -5.0
所以 fmod(m_Rotation + offset, 360.0f)
将是 -4.0
而你想要 356.0
,所以你添加完整的 360 度旋转并且在 fmod
之后一切都是积极的并且在 [0; 360) 范围