Как уберечь мою камеру Quaternion-FPS от наклона и ошибок?

17

Я использую FPS-подобную камеру, и она использует кватернионы. Но всякий раз, когда я пытаюсь смотреть вверх, а затем в сторону, он наклоняется, а иногда он может перевернуться с ног на голову. Как я могу это исправить?

Aeodyn
источник
3
(Самостоятельно ответит через 7 часов) ...
Aeodyn

Ответы:

16

Вы можете разложить кватернион на набор углов отклонения / рыскания / крена, но обычно это излишне.

Вместо того, чтобы составлять свои кватернионы, как это:

cameraOrientation = cameraOrientation * framePitch * frameYaw;

Попробуй это:

cameraOrientation = framePitch * cameraOrientation * frameYaw;

Тогда он никогда не будет генерировать наклон / крен и эквивалентен хранению рыскания и тангажа отдельно

ltjax
источник
3
Эта. Это именно то, что я искал. Решил мою проблему в одну строчку. Ницца!
aardvarkk
1
Есть framePitchи frameYaw floatтипы? Кроме того, я был бы признателен за разъяснения по поводу вашего первого предложения.
Сирданк
1
@sirdank cameraOrientation, framePitchи frameYawвсе кватернионы (каждый кватернион равен 4 числам с плавающей запятой или двойным числам ).
Дан
8

Это проблема, которая у меня возникла некоторое время, и я не мог найти ответы на нее, поэтому я решил опубликовать ее здесь.

Это на самом деле довольно просто. То, как вы, скорее всего, делаете повороты, выглядит так:

currentDirection * newRotation;

Но делать это так же не получается.

newRotation * currentDirection;

То, что вам нужно сделать, это сделать это в первом порядке для вращений вверх и вниз и во втором порядке для боковых вращений.

Для меня это было так:

        if (keyboard.IsKeyDown(Keys.Up))
            Direction = Direction * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), TurnSpeed);
        if (keyboard.IsKeyDown(Keys.Down))
            Direction = Direction * Quaternion.CreateFromAxisAngle(new Vector3(-1, 0, 0), TurnSpeed);
        if (keyboard.IsKeyDown(Keys.Left))
            Direction = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), TurnSpeed) * Direction;
        if (keyboard.IsKeyDown(Keys.Right))
            Direction = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), TurnSpeed) * Direction;

По какой-то причине первый способ имеет вращение относительно текущего бокового направления, которое требуется для перемещения вверх и вниз, но вы не хотите этого для боковых вращений, поэтому необходим второй порядок.

Aeodyn
источник
Мне пришлось ждать 7 часов, чтобы ответить на мой собственный ...
Aeodyn
извините, вы можете объяснить это некоторыми скриншотами? «первый порядок» и «второй порядок» немного сбивают с толку - спасибо!
Atav32
При работе с кватернионами порядок имеет значение, как это всегда имеет место с трехмерными вращениями. В моем примере «Direction * = newRotation» совпадает с «Direction = Direction * newRotation». Но, с левым и правым вращением, мы хотим наоборот. Это делает его не зависимым от наклона вверх и вниз, что вызывает крен.
Aeodyn
О, хотя я и думал, что дело в том, что он избежал блокировки карданного подвеса, и все вращения были независимы, но я, возможно, неправильно прочитал учебник. Итак, просто чтобы уточнить, вы говорите, что если вы измените порядок преобразования вращения, вы можете предотвратить наклон камеры? Или вы вручную устанавливаете преобразования крена и тангажа в 0 при повороте рыскания?
Atav32
5

Для камеры FPS вы обычно не хотите вращаться и ограничены с шагом +/- 90 градусов, поэтому я бы просто отслеживал текущее состояние, используя углы поворота и рыскания. Полная сила кватернионов не очень полезна для этого.

Вы все еще можете конвертировать углы рыскания / тангажа в кватернионы и из них в случае, если вы хотите переключиться между камерой FPS и анимированными камерами, используя кватернионную интерполяцию ключевых кадров или что-то в этом роде.

Натан Рид
источник
0

Другой простой трюк - поместить камеру в объект GameObject и заставить вращение Yaw управлять игровым объектом, в то время как дочерняя камера настроена с помощью координат высоты тона:

playerCameraHolder.transform.Rotate(0, rotationYaw, 0);
playerCamera.transform.Rotate(rotationPitch, 0, 0);
Виктор С
источник