Вычислить угол из двух точек и вектора направления - PullRequest
4 голосов
/ 03 февраля 2011

У меня есть два вектора в игре.Один вектор - игрок, один вектор - объект.У меня также есть вектор, который указывает направление, на которое игрок смотрит.Вектор направления не имеет z-части.Это точка с величиной 1, расположенная где-то вокруг начала координат.

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

Диаграмма ниже описывает мою проблему.Я хочу рассчитать угол между двумя пунктирными линиями.Одна пунктирная линия соединяет игрока и объект, а другая - линию, представляющую направление, в котором находится игрок, с точки, в которой находится игрок.

Angle Problem

В данный моментЯ делаю это (предположим, что игрок, объект и направление - это все векторы с 3 точками, x, y и z):

Vector3d v1 = direction;
Vector3d v2 = object - player;
v1.normalise();
v2.normalise();
float angle = acos(dotProduct(v1, v2));

Но, похоже, это дает неверные результаты.Любой совет?

Проверка кода:

Vector3d soldier = Vector3d(1.f, 1.f, 0.f);
Vector3d object = Vector3d(1.f, -1.f, 0.f);
Vector3d dir = Vector3d(1.f, 0.f, 0.f);

Vector3d v1 = dir;
Vector3d v2 = object - soldier;

long steps = 360;
for (long step = 0; step < steps; step++) {
    float rad = (float)step * (M_PI / 180.f);
    v1.x = cosf(rad);
    v1.y = sinf(rad);
    v1.normalise();

    float dx = dotProduct(v2, v1);
    float dy = dotProduct(v2, soldier);
    float vangle = atan2(dx, dy);
}

Ответы [ 2 ]

9 голосов
/ 03 февраля 2011

Вы должны всегда использовать atan2 при вычислении угловых дельт, а затем нормализовать. Причина в том, что, например, acos - это функция с доменом -1 ... 1; Даже нормализуя, если входное абсолютное значение (из-за приближений) становится больше 1, функция не будет работать, даже если ясно, что в таком случае вы бы предпочли угол 0 или PI. Также acos не может измерить полный диапазон -PI..PI, и вам нужно будет использовать тесты с явной подписью, чтобы найти правильный квадрант.

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

Вот пример на C ++

// Absolute angle 1
double a1 = atan2(object.y - player.y, object.x - player.x);

// Absolute angle 2
double a2 = atan2(direction.y, direction.x);

// Relative angle
double rel_angle = a1 - a2;

// Normalize to -PI .. +PI
rel_angle -= floor((rel_angle + PI)/(2*PI)) * (2*PI) - PI;

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

// I'm assuming that '*' is defined as the dot product
// between two vectors: x1*x2 + y1*y2 + z1*z2
double dx = (object - player) * nose_direction;
double dy = (object - player) * right_ear_direction;
double angle = atan2(dx, dy); // Already in -PI ... PI range

enter image description here

1 голос
/ 03 февраля 2011

В трехмерном пространстве вам также необходимо вычислить ось :

Vector3d axis = normalise(crossProduct(normalise(v1), normalise(v2)));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...