Как проверить, смотрят ли векторы в одном направлении

Я работаю над вопросом, в котором я работаю в правой системе координат, где ось Y направлена ​​прямо вверх. Мне предоставлена ​​структура, представляющая трехмерный вектор, который выглядит следующим образом:

struct vec{float x; float y; float z; };

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

PlayerDirection = sqrt((PlayerVector.x *= PlayerVector.x)
                     + (PlayerVector.y *= PlayerVector.y)
                     + (PlayerVector.z *= PlayerVector.z));

Но я не знаю, что делать дальше. Любая помощь / объяснение поможет, спасибо.


person user9564128    schedule 28.03.2018    source источник
comment
*= следует заменить на *.   -  person Jarod42    schedule 28.03.2018
comment
Взгляните на Dot_product.   -  person Jarod42    schedule 28.03.2018


Ответы (4)


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

person RAM    schedule 28.03.2018
comment
Скалярное произведение симметрично, поэтому этот подход не работает. Симметричный в данном контексте означает, что невозможно оценить, равен ли реальный угол 10 ° или 350 °. - person Y.S; 28.03.2018
comment
@ Y.S В этом контексте эти углы эквивалентны. OP хотят вернуться, если [игрок] смотрит больше на север, чем на юг. - person patatahooligan; 28.03.2018
comment
@ Y.S. это не имеет значения. Единичные векторы севера и юга - это один и тот же вектор с противоположным направлением, поэтому скалярное произведение каждого вектора будет отличаться только сигналом результата. Кроме того, 10 градусов и 350 градусов - это один и тот же угол, поэтому оба они эквивалентны в этом отношении. - person RAM; 28.03.2018

Формула, которую вы включаете (и которая содержит ошибку - продукт «*», а не «* =»), дает вам сущность движения - длину вектора. Что вы уже знаете, поскольку это вектор unit и, следовательно, его длина равна 1.

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

«Севернее, чем юг» означает, что скалярное произведение положительно, поэтому:

вернуться, если они смотрят больше на север, чем на юг

Alignment =  ((PlayerVector.x * NorthVector.x)
            + (PlayerVector.y * NorthVector.y)
            + (PlayerVector.z * NorthVector.z));

return (Alignment > 0);

Вопросов

Что, если бы я хотел сказать, смотрит ли он на восток / запад?

Точечное произведение показывает, насколько выровнены два вектора. Это та же формула, которую показал Кевин Глассон, без норм единичных векторов, поскольку они равны 1, и деление на единицу ничего не меняет.

Таким образом, вы не можете использовать его, чтобы определить, где обращен вектор , кроме как с точки зрения другого вектора. Вот почему вам дан северный вектор; с одним только вектором игрока вы не можете запустить скалярное произведение. Чтобы определить, смотрит ли игрок на восток, вам нужен вектор на восток (или вектор на запад, а затем выберите противоположный знак).

Итак, если число возвращается, скажем, 35, это означает, что он смотрит больше на север, чем на юг, но почему?

Почему это так: вы можете найти объяснение на странице Википедии, скалярное произведение равно произведению двух длин на косинус их угла. Поскольку обе длины равны 1, это просто косинус. Косинус варьируется от 1 до -1 (так что вы никогда не получите 35). Когда косинус равен 1, это означает, что угол равен нулю и векторы выровнены; когда -1, они противоположны. Нулевой косинус означает, что векторы перпендикулярны друг другу, т. Е. Образуют угол 90 °, и в этом случае это означает, что игрок смотрит либо на восток, запад, либо вверх, либо вниз - но он не говорит вам, какой.

person LSerni    schedule 28.03.2018
comment
Я не понимаю, что происходит со значением Alignment. Итак, если число возвращается, скажем, 35, это означает, что он смотрит больше на север, чем на юг, но почему? Что, если бы я хотел сказать, смотрит ли он на восток / запад? - person user9564128; 28.03.2018
comment
Не могли бы те, кто проголосовал против, объяснить, в чем проблема с ответом ...? При необходимости ответ может быть изменен. - person LSerni; 13.04.2020

