我已经用谷歌搜索了问题,但只发现了二维解决方案或不适合我的公式(发现这个公式看起来不错:http://www.ogre3d.org/forums/viewtopic.php?f=10&t=55796但似乎不正确。)
我已经给出了:
Vec3 cannonPos;
Vec3 targetPos;
Vec3 targetVelocityVec;
float bulletSpeed;
我正在寻找的是时间t
targetPos+t*targetVelocityVec
是将大炮瞄准射击的交叉点。
我正在为t寻找一个简单,廉价的公式(简单来说,我的意思是不要进行许多不必要的矢量空间转换等)
谢谢!
答案 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