四边形的 2D 旋转

2D rotation of a quad

本文关键字:旋转 2D 四边形      更新时间:2023-10-16

我正在使用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)

应该有所不同以显示所需的行为。但是,我无法弄清楚。我应该如何更新此代码以获得我想要的内容?

我相信正确的解决方案应该如下:

让我们称这两个角度为fromto。根据您的问题,我认为两者都是积极的。有两种情况:

  • 绝对距离|to - from|小于 180.
    这意味着行进to - from的度数比在另一个方向上的行进要小,这就是您应该选择的方式.
    在这种情况下,您应该旋转sign(to-from) * deltaRotation,其中sign(x)= 1 如果 x> 0,否则为 -1。要查看符号函数的需求,请查看以下 2 个示例,其中|to - from|<180: 从 = 10,到 =
    • 20。 到 - 从 = 10> 0,因此您应该增加旋转。
    • 从 = 20,到 = 10。
    • 到 - 从 = -10 <0,您应该减少旋转。
  • |to - from|超过180。在这种情况下,方向应该是相反的,你应该旋转- sign(to-form) * deltaRotation,注意减号。你也可以用sign(from-to) * deltaRotation来表达,交换fromto,但我把它们留作以前,为了明确起见。
    • 从 = 310,到 = 10。然后,到 - from = -300 <0,您应该增加旋转(形式上,-sign(to-from
    • ) = -sign(-300) = -(-1) = 1)
    • 从 = 10,到 = 310。然后,到 - 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是旋转的绝对角度。然后,通过执行diff = fmod(diff, 360.0f)使其处于 [0; 360) 范围内。

should_rotate_forward确定是应减小还是增加当前角度。请注意,^是异或操作

offset基本上是-5.05.0,具体取决于条件,但也有一些+360.0f,例如,如果m_Rotation == 1.0offset == -5.0,那么fmod(m_Rotation + offset, 360.0f)在您想要356.0时会-4.0,所以你添加完整的360旋转,之后fmod一切都是积极的,并且在[0; 360)范围内