使用欧拉角在 Godot (GDScript) 中进行 3D 旋转

3D rotation in Godot (GDScript) using Euler angles

我正在尝试根据显示如何在 Unity 中执行此操作的 this 视频为模拟游戏创建 3D 相机。当 t运行将代码转换为 GDScript 时,我 运行 遇到了一个问题:我无法让相机旋转 。 这是我对视频中脚本旋转部分的 GDScript 解释(时间戳:8:50-10:10):

export(float) var rotation_amount = 1
export(Quat) var new_rotation

func _ready():
    new_rotation = rotation

func _process(delta):
    handle_movement_input(delta)

func handle_movement_input(delta):
    if(Input.is_action_pressed("cam_rotate_left")):
        new_rotation *= Quat(Vector3.UP * rotation_amount).get_euler()
    if(Input.is_action_pressed("cam_rotate_right")):
        new_rotation *= Quat(Vector3.UP * -rotation_amount).get_euler()

    rotation = rotation.linear_interpolate(new_rotation, delta * movement_time)

类型

您声称 new_rotationQuat (export(Quat))。但是您不仅立即覆盖它(在 _ready 中),您还用 Vector3 覆盖它(rotation 是代表欧拉角的 Vector3):

func _ready():
    new_rotation = rotation

如果你创建了一个类型化的导出变量,Godot 会告诉你这个问题:

export var new_rotation:Quat

是的,GDScript 有类型变量。使用它们。


角度表示法

如果您想使用四元数(如视频中所示),您可以像这样获得旋转 Quat

var new_rotation:Quat

func _ready():
    new_rotation = transform.basis.get_rotation_quat()

然后你可以通过乘法组合四元数,用slerp插值,最后用get_euler()

顺便说一句,当您创建一个 Quat 并传递一个 Vector3 时,它被理解为欧拉角。这相当于 Unity 的 Quaternion.Euler(他们在视频中使用)。此外,调用 to_euler 会将 Quat 转换为欧拉角,这使得使用 Quat 毫无意义,因为它只是从欧拉角创建的(而且根本不是他们在视频中所做的) .


如果您想使用欧拉角,您应该将它们相加而不是相乘。


但是,由于您只关心垂直方向的旋转,我在这里告诉您:使用 float。把事情简单化。关键你把代码放在哪里。


插值注意事项

Vector3.linear_interpolate(或Quat.slerplerp)的权重是一个介于0和1之间的值。如果为0,则得到原始值。如果它是 1,您将获得新值。

添加插值将使运动平滑,但也会给你一个 deceleration/slowing 向下的效果。所以你失去了敏锐的控制。

如果平滑旋转并急剧停止,请将角度乘以增量和一些缩放常数。也就是说,不是这样做:Quat(Vector3.UP * rotation_amount),而是这样做:Quat(Vector3.UP * rotation_amount * delta)。并且不做插值。


你把代码放在哪里?

如果您在 Camera 节点中编写该代码,它将无法工作。因为 rotation 改变了相机的观看方向。而这正是我们不想要的。相反,我们想围绕 space.

中的某个其他点旋转

因此,在场景树中设置:

Pivot:Spatial
└ Camera

您可以将 Pivot(一个 Spatial 节点)放在地面上,然后让 Camera 从空中观察它。而你把旋转逻辑放在Pivot中。由于 Pivot 仅负责该旋转,因此您可以使用 float 作为角度。而生活是轻松简单的(用[​​=33=]插值float)。


能不能单节点做?是的。我有一个过度设计的解决方案,完全可以做到这一点 elsewhere(包括解释为什么它不是最好的主意)。