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

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, поэтому y не должно быть 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.

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

1
Vali Deaconu 24 Фев 2020 в 11:36

2 ответа

Лучший ответ

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

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

Отклонение от вертикальной оси должно колебаться от 0 до 360 градусов, но акос возвращается только от 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
phry 25 Фев 2020 в 00:40

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

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

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

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

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

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

float yaw = glm :: deges (glm :: acos ((float) x / glm :: cos (glm :: asin (y))));

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

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

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

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

шаг с плавающей точкой = glm :: градусов (glm :: acos (glm :: точка (вперед, yUnit)));

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

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

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

0
Hugh Fisher 24 Фев 2020 в 22:23