如何设置一个变量以包含旋转度?

发布于 2025-02-06 18:11:53 字数 1088 浏览 3 评论 0原文

我正在尝试在我正在构建的游戏中实现倾斜的技工。为此,我想设置一个变量以充当旋转度的默认数(理想情况下x0y0z0)和一个用于向右倾斜的字符的旋转度(理想的x0.6y0z0)。

这是我的代码(对于上下文,将此脚本连接到一个空间节点,称为Upperbody):

extends Spatial

const LEAN_LERP = 5
export var default_degrees : Vector3
export var leaning_degrees : Vector3

func _process(delta):
    
    if Input.is_action_pressed("LeanRight"):
        transform.origin = transform.origin.linear_interpolate(leaning_degrees, LEAN_LERP * delta)
    else:
        transform.origin = transform.origin.linear_interpolate(default_degrees, LEAN_LERP * delta)
    
    if Input.is_action_pressed("LeanLeft"):
        transform.origin = transform.origin.linear_interpolate(-leaning_degrees, LEAN_LERP * delta)
    else:
        transform.origin = transform.origin.linear_interpolate(default_degrees, LEAN_LERP * delta)

如您所见,我都有default_degrees and code> leaning_degrees '类型设置为vector3,而不是旋转度等效的(当前未知)。

我的问题是:如何设置一个变量以包含旋转度?

谢谢。

I'm trying to implement a leaning mechanic in a game that I'm building. To do that I want to set one variable to act as the default number of rotation degrees (ideally x0, y0, and z0), and one for the rotation degrees of a character that is leaning to the right (ideally x0.6, y0, and z0).

Here's my code (for context, this script is attached to a Spatial node called UpperBody):

extends Spatial

const LEAN_LERP = 5
export var default_degrees : Vector3
export var leaning_degrees : Vector3

func _process(delta):
    
    if Input.is_action_pressed("LeanRight"):
        transform.origin = transform.origin.linear_interpolate(leaning_degrees, LEAN_LERP * delta)
    else:
        transform.origin = transform.origin.linear_interpolate(default_degrees, LEAN_LERP * delta)
    
    if Input.is_action_pressed("LeanLeft"):
        transform.origin = transform.origin.linear_interpolate(-leaning_degrees, LEAN_LERP * delta)
    else:
        transform.origin = transform.origin.linear_interpolate(default_degrees, LEAN_LERP * delta)

As you can see, I have both default_degrees and leaning_degrees' types set to Vector3 instead of the (currently unknown) equivalent for rotational degrees.

My question is this: how do I set a variable to contain rotational degrees?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

复古式 2025-02-13 18:11:53

没有用于欧拉角的专用类型。取而代之的是,您将使用…鼓卷… vector3

实际上,如果您看到 rotation_degrees 属性,您会发现它被定义为vector3


当然,这并不是表示旋转/方向的唯一方法。最终,转换有两个部分:

  • A vector3称为Origin代表转换。
  • 基础称为基础,该基础代表转换的其余部分(旋转,缩放和反射,以及剪切或偏斜)。

一个基础可以想到vector3的三人,每个代表坐标系的轴之一。考虑基础的另一种方法是3乘3矩阵。

因此,无论您用来代表旋转或方向的用品最终都将转换为基础(然后替换或与转换的Basic组成)。


现在,您想插入旋转,对吗?欧拉角对插值不利。相反,您可以

  • 使用Interpaly_with_with_with transform.interpalle_with_with)插值:变换(变换)。
  • 基础(基础使用basis.slerp)。
  • quaternions(quat使用quat.slerp)。

另一方面,Euler角度非常适合输入。在这种特殊情况下,这意味着与在检查员中写下这些数字相比,将头缠绕在数字上是相对容易的。

因此,我们有两个途径:

  • 将欧拉角转换为变换基础quat
  • 找到一种简单的方法来输入转换BaseNquat

Euler与Quat

quat具有一个构造函数,该构造器为欧拉角(Euler Angles)带有一个构造函数。捕获的是,它是弧度中的欧拉角。因此,我们需要将学位转换为弧度(我们可以用 deg2rad )。像这样:

var target_quat := Quat(
    Vector3(
        deg2rad(degrees.x),
        deg2rad(degrees.y),
        deg2rad(degrees.z)
    )
)

