使用 3D 变换¶

欧拉角的问题¶

插值¶

• 旋转不会线性映射到方向, 因此它们插值并不总是会形成最短路径(即从 `270``0` 的度数与从 `270` 开始到 `360` 的度数不同, 即使角度是相同的).

• "万向节锁死" 正在发挥作用(第一个和最后一个旋转的轴对齐, 因此失去了一个自由度). 请参阅 维基百科关于Gimbal Lock 的页面 以了解这个问题的详细解释.

变换的介绍¶

Godot里的方向使用 Transform 数据类型. 每一个 Spatial 节点都包含一个 `transform` 属性, 如果该父类是一个空间派生类型, 则该属性相对依赖于父类变换.

```var basis = Basis()
# Contains the following default values:
basis.x = Vector3(1, 0, 0) # Vector pointing along the X axis
basis.y = Vector3(0, 1, 0) # Vector pointing along the Y axis
basis.z = Vector3(0, 0, 1) # Vector pointing along the Z axis
```

操作变换¶

```var axis = Vector3(1, 0, 0) # Or Vector3.RIGHT
var rotation_amount = 0.1
# Rotate the transform around the X axis by 0.1 radians.
transform.basis = Basis(axis, rotation_amount) * transform.basis
# shortened
transform.basis = transform.basis.rotated(axis, rotation_amount)
```

Spatial中的一种方法简化了这个操作:

```# Rotate the transform around the X axis by 0.1 radians.
rotate(Vector3(1, 0, 0), 0.1)
# shortened
rotate_x(0.1)
```

```# Rotate around the object's local X axis by 0.1 radians.
rotate_object_local(Vector3(1, 0, 0), 0.1)
```

精度误差¶

```transform = transform.orthonormalized()
```

```transform = transform.orthonormalized()
transform = transform.scaled(scale)
```

获取信息¶

```bullet.transform = transform
bullet.speed = transform.basis.z * BULLET_SPEED
```

```# Get the direction vector from player to enemy
var direction = enemy.transform.origin - player.transform.origin
if direction.dot(enemy.transform.basis.z) > 0:
enemy.im_watching_you(player)
```

```# Remember that +X is right
if Input.is_action_pressed("strafe_left"):
translate_object_local(-transform.basis.x)
```

```# Keep in mind Y is up-axis
if Input.is_action_just_pressed("jump"):
velocity.y = JUMP_SPEED

velocity = move_and_slide(velocity)
```

设置信息¶

```# accumulators
var rot_x = 0
var rot_y = 0

func _input(event):
if event is InputEventMouseMotion and event.button_mask & 1:
# modify accumulated mouse rotation
rot_x += event.relative.x * LOOKAROUND_SPEED
rot_y += event.relative.y * LOOKAROUND_SPEED
transform.basis = Basis() # reset rotation
rotate_object_local(Vector3(0, 1, 0), rot_x) # first rotate in Y
rotate_object_local(Vector3(1, 0, 0), rot_y) # then rotate in X
```

用四元数插值¶

```# Convert basis to quaternion, keep in mind scale is lost
var a = Quat(transform.basis)
var b = Quat(transform2.basis)
# Interpolate using spherical-linear interpolation (SLERP).
var c = a.slerp(b,0.5) # find halfway point between a and b
# Apply back
transform.basis = Basis(c)
```

Quat 类型引用有更多关于数据类型的信息(它还可以做变换累加, 变换点等, 不过这个使用频率较低). 如果你多次对四元数进行插值或应用操作, 请记住它们最终需要被归一化. 否则, 会带来数值精度误差影响.