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

Ultimate struggle with a full 3d space controller

对不起,如果我是愚蠢之类的,但我对“全 3d”space 运动的作品深感恐惧。

我正在尝试制作一个“space ship”KinematicBody 控制器,它使用基本向量作为旋转点并且能够strafe/move 左、右、上、下基于它的面向方向.

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

我有一种廉价的解决方案,我不喜欢将旋转应用于输入向量,因此它将“对应”于其中一个基础,但它开始在某些角度制动。

有人可以建议我可以改变我的逻辑,或者也许有办法 使用 quaternion/matrix 相关 methods/formulas?

我不确定我是否完全理解你想做什么,但我可以给你一些可以使用的东西。

我假设您已经有了 Vector3 的输入。 如果没有,你想看Input.get_action_strengthInput.get_axisInput.get_vector

我也假设你遇到的刹车情况是gimbal lock的情况。但是因为你问的是应用速度而不是旋转,我不会进入那个话题。

由于您使用的是 KinematicBody,我想您会使用 move_and_slide 或类似的方法,它们在全局 space 中有效。但是您希望输入必须基于当前方向。因此,您会认为代表输入的 Vector3 在本地 space。问题是如何从本地 space 到 move_and_slide et.al 的全局 space。需要。


转换

您可能熟悉 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 x 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.basis * Basis(quaternion), transform.origin)

或者这个(四元数):

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

或者这个 (axis-angle):

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

或者这个 (axis-angle):

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_xrotate_yrotate_z,或者设置 rotationSpatial。但有时您需要直接使用 Transform


另请参阅:

  • .
  • .