或者,您可以做到这一点:

var target_quat := Quat(degrees * PI / 180.0)

我们还需要从转换中获取当前的四元素:

var current_quat := transform.basis.get_rotation_quat()

插入它们:

var new_quat := current_quat.slerp(target_quat, LEAN_LERP * delta)

并替换Quat:

transform = Transform(
    Basis(new_quat).scaled(transform.basis.get_scale()),
    transform.origin
)

上线假设转换仅是旋转,缩放和翻译。如果我们想保持偏斜,可以做到这一点:

transform = Transform(
    Basis(new_quat) * Basis(current_quat).inverse() * transform.basis,
    transform.origin
)

在下一节中解释。

通知我们最终将quat 转换为base /代码>。因此,也许我们最好完全避免四次季节。


Euler与基础的角度

基础类还具有一个构造函数,其工作函数的工作原理,就像我们在quat quat中找到的构造函数一样。因此,我们可以做到这一点:

var target_basis := Basis(degrees * PI / 180.0)

这次捕获是基础不仅代表旋转。因此,如果这样做,我们将失去缩放率(以及任何其他转换基础具有)。我们可以保留这样的缩放:

target_basis = target_basis.scaled(transform.basis.get_scale())

当然,当前的基础是:

var current_basis := transform.basis

我们这样插值:

var new_basis := current_basis.slerp(target_basis, LEAN_LERP * delta)

我们替换了基础这样:

transform.basis = new_basis

老实我对上述方法不满意。我将向您展示一种让基础您插值仅用于旋转的方法(因此,它可以保留任何偏斜的原始基础不仅是其比例)它更多的参与。让我们再次从这里开始:

var target_rotation := Basis(degrees * PI / 180.0)

我们不会扩展,而是要获得一个基础,那只是当前一个的旋转。我们可以通过从基础转到quat和back:

var current_rotation := Basis(transform.basis.get_rotation_quat())

我们以与以前相同的方式进行操作来做到这一点:

var new_rotation := current_rotation.slerp(target_rotation, LEAN_LERP * delta)

但是要替换基础我们要替换。保留有关旧的所有内容,不是旋转。换句话说,我们将要:

  • 基础

    进行

      transform.basis
     
  • 删除其旋转(即与旋转的倒数构成):

     基础(transform.basis.get_rotation_quat())。inverse() * transform.basis
     

    与:

    相同

      current_rotation.inverse() * transform.basis
     
  • ,并应用新旋转:

      new_rotation * current_rotation.inverse() * transform.basis
     

这就是我们设置的:

transform.basis = new_rotation * current_rotation.inverse() * transform.basis

我已经测试了以确保构图顺序正确。而且,是的,上面显示的用于保存偏斜的代码是基于此


。创建转换从Euler角度是通过基础

var target_transform := Transform(Basis(degrees * PI / 180.0), Vector3.ZERO)

我们可以使用此方法保留刻度和翻译:

var target_transform := Transform(
    Basis(degrees * PI / 180.0).scaled(trasnform.basis.get_scale()),
    transform.origin
)

如果您想同时插入翻译,则可以设置您的目标位置,而不是transform.origin

当前转换是:

var current_transform := transform

我们这样插入它们:

var new_transform = current_transform.interpolate_with(target_transform, LEAN_LERP * delta)

我们可以设置:

transform = new_trasnform

如果我们嵌入式这些变量,我们有这:

transform = transform.interpolated_with(target_transform, LEAN_LERP * delta)

如果要保留偏斜,请使用基础方法。


euler Angles的替代输入

我们发现interpolating变换实际上是非常非常简单的。有没有一种方法可以轻松输入变换修辞问题。我们可以在场景中添加一些position3d。定位并旋转它们(即使position3d没有大小),然后将它们缩小(甚至比较),然后使用transform

我们可以使position3d您的空间的孩子(这有点奇怪,但对此不太认真)或兄弟姐妹。无论如何,我们的想法是,我们将从这些position3d中采取变换,并使用它来插入空间。它的代码与以前相同:

transform = transform.interpolated_with(position.transform, LEAN_LERP * delta)

实际上,当我们在其中时,为什么没有三个position3d

  • 左左目标。
  • 右右目标。
  • 默认目标。

