从两点和方向向量计算角度 [英] Calculate Angle from Two Points and a Direction Vector

查看:854
本文介绍了从两点和方向向量计算角度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在游戏中有两个向量.一个向量是玩家,一个向量是对象.我还有一个向量,它指定玩家面对时的方向.方向向量没有z部分.这个点的大小为1,位于原点周围.

I have two vectors in a game. One vector is the player, one vector is an object. I also have a vector that specifies the direction the player if facing. The direction vector has no z part. It is a point that has a magnitude of 1 placed somewhere around the origin.

我想计算士兵当前所面对的方向与物体之间的夹角,以便可以正确平移一些音频(仅限立体声).

I want to calculate the angle between the direction the soldier is currently facing and the object, so I can correctly pan some audio (stereo only).

下图描述了我的问题.我想计算两条虚线之间的角度.一条虚线连接玩家和对象,另一条虚线表示玩家从其所处的点朝向的方向.

The diagram below describes my problem. I want to calculate the angle between the two dashed lines. One dashed line connects the player and the object, and the other is a line representing the direction the player is facing from the point the player is at.

此刻,我正在这样做(假设播放器,对象和方向都是具有x,y和z 3点的矢量):

At the moment, I am doing this (assume player, object and direction are all vectors with 3 points, x, y and z):

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

但这似乎给了我错误的结果.有什么建议吗?

But it seems to give me incorrect results. Any advice?

代码测试:

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);
}

推荐答案

计算角度增量时应始终使用atan2,然后进行归一化. 原因是例如acos是域为-1 ... 1的函数;即使输入绝对值(由于近似值)大于1而进行归一化,即使很明显在这种情况下,您本来希望使用0或PI角,函数也会失败.同样,acos无法测量-PI..PI的整个范围,因此您需要使用显式符号测试来找到正确的象限.

You shoud always use atan2 when computing angular deltas, and then normalize. The reason is that for example acos is a function with domain -1...1; even normalizing if the input absolute value (because of approximations) gets bigger than 1 the function will fail even if it's clear that in such a case you would have liked an angle of 0 or PI instead. Also acos cannot measure the full range -PI..PI and you'd need to use explicitly sign tests to find the correct quadrant.

相反,只有atan2的奇点位于(0, 0)(当然,计算角度没有意义),并且其共域是完整的圆-PI ... PI.

Instead atan2 only singularity is at (0, 0) (where of course it doesn't make sense to compute an angle) and its codomain is the full circle -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;

对于一般的3D方向,您需要两个正交方向,例如鼻子指向的向量和右耳的向量. 在这种情况下,公式只是稍微复杂一点,但是如果您方便使用点积,则公式会更简单:

In the case of a general 3d orientation you need two orthogonal directions, e.g. the vector of where the nose is pointing to and the vector to where your right ear is. In that case the formulas are just slightly more complex, but simpler if you have the dot product handy:

// 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

这篇关于从两点和方向向量计算角度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