首页 > 解决方案 > 使用欧拉角在 Godot (GDScript) 中进行 3D 旋转

问题描述

我正在尝试根据视频为模拟游戏创建一个 3D 相机,该视频展示了如何在 Unity 中进行操作。在将代码翻译成 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)

标签: 3dquaternionsgodoteuler-angles

解决方案


类型

您声称new_rotationQuat( export(Quat))。但是您不仅要立即覆盖它(在 中_ready),还可以用 a 覆盖它Vector3rotationVector3表示欧拉角的 a):

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()

然后你可以通过乘法组成四元数,用它们插值slerpget_euler()在最后使用。

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


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


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


关于插值的说明

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

添加插值将使运动平滑,但也会给您减速/减速效果。所以你失去了敏锐的控制力。

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


你把代码放在哪里?

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

因此,在场景树中进行设置:

Pivot:Spatial
└ Camera

您将Pivot(一个Spatial节点)放在地面上,然后Camera从空中观察它。你把旋转逻辑放在Pivot. 由于Pivot它只负责旋转,因此您可以使用 afloat作为角度。生活轻松简单(用于lerp插值float)。


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


推荐阅读