如何从 Godot 中的两个变换获得欧拉角
How to get Euler angles from two transforms in Godot
我有一个 Transform
在轴上旋转了一个角度。是否可以使用旋转前的Transform
和旋转后的Transform
来获得旋转的欧拉角?我尝试使用 Transform.basis.get_euler()
来获得 Transform
前后的欧拉角。但是我不认为减去它们会起作用。这将如何完成?
解决方案
我想到了这个:
var A := start.basis.get_rotation_quat()
var B := end.basis.get_rotation_quat()
var R := A.inverse() * B
print(R.get_euler())
还建议始终使用 normalize
四元数,以尽量减少累积浮点错误。不过我相信这里不是问题。
说明
想法是你有一个旋转四元数 A
,经过一些旋转 R
变成 B
。换句话说:
B = A * R
如果我们求解 R
,我们会得到:
B = A * R
B * R.inverse() = A * R * R.inverse()
B * R.inverse() = A
B.inverse() * B * R.inverse() = B.inverse() * A
R.inverse() = B.inverse() * A
R = (B.inverse() * A).inverse()
R = A.inverse() * B
测试
这是我用来测试的:
tool
extends MeshInstance
func _enter_tree() -> void:
set_notify_transform(true)
func _notification(what: int) -> void:
if what == NOTIFICATION_TRANSFORM_CHANGED:
var parent := get_parent() as Spatial
var end := global_transform.basis.get_rotation_quat()
var start := parent.global_transform.basis.get_rotation_quat()
var A := start
var B := end
var R := A.inverse() * B
var S := transform.basis.get_rotation_quat()
if R.w < 0: R = -R
if S.w < 0: S = -S
if not S.is_equal_approx(R):
prints("FAIL", rotation_degrees, R, S)
将其附加到 Spatial
的 MeshInstance
子级。
代码将 运行 放在编辑器上。它启用对其 Transform
中的任何更改的通知。当它收到通知时,它会根据其 global_transform
及其父 global_transform
计算四元数。旋转它看看是否打印出来。
顺便说一句,我最初忘记了有两种方法可以用四元数表示相同的旋转。所以它没有通过测试。这些行修复它:
if R.w < 0: R = -R
if S.w < 0: S = -S
不,normalize
没有解决这个问题。缺少 normalize
也没有导致测试失败。
我还测试了您不需要这样做就可以从 get_euler
中获取正确的值。我的意思是,像这样它可以正常工作:
var end := global_transform.basis.get_rotation_quat()
var start := parent.global_transform.basis.get_rotation_quat()
var A := start
var B := end
var R := A.inverse() * B
var S := transform.basis.get_rotation_quat()
if not S.get_euler().is_equal_approx(R.get_euler()):
prints("FAIL", rotation_degrees, R, S)
类似地,它可以直接与 Transform
一起正常工作,如下所示:
var end := global_transform
var start := parent.global_transform
var A := start
var B := end
var R := A.affine_inverse() * B
var S := transform
if not S.is_equal_approx(R):
prints("FAIL", rotation_degrees, R, S)
我有一个 Transform
在轴上旋转了一个角度。是否可以使用旋转前的Transform
和旋转后的Transform
来获得旋转的欧拉角?我尝试使用 Transform.basis.get_euler()
来获得 Transform
前后的欧拉角。但是我不认为减去它们会起作用。这将如何完成?
解决方案
我想到了这个:
var A := start.basis.get_rotation_quat()
var B := end.basis.get_rotation_quat()
var R := A.inverse() * B
print(R.get_euler())
还建议始终使用 normalize
四元数,以尽量减少累积浮点错误。不过我相信这里不是问题。
说明
想法是你有一个旋转四元数 A
,经过一些旋转 R
变成 B
。换句话说:
B = A * R
如果我们求解 R
,我们会得到:
B = A * R
B * R.inverse() = A * R * R.inverse()
B * R.inverse() = A
B.inverse() * B * R.inverse() = B.inverse() * A
R.inverse() = B.inverse() * A
R = (B.inverse() * A).inverse()
R = A.inverse() * B
测试
这是我用来测试的:
tool
extends MeshInstance
func _enter_tree() -> void:
set_notify_transform(true)
func _notification(what: int) -> void:
if what == NOTIFICATION_TRANSFORM_CHANGED:
var parent := get_parent() as Spatial
var end := global_transform.basis.get_rotation_quat()
var start := parent.global_transform.basis.get_rotation_quat()
var A := start
var B := end
var R := A.inverse() * B
var S := transform.basis.get_rotation_quat()
if R.w < 0: R = -R
if S.w < 0: S = -S
if not S.is_equal_approx(R):
prints("FAIL", rotation_degrees, R, S)
将其附加到 Spatial
的 MeshInstance
子级。
代码将 运行 放在编辑器上。它启用对其 Transform
中的任何更改的通知。当它收到通知时,它会根据其 global_transform
及其父 global_transform
计算四元数。旋转它看看是否打印出来。
顺便说一句,我最初忘记了有两种方法可以用四元数表示相同的旋转。所以它没有通过测试。这些行修复它:
if R.w < 0: R = -R
if S.w < 0: S = -S
不,normalize
没有解决这个问题。缺少 normalize
也没有导致测试失败。
我还测试了您不需要这样做就可以从 get_euler
中获取正确的值。我的意思是,像这样它可以正常工作:
var end := global_transform.basis.get_rotation_quat()
var start := parent.global_transform.basis.get_rotation_quat()
var A := start
var B := end
var R := A.inverse() * B
var S := transform.basis.get_rotation_quat()
if not S.get_euler().is_equal_approx(R.get_euler()):
prints("FAIL", rotation_degrees, R, S)
类似地,它可以直接与 Transform
一起正常工作,如下所示:
var end := global_transform
var start := parent.global_transform
var A := start
var B := end
var R := A.affine_inverse() * B
var S := transform
if not S.is_equal_approx(R):
prints("FAIL", rotation_degrees, R, S)