四边形的二维旋转

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)

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

我认为正确的解决方案应该如下:

我们称这两个角为fromto。根据您的问题,我认为两者都处于正数。有两种情况:

  • 绝对距离|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,交换 fromto,但为了明确起见,我像以前一样保留它们。
    • 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.05.0,具体取决于条件,但也有 +360.0f,例如 m_Rotation == 1.0offset == -5.0 所以 fmod(m_Rotation + offset, 360.0f) 将是 -4.0 而你想要 356.0,所以你添加完整的 360 度旋转并且在 fmod 之后一切都是积极的并且在 [0; 360) 范围