2D вращение квадрата - PullRequest
       18

2D вращение квадрата

2 голосов
/ 10 июля 2020

Я работаю над программой моделирования basi c с использованием C ++, и у меня есть средство визуализации, использующее OpenGL. Я визуализирую квадроциклы на экране, которые в симуляции имеют место динамического c. Моя цель - изменить ориентацию квадроцикла, когда он движется в симуляции. Для каждого квадрата у меня есть переменная (m_Rotation), которая содержит текущее вращение, и я вычисляю необходимое вращение с помощью тригонометрии и помещаю значение в переменную (m_ProjectedRotation). В рендере l oop я использую следующий код для изменения ориентации в движении:

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)

должно отличаться, чтобы показать требуемое поведение. Однако я не мог этого понять. Как мне обновить этот код, чтобы получить то, что я хочу?

Ответы [ 2 ]

1 голос
/ 10 июля 2020

Я бы сделал что-то вроде этого:

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 определяет, следует ли вам уменьшить или увеличить текущий угол. Обратите внимание, что ^ - это операция XOR

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) диапазон

1 голос
/ 10 июля 2020

Я считаю, что правильное решение должно быть следующим:

Назовем эти два угла from и to. Я предполагаю, что оба в положительной степени согласно вашему вопросу. Возможны два случая:

  • абсолютное расстояние |to - from| меньше 180. Это означает, что на to - from меньше градусов, чем в другом направлении, и , что - это путь, который вам следует выбрать. В этом случае вы должны повернуть на sign(to-from) * deltaRotation, где sign(x) = 1, если x> 0, и -1 в противном случае. Чтобы увидеть необходимость функции знака, посмотрите следующие 2 примера, где |to - from| <180: <ul>
  • from = 10, to = 20. to - from = 10> 0, поэтому вам следует увеличить поворот.
  • от = 20, до = 10. до - от = -10 <0, вы должны <em>уменьшить поворот.
|to - from| больше 180. В этом случае направление должно быть обратным, и вы должны повернуть на - sign(to-form) * deltaRotation, обратите внимание на знак минус. Вы также можете express это как sign(from-to) * deltaRotation, поменяв местами from и to, но я оставил их, как прежде, для ясности.
  • from = 310, to = 10. Затем, чтобы - from = -300 <0, вы должны <em>увеличить поворот (Формально -sign (to-from) = -sign (- 300) = - (- 1) = 1)
  • from = 10, to = 310. Затем, чтобы - from = 300> 0, вы должны уменьшить поворот (Формально, -sign (to-from) = -sign (300) = -1)

Написав это на C ++, вы можете инкапсулировать этот logi 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.)

...