您根据输入选择要使用的目标,然后将其插值:

extends Spatial

const LEAN_LERP = 5

onready var left_target:Position3D = get_node(…)
onready var right_target:Position3D = get_node(…)
onready var default_target:Position3D = get_node(…)


func _process(delta):
    var left := Input.is_action_pressed("LeanLeft")
    var right := Input.is_action_pressed("LeanRight")
    var target := default_target
    if left and not right:
        target = left_target
    
    if right and not left:
        target = right_target

    transform = transform.interpolate_with(target, LEAN_LERP * delta)

将节点路径放在我离开的节点路径...


然后, Euler Angles版本:

extends Spatial

const LEAN_LERP = 5

export var default_degrees : Vector3
export var leaning_degrees : Vector3


func _process(delta):
    var left := Input.is_action_pressed("LeanLeft")
    var right := Input.is_action_pressed("LeanRight")
    var degrees := default_degrees
    if left and not right:
        degrees = -leaning_degrees
    
    if right and not left:
        degrees = leaning_degrees

    var target_rotation := Basis(degrees * PI / 180.0)
    var current_rotation := Basis(transform.basis.get_rotation_quat())
    var new_rotation := current_rotation.slerp(target_rotation, LEAN_LERP * delta)
    transform.basis = new_rotation * current_rotation.inverse() * transform.basis

There is no dedicated type for Euler angles. Instead you would use … drum roll … Vector3.

In fact, if you see the rotation_degrees property, you will find it is defined as a Vector3.


That, of course, isn't the only way to represent rotations/orientations. Ultimately, the Transform has two parts:

  • A Vector3 called origin which represents the translation.
  • A Basis called basis which represent the rest of the transformation (rotation, scaling and reflection, and shear or skewing).

A Basis can be thought of a trio of Vector3 each representing one of the axis of the coordinate system. Another way to think of Basis is as a 3 by 3 matrix.

Thus whatever you use to represent rotations or orientations will ultimately be converted to a Basis (and then either replace or be composed with the Basis of the transform).


Now, you want to interpolate the rotations, right? Euler angles aren't good for interpolation. Instead you could interpolate:

  • Transformations (Transform using interpolate_with Transform.interpolate_with).
  • Basis (Basis using Basis.slerp).
  • Quaternions (Quat using Quat.slerp).

On the other hand, Euler angles are good for input. In this particular case that means it is relative easy to wrap your head around what the numbers mean compared to writing any of these in the inspector.

Thus, we have two avenues:

  • Convert Euler angles to either Transform, Basis or Quat.
  • Find an easy way to input a Transform, Basis or Quat.

Euler angle to Quat

The Quat has a constructor that takes a vector for Euler angles. The catch is that it is Euler angles in radians. So we need to convert degrees to radians (which we can do with deg2rad). Like this:

var target_quat := Quat(
    Vector3(
        deg2rad(degrees.x),
        deg2rad(degrees.y),
        deg2rad(degrees.z)
    )
)

Alternatively, you could do this:

var target_quat := Quat(degrees * PI / 180.0)

We also need to get the current quaternion from the transform:

var current_quat := transform.basis.get_rotation_quat()

Interpolate them:

var new_quat := current_quat.slerp(target_quat, LEAN_LERP * delta)

And replace the quat:

transform = Transform(
    Basis(new_quat).scaled(transform.basis.get_scale()),
    transform.origin
)

The above line assumes the transformation is only rotation, scaling, and translation. If we want to keep skewing, we can do this:

transform = Transform(
    Basis(new_quat) * Basis(current_quat).inverse() * transform.basis,
    transform.origin
)

The explanation for that is in the below section.

Notice we ended up converting the Quat to a Basis. So perhaps we are better off avoiding quaternions entirely.


Euler angle to Basis

The Basis class also has a constructor that works like the one we found in Quat. So we can do this:

var target_basis := Basis(degrees * PI / 180.0)

The catch this time is that Basis does not only represent rotation. So if we do that, we are losing scaling (and any other transformation the Basis has). We can preserve the scaling like this:

target_basis = target_basis.scaled(transform.basis.get_scale())

Ah, of course, the current Basis is this:

var current_basis := transform.basis

