我在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点。
答案 0 :(得分:0)
我最近为此类事情发布了vector / matrix宝石,尽管它是用C编写的,但我将尝试将其转换为纯Ruby。
实际上,有几种方法可以计算3D空间中两个向量之间的角度。通常使用典型的acos
函数,但是当斜率接近+/- 1.0时,精度问题会很大,因此最好使用角度平分线进行计算。使用acos
,甚至因叉积产生的光精度误差都会导致更大的角度误差,因此,经过一些研究,我发现这种方法始终是一致的。
给出两个定义为v1
和v2
的向量:
# 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)
我没有运行/测试此代码,也不确定您使用的是什么矢量实现,我只是假设一个对象为x
,y
和z
说明点的值。可能需要进行一些小的改进,例如乘以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 ]