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

Mat*_*Mat 8 algorithm 3d linear-algebra

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

我给了:

Vec3 cannonPos;
Vec3 targetPos;
Vec3 targetVelocityVec;
float bulletSpeed;
Run Code Online (Sandbox Code Playgroud)

我正在寻找的是时间这样的

targetPos+t*targetVelocityVec
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢!

Emi*_*l H 15

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

该球体可以用数学表达为:

(x-x_b0)^2 + (y-y_b0)^2 + (z-z_b0)^2 = (bulletSpeed * t)^2      (eq 1)
Run Code Online (Sandbox Code Playgroud)

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

targetPos+t*targetVelocityVec                                   (eq 2)
Run Code Online (Sandbox Code Playgroud)

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

x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z
Run Code Online (Sandbox Code Playgroud)

这三个方程可以插入(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
Run Code Online (Sandbox Code Playgroud)

该等式仅包含已知变量,并且可以针对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
Run Code Online (Sandbox Code Playgroud)

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

(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
Run Code Online (Sandbox Code Playgroud)

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

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

# 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
Run Code Online (Sandbox Code Playgroud)

  • 从技术上来说,并不是"在过去的时候发射大炮",而是将大炮*射入过去的负面`t`. (2认同)