根据两个3D向量计算目标角度?

时间:2018-08-16 20:28:30

标签: math vector 3d angle

我在Ruby中编写了此函数,以查找两个2D(x,y)向量之间的目标角度,但是现在我想了解如何以类似的方式在3D中执行此操作:

def target_angle(point1, point2)
    x1 = point1[0]
    y1 = point1[1]
    x2 = point2[0]
    y2 = point2[1]
    delta_x = x2 - x1
    delta_y = y2 - y1
    return Math.atan2(delta_y, delta_x)
  end

给定一个对象(在这种情况下像子弹),我可以在播放器(x,y)和鼠标(x,y)之间给定target_angle的情况下射击该对象,例如在子弹更新功能中:

  def update
    wall_collision
    # the angle here is the target angle where point 1 is the player and
    # point 2 is the mouse
    @x += Math.cos(angle)*speed
    @y += Math.sin(angle)*speed
  end

是否有一种类似的方法来计算3D中的目标角度并以与我的更新函数类似的方式使用该角度(以3D方式发射子弹)?我该如何对两个3D向量(x,y,z)进行这项工作,在这些位置上您具有播放器位置(x,y,z)和远离播放器的其他任意3d点。

2 个答案:

答案 0 :(得分:0)

我最近为此类事情发布了vector / matrix宝石,尽管它是用C编写的,但我将尝试将其转换为纯Ruby。

实际上,有几种方法可以计算3D空间中两个向量之间的角度。通常使用典型的acos函数,但是当斜率接近+/- 1.0时,精度问题会很大,因此最好使用角度平分线进行计算。使用acos,甚至因叉积产生的光精度误差都会导致更大的角度误差,因此,经过一些研究,我发现这种方法始终是一致的。

给出两个定义为v1v2的向量:

# Normalize vectors
inv = 1.0 / Math.sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z)
n1 = Vector.new(v1.x * inv, v1.y * inv, v1.z * inv)

inv = 1.0 / Math.sqrt(v2.x * v2.x + v2.y * v2.y + v2.z * v2.z)
n2 = Vector.new(v2.x * inv, v2.y * inv, v2.z * inv)

ratio = n1.x * n2.x + n1.y * n2.y + n1.z * n2.z


if ratio < 0.0
  x = -n1.x - n2.x
  y = -n1.y - n2.y
  z = -n1.z - n2.z
  length = Math.sqrt(x * x + y * y + z * z)
  theta = Math::PI - 2.0 * Math.asin(length / 2.0)
else
  x = n1.x - n2.x
  y = n1.y - n2.y
  z = n1.z - n2.z
  length = Math.sqrt(x * x + y * y + z * z)
  theta = 2.0 * asin(length / 2.0)
end

# Convert from radians to degrees
angle = theta * (180.0 / Math::PI)

我没有运行/测试此代码,也不确定您使用的是什么矢量实现,我只是假设一个对象为xyz说明点的值。可能需要进行一些小的改进,例如乘以0.5而不是除以2.0,因为除法速度较慢,但​​希望基本前提会有所帮助。

我从C项目转换了此代码,因此,如果您对其他矢量功能感兴趣,请参阅here(无耻的自我广告)。

答案 1 :(得分:0)

[伪代码]

两个向量的点积与它们之间角度的余弦有关。

COS(angle) = dot(a,b)/( |a|*|b| ) 

两个向量的叉积与它们之间夹角的正弦有关。

SIN(angle) = | cross(a,b) |/( |a|*|b| )

所以切线就是正弦与余弦之比(分母彼此抵消)。

angle = atan2( magnitude(cross(a,b)), dot(a.b) )  % returns angle in radians

请注意atan2(Δy,Δx)的约定。

最后,定义以下功能

magnitude(c) = sqrt(c.x^2+c.y^2+c.z^2)
dot(a,b) = a.x*b.x + a.y*b.y + a.z*b.z
cross(a,b) = [ a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a>x*b.y - a.y*b.x ]