Как предотвратить ошибки с плавающей точкой в ​​векторах камеры - PullRequest
2 голосов
/ 15 марта 2011

На другой вопрос пользователь, который ответил (Рикки) мне, также сказал следующее (что я все еще нахожу немного запутанным):

Когда я говорю, что они должны оставаться перпендикулярно, я имею в виду, что если вы вращать векторы независимо друг от друга одно и то же преобразование снова и снова, ошибки с плавающей точкой могут закрадываться и они могут отличаться от перпендикуляр. Точка (x, y), точка (y, z) и точка (x, z) должна быть очень близка к нулю. Если нет, вам нужно сделать кросс продукты и перпендикулярно их. Это так же просто, как перезапись z = крест (х, у), тогда у = крест (z, х).

В моей системе камер есть 3 соответствующих вектора, эти векторы являются числами с плавающей запятой и всегда нормализованы. Опорные векторные точки в направлении, куда смотрит камера, UpVector и RightVector говорят сами за себя.

Любой, кто знает, как ответить, должен ответить, конечно, но Рики, если ты там, пожалуйста, помоги мне ...

1) Что именно означает точка (x, y), точка (y, z) и точка (x, z)? Это произведение точек между этими векторами? Я полагаю ... Но какие (x, y, z) соответствуют моим ссылкам, UpVector и RightVector? Я немного растерялся ...

2) Тогда эти точечные произведения должны быть очень близки к нулю, как именно это проверить? Я видел такой код, чтобы добиться того же в подобном контексте:

const float Math::EPSILON = 1e-6f;

Math::closeEnough(<floating_point_variable_to_check>, 0.0f);

static bool closeEnough(float f1, float f2) {
    // Determines whether the two floating-point values f1 and f2 are
    // close enough together that they can be considered equal.

    return fabsf((f1 - f2) / ((f2 == 0.0f) ? 1.0f : f2)) < EPSILON;
}

Полагаю, это достаточно хорошо?

3) Где мне в точности выполнить все эти проверки и заново перпендикулярно векторам? У меня есть 3 функции, которые вращают камеру, Pitch, Yaw и Roll (последняя, ​​которую я так мало использую), только эти функции изменяют эти единицы измерения. Должен ли я выполнять проверки и исправления каждый раз, когда вызываю одну из этих функций поворота, или это будет слишком много? Где и когда тогда?

4) И последнее, но не менее важное: чтобы исправить их, нужно переписать векторы перекрестным произведением, имеет смысл, поскольку я хочу, чтобы они были перпендикулярны друг другу. Но разве в приведенной выше цитате отсутствует один кросс-продукт? И имеет ли значение порядок, в котором я выполняю эти исправления?

Ответы [ 3 ]

5 голосов
/ 15 марта 2011

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

Матрица вращения - это просто матрица с тремя векторами (например, вверх, вправо, вперед) в качестве трех столбцов.Рассмотрим матрицу с тремя векторами e1 = вправо, e2 = вверх, e3 = назад.Затем, чтобы преобразовать точку в ту же систему отсчета, что и матрица, вы предварительно умножаете вектор столбца на

[ e1_x  e2_x  e3_x ]
[ e1_y  e2_y  e3_y ]
[ e1_z  e2_z  e3_z ]

(или наоборот ... Я всегда путаю язык в зависимости от того, как вы к нему относитесь.Кроме того, OpenGL использует матрицы 4x4 в качестве трюка для применения переводов или даже перспективы только с одной матрицей.) В любом случае, вы можете получить любой из трех векторов, скрестив два других.то есть e1 = e2 x e3, e2 = e3 x e1 и e3 = e1 x e2 Это означает, что один вектор не нужен.Один меньший вектор оставляет шесть чисел.Длина двух оставшихся векторов не имеет значения - важно только направление - в результате остается четыре числа, необходимых для описания преобразования.Введите кватернионы.Это математический инструмент, который работает с остальными четырьмя числами стабильным и надежным способом.Если вы используете все девять чисел, вам просто нужно убедиться, что векторы всегда имеют длину 1 и что любое перпендикулярно двум другим.В противном случае это не совсем матрица вращения.Вверх не может быть на 90 градусов справа.Вот почему я предложил:

e1 = Normalize(e1);
e3 = Normalize(Cross(e1,e2));  // e3 is now perpendicular to e1 and e2, and
                               // probably hasn't changed much.  It will also 
                               // have length 1.
e2 = Normalize(Cross(e3,e1));  // e2 was perpendicular to e3 from the previous
                               // step, but now it's also perpendicular to e1.

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

1 голос
/ 15 марта 2011

1) Точка (x, z) означает скалярное произведение между (например) вашим опорным вектором и вашим побочным вектором.Поскольку все эти векторы должны быть перпендикулярными, скалярное произведение any , два из них должны быть равны нулю.

2) Поскольку все ваши векторы (теоретически) нормализованы, вы просто должны быть в состоянии проверить, есть ли fabs (Dot (a, b))

3) Честно говоря, если есть только одна камера, я бы просто перенормировал их каждый кадр - почему бы и нет?

Вот один из подходов:

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

1016 * Возьмите перекрестный продукт вперед (ссылка) вектора с повышающим вектором (0,1,0).Это дает вам побочный вектор, который гарантированно перпендикулярен переднему вектору.Теперь возьмите перекрестное произведение этого нового вектора с прямым вектором.Это дает вам «реальный» вектор подъема камеры - т.е.он будет наклонен вперед на любой угол наклона камеры.
1 голос
/ 15 марта 2011
  1. Да, произведение векторных точек между вашими векторами. х . y = 0, если x и y перпендикулярно.Неважно, какие пары вы выберете, так как каждая из них должна быть перпендикулярна двум другим.

  2. Да, это так

  3. Вездетебе нравится на самом деле.Один раз за кадр перед рендерингом это хорошее место.Идея состоит в том, чтобы не допустить выхода кумулятивных ошибок.

  4. Нет, вам просто нужно исправить два вектора относительно другого (и друг друга),поэтому нужно изменить только два вектора.Выбираете ли вы вектор вперед, вектор вверх или даже правильный вектор - ваш выбор.Выбор «вверх» имеет смысл для случаев, когда вы всегда хотите камеру в вертикальном положении.Порядок подачи заявок не имеет значения, так как исправления должны быть крошечными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...