我在游戏中有两个向量。一个向量是玩家,一个向量是一个对象。我还有一个向量,指定玩家面对的方向。方向矢量没有z部分。这个点的大小为1,位于原点附近。
我想计算士兵当前面对的方向与物体之间的角度,所以我可以正确地平移一些音频(仅限立体声)。
下图描述了我的问题。我想计算两条虚线之间的角度。一条虚线连接玩家和物体,另一条线代表玩家从玩家所在点朝向的方向。
目前,我正在这样做(假设玩家,物体和方向都是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);
}
答案 0 :(得分:9)
在计算角度增量时,你总是使用atan2
,然后进行标准化。
原因是例如acos
是域-1 ... 1的函数;如果输入绝对值(由于近似值)大于1,即使很明显在这种情况下你会喜欢0或PI的角度,函数也会失效。另外acos
无法测量整个范围-PI..PI,您需要使用显式符号测试来查找正确的象限。
相反atan2
只有奇点位于(0, 0)
(当然,计算角度没有意义),其codomain是完整的圆-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
答案 1 :(得分:1)
在3D空间中,您还需要计算the axis:
Vector3d axis = normalise(crossProduct(normalise(v1), normalise(v2)));