Интерполировать Вверх Линейно, когда Вверх действительно не Вверх? - PullRequest
0 голосов
/ 05 января 2019

Обзор

Я какое-то время оглядывался по сторонам и не нашел ответа, так что, надеюсь, сообщество здесь может мне помочь. Я перерабатываю свою камеру для наблюдения (написано до 2000 года) и испытываю трудности с устранением проблемы, когда векторы обзора и поворота выровнены, из-за чего камера выходит из-под контроля. Первоначально я понимал, что это блокировка карданного подвеса, но теперь я не уверен в этом.

Из моего понимания блокировки карданного подвеса, когда высота звука выравнивается по крену, высота становится креном; и, по сути, это то, чем оно кажется, но проблема в том, что скорость изменения не должна увеличиваться только потому, что оси выровнены, я должен просто получить плавный крен. Вместо этого я получаю жестокий бросок, в котором я не могу точно сказать, в каком направлении идет бросок.


Обновление положения камеры

Когда пользователь перемещает мышь, я перемещаю камеру на основе координат X и Y мыши:

Vector2 mousePosition = new Vector2(e.X, e.Y);
Vector2 delta = mousePosition - mouseSave;
mouseSave = mousePosition;

ShiftOrbit(delta / moveSpeed);

В методе ShiftOrbit я вычисляю новую позицию на основе векторов обзора, справа и вверх по отношению к delta, переданному из события мыши выше:

Vector3 lookAt = Position - Target;
Vector3 right = Vector3.Normalize(Vector3.Cross(lookAt, Up));
Vector3 localUp = Vector3.Normalize(Vector3.Cross(right, lookAt));

Vector3 worldYaw = right * delta.X * lookAt.Length();
Vector3 worldPitch = localUp * delta.Y * lookAt.Length();
Position = Vector3.Normalize(Position + worldYaw + worldPitch) * Position.Length();

Это работает плавно, как и должно, и перемещает камеру вокруг цели в любом направлении по моему выбору.


Матрица просмотра

Здесь я испытываю проблему, упомянутую в обзоре выше. Мое свойство Up ранее было установлено всегда 0, 0, 1 из-за того, что мои данные были в координатах ECR. Тем не менее, это то, что вызывает выравнивание оси, когда я перемещаю камеру, и матрица вида обновляется. Я использую SharpDX метод Matrix.CreateLookAtRH(Position, Target, Up), чтобы создать свою матрицу вида.

Обнаружив, что вектор Up, используемый при создании матрицы представления, должен обновляться, а не всегда быть 0, 0, 1, я столкнулся с другой проблемой. Я теперь вызвал крен, когда были введены рыскание и тангаж. Это не должно происходить из-за требования, поэтому я немедленно начал искать исправление.

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

float dot = Math.Abs(Vector3.Dot(Up, Position) / (Up.Length() * Position.Length()));
if (dot > 0.98)
    Up = localUp;
else
    Up = new Vector3(0, 0, localUp.Z);

Однако, это было немного нервно и все еще не казалось правильным. После некоторых проб и ошибок, наряду с обширными исследованиями в Интернете, пытаясь найти потенциальные решения, я вспомнил, как линейная интерполяция может плавно переходить от одного значения к другому в течение определенного периода времени. Затем я перешел к использованию Vector3.Lerp вместо:

float dot = Math.Abs(Vector3.Dot(Up, Position) / (Up.Length() * Position.Length()));
Up = Vector3.Lerp(new Vector3(0, 0, localUp.Z), localUp, dot);

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


Проблема

Моя камера также может прикрепляться к точке, отличной от 0, 0, 0, и в этом случае вектор повышения для камеры устанавливается на нормализованное положение цели. Это вызывает исходную проблему в обзоре при использовании Vector3.Lerp, как указано выше; Итак, в случае, когда моя камера подключена к точке, отличной от 0, 0, 0, вместо этого я делаю следующее:

Up = Vector3.Lerp(Vector3.Normalize(Target), localUp, dot);

Однако даже это не работает, и я понятия не имею, как заставить это сделать это. Я работал над этой проблемой уже несколько дней и приложил немало усилий, чтобы ее исправить, и это пока большое улучшение.


Что я могу сделать, чтобы предотвратить насильственное вращение, используя Vector3.Lerp, когда повышение не эквивалентно 0, 0, z?

1 Ответ

0 голосов
/ 05 января 2019

Представьте себе вертикальную плоскость, которая поворачивается вокруг вертикальной оси на yaw (ϕ):

enter image description here

Камера может вращаться только с плоскостью или в плоскости, ее ориентация в плоскости определяется pitch (θ):

enter image description here

ϕ и θ должны быть сохранены и увеличены с входной дельтой. При такой настройке камера никогда не наклонится, и всегда можно рассчитать локальное направление вверх:

enter image description here

d и u являются местными направлениями спереди и вверх соответственно и всегда перпендикулярно (поэтому выравнивание не будет проблемой). Конечно, цель может быть принята за позицию + d.

Но подождите, есть подвох.


Предположим, вы двигаете мышь вправо; ϕ увеличивается, и вы наблюдаете:

  • Если камера в вертикальном положении, вид поворачивается вправо.
  • Если камера перевернута, изображение поворачивается влево.

В идеале это должно быть согласовано независимо от вертикальной ориентации.

Решение состоит в том, чтобы перевернуть знак приращений до ϕ, когда камера перевернута. Одним из способов было бы масштабирование приращений на cos(θ), что также плавно снижает чувствительность при приближении θ к 90/270 градусам, чтобы не было внезапных изменений в горизонтальном направлении вращения.

...