Как вычислить значения высоты тона и рыскания от вектора вперед - PullRequest
1 голос
/ 24 февраля 2020

Я хочу вычислить значения шага и рыскания камеры на основе положения и целевых точек, которые получает камера, когда она создается. Если я установлю шаг на 0 и отклонюсь от -90 (как в LearnOpenGL Camera Tutorial ), когда произойдет первый поворот, камера внезапно прыгнет; после этого вращение работает правильно. Итак, во-первых, начиная с уравнений, приведенных в этом уроке, я попытался получить значения высоты тона и рыскания от прямого вектора:

float pitch = glm::degrees(glm::asin(forward.y));
float yaw = glm::degreees(glm::acos((float)x/glm::cos(glm::asin(y))));

Но также

float yaw = glm::degreees(glm::asin((float)z/glm::cos(glm::asin(y))));

И cos (sin (y )) не должно быть 0, поэтому у не должно быть 0 или -1. Я пытался реализовать их, но 2 значения yaw не совпадают, также первое значение yaw, кажется, то, что я ищу, но высота тона - нет. После этого я попробовал простой подход, зная, что шаг - это угол между прямым вектором и осью y, а yaw - это угол между прямым вектором и осью x, я попытался вычислить (на бумаге) следующее:

const glm::vec3 yUnit(0, 1, 0);
const glm::vec3 xUnit(1, 0, 0);
float pitch = glm::degrees(glm::acos(glm::dot(forward, yUnit)));
float yaw = glm::degrees(glm::acos(glm::dot(forward, xUnit)));

Со следующими 2 входами: позиция = (0, 0, 0), цель = (0, 1, 2,5), вперед = цель - позиция = (0, 1, 2.5), нормализовано вперед ~ (0, 0,37, 0,926), результаты имеют наклон ~ 68 градусов и рыскание = 90 градусов. Кроме того, я напечатал значения высоты тона и рыскания внутри приложения, и ожидаемые значения должны быть pitch = -20 и yaw = -90.

Можете ли вы объяснить мне, если я ошибаюсь, почему и где я допустил ошибку

Ответы [ 2 ]

0 голосов
/ 25 февраля 2020

на основе ваших ожидаемых значений кажется, что ваш шаг должен варьироваться от -90 до 90 градусов, поэтому вы должны использовать asin вместо acos для высоты тона.

при расчете рыскания, вам нужно спроецировать вперед вектор на плоскость xz. Вы можете сделать это, установив компонент y в ноль, а затем нормализовав его.

В этом случае угол поворота должен изменяться в диапазоне от 0 до 360 градусов, а acos возвращается только в диапазоне от 0 до 180 градусов. рыскание будет правильным для первых 180 градусов, но по мере увеличения рыскания от 180 до 360, акос уменьшится с 180 до нуля. когда скалярное произведение между прямым вектором и (0,0,1) больше нуля, отклонение от вертикальной оси будет больше 180 градусов, и поэтому значение acos следует откорректировать, вычтя его из 360.

исходя из ваших ожидаемых значений, я предполагаю правильные значения рыскания и тангажа

pitch = degrees(-asin(dot(forward, y_unit)))
forward.y = 0
forward = normalize(forward)
yaw = degrees(acos(dot(forward, x_unit)))
if(dot(forward, z_unit) > 0)
    yaw = 360 - yaw
0 голосов
/ 25 февраля 2020

Невозможно указать ни одну строку для изменения, но есть предложения:

, когда происходит первый поворот, камера внезапно прыгает

Это признак того, что что-то не инициализируется к тому, что вы думаете. В этом случае тангаж и рыскание являются производными значениями, которые можно рассчитать по прямому вектору, верно? Когда вы получили производные значения, вы никогда не должны инициализировать их напрямую, потому что есть вероятность, что вы ошибетесь. Если два значения, которые должны быть «одинаковыми», различны, произойдут странные вещи. Вместо этого инициализируйте прямой вектор и сразу рассчитайте его высоту и рыскание.

И cos (sin (y)) не должно быть 0

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

Тем не менее, вы можете проверить, что происходит, когда передний вектор равен (0, 0, 0). Удивительно, что в графическом программировании как-то получается получить нулевой вектор.

float yaw = glm :: градусов (glm :: acos ((float) x / glm :: cos (glm :: asin) (у))));

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

Простой случай, когда рыскание (курс), наклон и крен независимы углы, так что рыскание не меняется, если высота тона меняется, и наоборот. Ваш последний кодовый блок с векторами xUnit и yUnit, кажется, делает это.

Однако в авиасимуляторах и в аэрокосмических расчетах рывок-тангаж немного сложнее, потому что они не независимы. Угол поворота может быть измерен в плоскости тангажа, а не в абсолютном XZ. А аэрокосмический рывок часто измеряется с «севера» оси Z, а не X. Таким образом, вы должны четко понимать, какой тип рыскания и тангажа вы измеряете, и быть последовательными во всем. И вам нужно изучить любые учебные примеры или код, чтобы выяснить, как они используют тональность и тональность, и соответствует ли она вашим.

Я предлагаю сейчас придерживаться простых однокоординатных мер.

float pitch = glm :: градусов (glm :: acos (glm :: dot (forward, yUnit)));

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

И вы проверили, что ваша математическая библиотека имеет значения за пределами от -180 до 180 градусов? Еще одна вещь, о которой стоит беспокоиться.

Надеюсь, это поможет. Если вы находите углы Эйлера беспокойными и раздражающими, вы не одиноки! Вот почему многие книги и учебники по 3D рекомендуют изучать кватернионы.

...