We interpolate like this:

var new_basis := current_basis.slerp(target_basis, LEAN_LERP * delta)

And we replace the Basis like this:

transform.basis = new_basis

To be honest, I'm not happy with the above approach. I'll show you a way to have the Basis you interpolate be only for rotation (so it can preserve any skewing the original Basis had, not only its scale), but it is a little more involved. Let us start here again:

var target_rotation := Basis(degrees * PI / 180.0)

And we will not scale that, instead we want to get a Basis that is only the rotation of the current one. We can do that by going from Basis to Quat and back:

var current_rotation := Basis(transform.basis.get_rotation_quat())

We interpolate the same way as before:

var new_rotation := current_rotation.slerp(target_rotation, LEAN_LERP * delta)

But to replace the Basis we want to keep everything about the old Basis that wasn't the rotation. In other words we are going to:

  • Take the Basis:

    transform.basis
    
  • Remove its rotation (i.e. compose it with the inverse of its rotation):

    Basis(transform.basis.get_rotation_quat()).inverse() * transform.basis
    

    Which is the same as:

    current_rotation.inverse() * transform.basis
    
  • And apply the new rotation:

    new_rotation * current_rotation.inverse() * transform.basis
    

And that is what we set:

transform.basis = new_rotation * current_rotation.inverse() * transform.basis

I have tested to make sure the composition order is correct. And, yes, code for preserving skewing with Quat I showed above is based on this.


Euler angle to Transform

The way to create a Transform from Euler angles is via a Basis:

var target_transform := Transform(Basis(degrees * PI / 180.0), Vector3.ZERO)

We could preserve scale and translation with this approach:

var target_transform := Transform(
    Basis(degrees * PI / 180.0).scaled(trasnform.basis.get_scale()),
    transform.origin
)

If you want to interpolate translation at the same time, you can set your target position instead of transform.origin.

The current transform is, of course:

var current_transform := transform

We interpolate them like this:

var new_transform = current_transform.interpolate_with(target_transform, LEAN_LERP * delta)

And we can set that:

transform = new_trasnform

If we inline these variables, we have this:

transform = transform.interpolated_with(target_transform, LEAN_LERP * delta)

If you want to preserve skewing, use the Basis approach.


Alternative input to Euler angles

We have found out that interpolating transforms is actually very easy. Is there a way to easily input a Transform? Rhetorical question. We can add some Position3D to the scene. Position and rotate them (and even scale them, even though Position3D has no size), and then use the Transform from them.

We can make the Position3D children of your Spatial (which is somewhat odd, but don't think too hard about it), or as sibling. Regardless, the idea is that we are going to take the transform from these Position3D and use it to interpolate the transform of your Spatial. It is the same code as before:

transform = transform.interpolated_with(position.transform, LEAN_LERP * delta)

In fact, while we are at it, why not have three Position3D:

  • The lean left target.
  • The lean right target.
  • The default target.

Then you pick which target to use depending on input, and interpolate to that:

extends Spatial

const LEAN_LERP = 5

onready var left_target:Position3D = get_node(…)
onready var right_target:Position3D = get_node(…)
onready var default_target:Position3D = get_node(…)


func _process(delta):
    var left := Input.is_action_pressed("LeanLeft")
    var right := Input.is_action_pressed("LeanRight")
    var target := default_target
    if left and not right:
        target = left_target
    
    if right and not left:
        target = right_target

    transform = transform.interpolate_with(target, LEAN_LERP * delta)

Put the node paths where I left ....


Ok, Ok, here is one of the Euler angles versions:

extends Spatial

const LEAN_LERP = 5

export var default_degrees : Vector3
export var leaning_degrees : Vector3


func _process(delta):
    var left := Input.is_action_pressed("LeanLeft")
    var right := Input.is_action_pressed("LeanRight")
    var degrees := default_degrees
    if left and not right:
        degrees = -leaning_degrees
    
    if right and not left:
        degrees = leaning_degrees

    var target_rotation := Basis(degrees * PI / 180.0)
    var current_rotation := Basis(transform.basis.get_rotation_quat())
    var new_rotation := current_rotation.slerp(target_rotation, LEAN_LERP * delta)
    transform.basis = new_rotation * current_rotation.inverse() * transform.basis
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文