在3维移动目标上射击弹丸(直线弹道)

时间:2011-01-20 16:44:19

标签: algorithm 3d linear-algebra

我已经用谷歌搜索了问题,但只发现了二维解决方案或不适合我的公式(发现这个公式看起来不错:http://www.ogre3d.org/forums/viewtopic.php?f=10&t=55796但似乎不正确。)

我已经给出了:

Vec3 cannonPos;
Vec3 targetPos;
Vec3 targetVelocityVec;
float bulletSpeed;

我正在寻找的是时间t

targetPos+t*targetVelocityVec

是将大炮瞄准射击的交叉点。

我正在为t寻找一个简单,廉价的公式(简单来说,我的意思是不要进行许多不必要的矢量空间转换等)

谢谢!

1 个答案:

答案 0 :(得分:15)

真正的问题是找出空间中子弹可以与目标路径相交的位置。子弹速度是恒定的,因此在一定的时间内它将以相同的距离行进,而不管我们发射它的方向。这意味着它在时间t之后的位置将始终位于球体上。这是2d中的丑陋插图:

此球体可以数学方式表示为:

(x-x_b0)^2 + (y-y_b0)^2 + (z-z_b0)^2 = (bulletSpeed * t)^2      (eq 1)

x_b0,y_b0和z_b0表示大炮的位置。您可以使用问题中提供的公式求解t的等式来找到时间t:

targetPos+t*targetVelocityVec                                   (eq 2)

(eq 2)是一个向量方程,可以分解为三个独立的方程式:

x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z

这三个方程可以插入(eq 1)

(x_t0 + t * v_x - x_b0)^2 + (y_t0 + t * v_y - y_b0)^2 + (z_t0 + t * v_z - z_b0)^2 = (bulletSpeed * t)^2

该等式仅包含已知变量,可以求解t。通过将二次子表达式的常量部分赋值给常数,我们可以简化计算:

c_1 = x_t0 - x_b0
c_2 = y_t0 - y_b0
c_3 = z_t0 - z_b0
(v_b = bulletSpeed)

(t * v_x + c_1)^2 + (t * v_y + c_2)^2 + (t * v_z + c_3)^2 = (v_b * t)^2

将其重新排列为标准二次方程式:

(v_x^2+v_y^2+v_z^2-v_b^2)t^2 + 2*(v_x*c_1+v_y*c_2+v_z*c_3)t + (c_1^2+c_2^2+c_3^2) = 0

使用标准配方可以轻松解决这个问题。它可以产生零个,一个或两个解决方案。零解决方案(不包括复杂的解决方案)意味着子弹无法到达目标。当目标轨迹与球体的最边缘相交时,很可能很少发生一种解决方案。两种解决方案将是最常见的方案。否定解决方案意味着您无法击中目标,因为您需要将子弹射入过去。这些都是您必须检查的条件。

当你解决了这个等式后,你可以通过将它放回(eq 2)找到t的位置。在伪代码中:

# setup all needed variables
c_1 = x_t0 - x_b0
c_2 = y_t0 - y_b0
c_3 = z_t0 - z_b0
v_b = bulletSpeed
# ... and so on

a = v_x^2+v_y^2+v_z^2-v_b^2
b = 2*(v_x*c_1+v_y*c_2+v_z*c_3)
c = c_1^2+c_2^2+c_3^2

if b^2 < 4*a*c:
    # no real solutions
    raise error

p = -b/(2*a)
q = sqrt(b^2 - 4*a*c)/(2*a)

t1 = p-q
t2 = p+q

if t1 < 0 and t2 < 0:
    # no positive solutions, all possible trajectories are in the past
    raise error

# we want to hit it at the earliest possible time
if t1 > t2: t = t2
else: t = t1

# calculate point of collision
x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z