与全3d空间控制器的终极斗争



对不起,如果我很愚蠢或什么,但我有一个深深的恐惧的工作在一个"完整的3d ";空间运动。

我在试着造一艘"宇宙飞船"。KinematicBody控制器,它使用基向量作为旋转点,并且能够根据它的面向方向向左,向右,向上,向下扫射/移动。

问题是我想使用Vector3作为所有输入变量的存储,特别是输入强度,但我找不到一种方便的方法来定向或使用这个向量的变量将其应用于速度。

我得到了一种廉价的解决方案,我不喜欢对输入向量进行旋转,这样它就会"对应"到一个基础,但它开始在一些角度刹车。

请有人建议我可以改变我的逻辑,或者也许有一种方法使用四元数/矩阵相关的方法/公式?

我不确定我完全明白你想做什么,但我可以给你一些工作。

我假设你已经有了一个Vector3的输入。如果没有,您希望看到Input.get_action_strength,Input.get_axisInput.get_vector

我也假设你遇到的刹车情况是万向节锁的情况。但既然你问的是应用速度而不是旋转,我就不讨论这个话题了。

既然你正在使用KinematicBody,我想你会使用move_and_slide或类似的方法,在全局空间工作。但是你想要输入必须基于当前的朝向。因此,您可以认为表示输入的Vector3位于本地空间中。问题是如何从本地空间到move_and_slide等的全球空间。需要的。


变换

您可能熟悉to_localto_global。这将把Vector3解释为位置:

var global_input_vector:Vector3 = to_global(input_vector)

相反的操作是:

input_vector = to_local(global_input_vector)

问题在于,由于它们认为Vector3是位置,它们将根据KinematicBody的位置转换向量。我们可以撤销这个翻译:

var global_vec:Vector3 = to_global(local_vec) - global_transform.orign

相反的操作是:

local_vec = to_local(global_vec + global_transform.orign)

顺便说一下,这是编写相同代码的另一种方式:

var global_vec:Vector3 = (global_transform * local_vec) - global_transform.orign

相反的操作是:

local_vec = global_transform.affine_inverse() * (global_vec + global_transform.orign)

我之所以提到它,是因为我想让你看到它与下面的方法的相似之处。

基础

我宁愿不考虑Vector3是位置。就是自由向量。所以,我们只使用Basis来转换它,像这样:

var global_vec:Vector3 = global_transform.basis * local_vec

相反的操作是:

local_vec = global_transform.affine_inverse().basis * global_vec

这种方法不会有翻译问题。

你可以把Basis想象成一个3 × 3矩阵,而Transform是同一个矩阵加了一个平移向量(origin)。


皮疹

然而,如果你只想要旋转,让我们用四元数代替:

var global_vec:Vector3 = global_transform.basis.get_rotation_quat() * local_vec

相反的操作是:

local_vec = global_transform.affine_inverse().basis.get_rotation_quat() * global_vec

实际上,让我们把四元数倒过来:

local_vec = global_transform.basis.get_rotation_quat().inverse() * global_vec

这些只会根据KinematicBody的当前方向旋转向量(没有缩放,或任何其他变换,只是旋转)。


旋转变换

如果你想旋转一个Transform,要么…

这样做(四元数):

transform = Transform(transform.basis * Basis(quaternion), transform.origin)

或者this(四元数):

transform = transform * Transform(Basis(quaternion), Vector3.ZERO)

或者这个(轴角):

transform = Transform(transform.basis.rotated(axis, angle), transform.origin)

或者这个(轴角):

transform = transform * Transform.Identity.rotated(axis, angle)

或者这个(欧拉角):

transform = Transform(transform.basis * Basis(pitch, yaw, roll), transform.origin)

或者这个(欧拉角):

transform = transform * Transform(Basis(pitch, yaw, roll), Vector3.ZERO)

避免这种情况:

transform = transform.rotated(axis, angle)

原因是这个旋转总是在平移之前(即,它围绕全局原点旋转,而不是当前位置),你最终会得到一个不希望的结果。

是的,您可以使用rotate_x,rotate_yrotate_z,或者设置Spatialrotation。但有时你需要直接使用Transform


参见:

  • Godot/Gdscript旋转+从本地空间到世界空间。
  • 如何在Godot中走最长的路线或路径的两个角度之间进行LERP。

最新更新