Я думаю, что будет работать, если взять «точечный продукт» векторов. Используя следующую форму:

введите здесь описание изображения

Где бы вы перестроили тэту. Это даст вам угол между двумя векторами.

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

Я не знаю точно, как вы собираетесь это использовать, но это должно сработать, чтобы можно было отличить север от юга в трехмерном пространстве.

person Kevin Glasson    schedule 28.03.2018

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

cos(phi) = (a * b) / (|a|*|b|)

Что преобразуется в это:

phi = acos((ax*bx + ay*by + az * bz) / (sqrt(ax^2 + ay^2 + az^2)+sqrt(bx^2 + by^2 + bz^2)))

Теперь скалярное произведение симметрично, что означает: (1,1,1) (2,2,2) дает тот же результат, что и (2,2,2) (1,1,1) . Следовательно, вам нужно добавить еще один шаг. Добавляя третий вектор, угол которого к первому заданному вектору вам известен, вы можете проверить истинный угол между двумя векторами. Отказ от привязки к этому опорному вектору можно выполнить, повернув первый вектор вокруг оси; теперь, чтобы убедиться, что это действительная опорная точка, он должен находиться в той же плоскости, что и векторы a и b. Это означает, что ваша ось для поворота вашего первого вектора должна быть ортогональна векторам 1 и 2, векторное произведение двух векторов дает вектор, ортогональный обоим, поэтому мы будем использовать полученный таким образом вектор в качестве оси.

axis = a x b

Это равно:

axis = (aybz-azby, azbx-axbz, axby-aybx)

Чтобы повернуть вектор на заданную величину вокруг оси, необходимо сделать следующее:

double R[3][3] = {};
            Vector axis = Axis.getUnitVector();
            double deg = degrees / 180 * M_PI;
            R[0][0] = axis.X * axis.X * (1 - cos(deg)) + cos(deg); R[0][1] = axis.X * axis.Y * (1 - cos(deg)) - axis.Z * sin(deg); R[0][2] = axis.X * axis.Z * (1 - cos(deg)) + axis.Y * sin(deg);
            R[1][0] = axis.Y * axis.X * (1 - cos(deg)) + axis.Z * sin(deg); R[1][1] = axis.Y * axis.Y * (1 - cos(deg)) + cos(deg); R[1][2] = axis.Y * axis.Z * (1 - cos(deg)) - axis.X * sin(deg);
            R[2][0] = axis.Z * axis.X * (1 - cos(deg)) - axis.Y * sin(deg); R[2][1] = axis.Z * axis.Y * (1 - cos(deg)) + axis.X * sin(deg); R[2][2] = axis.Z * axis.Z * (1 - cos(deg)) + cos(deg);
            double x = this->X * R[0][0] + this->Y * R[0][1] + this->Z * R[0][2];
            double y = this->X * R[1][0] + this->Y * R[1][1] + this->Z * R[1][2];
            double z = this->X * R[2][0] + this->Y * R[2][1] + this->Z * R[2][2];

Единичный вектор определяется следующим образом:

e_a = (ax / sqrt(ax^2+ay^2+az^2),ay / sqrt(ax^2+ay^2+az^2),az / sqrt(ax^2+ay^2+az^2))

Используя эту новую ось, мы можем повернуть наш первый вектор на 90 °. Вычислив угол между нашей ссылкой и вторым вектором, мы можем теперь оценить реальный угол между первым и вторым векторами. Если угол к точке отсчета больше 90 °, 2-й вектор находится в 3-м или 4-м секторе или в декартовой системе координат, что означает, что для получения реального угла нам придется вычесть полученный угол между первым и 2-м векторами из 360 °. Если угол относительно опорной точки меньше 90 °, вычисленный угол является действительным.

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

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

edit: / поскольку вы указываете север и вектор игрока, просто вычислите угол между ними.

person Y.S    schedule 28.03.2018