Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Basis

用于表示 3D 旋转和缩放的 3×3 矩阵。

描述

Basis 内置 Variant 类型是一种 3×3 矩阵,用于表示 3D 旋转、缩放和倾斜。常用于 Transform3D

Basis 由 3 个轴向量组成,每个轴向量代表矩阵的一列:xyz。每个轴的长度(Vector3.length())都会影响该基的缩放,而所有轴的方向将影响旋转。通常,这些轴彼此垂直。但是,当你单独旋转任意轴时,该基会产生倾斜。对 3D 模型应用倾斜后的基会使模型发生变形。

特殊形式的 Basis 有:

  • 正交:轴相互垂直。

  • 归一化:轴的长度都是 1.0

  • 均匀:轴的长度相等(见 get_scale())。

  • 正交归一:既正交又归一化,只能表示旋转。

  • 共形:既正交又均匀,保证不扭曲。

通用介绍见教程《矩阵与变换》

注意:Godot 使用右手坐标系,这是一种普遍标准。方向方面,Camera3D 等内置类型的约定是 -Z 指向前方(+X 为右、+Y 为上、+Z 为后)。其他对象可能使用不同的方向约定。更多信息见教程《3D 资产方向惯例》

注意:基矩阵按列为主的顺序公开,这与 OpenGL 一致。但是内部使用行为主的顺序存储,这与 DirectX 一致。

Note

通过 C# 使用该 API 时会有显著不同,详见 C# API differences to GDScript

教程

属性

Vector3

x

Vector3(1, 0, 0)

Vector3

y

Vector3(0, 1, 0)

Vector3

z

Vector3(0, 0, 1)

构造函数

Basis

Basis()

Basis

Basis(from: Basis)

Basis

Basis(axis: Vector3, angle: float)

Basis

Basis(from: Quaternion)

Basis

Basis(x_axis: Vector3, y_axis: Vector3, z_axis: Vector3)

方法

float

determinant() const

Basis

from_euler(euler: Vector3, order: int = 2) static

Basis

from_scale(scale: Vector3) static

Vector3

get_euler(order: int = 2) const

Quaternion

get_rotation_quaternion() const

Vector3

get_scale() const

Basis

inverse() const

bool

is_conformal() const

bool

is_equal_approx(b: Basis) const

bool

is_finite() const

Basis

looking_at(target: Vector3, up: Vector3 = Vector3(0, 1, 0), use_model_front: bool = false) static

Basis

orthonormalized() const

Basis

rotated(axis: Vector3, angle: float) const

Basis

scaled(scale: Vector3) const

Basis

slerp(to: Basis, weight: float) const

float

tdotx(with: Vector3) const

float

tdoty(with: Vector3) const

float

tdotz(with: Vector3) const

Basis

transposed() const

运算符

bool

operator !=(right: Basis)

Basis

operator *(right: Basis)

Vector3

operator *(right: Vector3)

Basis

operator *(right: float)

Basis

operator *(right: int)

Basis

operator /(right: float)

Basis

operator /(right: int)

bool

operator ==(right: Basis)

Vector3

operator [](index: int)


常量

IDENTITY = Basis(1, 0, 0, 0, 1, 0, 0, 0, 1) 🔗

单位 Basis。这是一个没有旋转、没有倾斜的标准正交基,其缩放为 Vector3.ONE。这也意味着:

var basis = Basis.IDENTITY
print("| X | Y | Z")
print("| %.f | %.f | %.f" % [basis.x.x, basis.y.x, basis.z.x])
print("| %.f | %.f | %.f" % [basis.x.y, basis.y.y, basis.z.y])
print("| %.f | %.f | %.f" % [basis.x.z, basis.y.z, basis.z.z])
# 输出:
# | X | Y | Z
# | 1 | 0 | 0
# | 0 | 1 | 0
# | 0 | 0 | 1

使用该常量变换(乘以)一个 Vector3 或其他 Basis 时不会发生变换。

注意:在 GDScript 中,该常量与不使用任何参数创建 Basis 相同。该常量可用于使你的代码更清晰,并与 C# 保持一致。

FLIP_X = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1) 🔗

当任意基被 FLIP_X 相乘时,它会取负 x 轴(X 列)的所有分量。

FLIP_X 被任意基相乘时,它会取负所有轴(X 行)的 Vector3.x 分量。

FLIP_Y = Basis(1, 0, 0, 0, -1, 0, 0, 0, 1) 🔗

当任意基被 FLIP_Y 相乘时,它会取负 y 轴(Y 列)的所有分量。

FLIP_Y 被任意基相乘时,它会取负所有轴(Y 行)的 Vector3.y 分量。

FLIP_Z = Basis(1, 0, 0, 0, 1, 0, 0, 0, -1) 🔗

当任意基被 FLIP_Z 相乘时,它会取负 z 轴(Z 列)的所有分量。

FLIP_Z 被任意基相乘时,它会取负所有轴(Z 行)的 Vector3.z 分量。


属性说明

Vector3 x = Vector3(1, 0, 0) 🔗

该基的 X 轴和矩阵的 0 列。

在单位基上,该向量指向右侧(Vector3.RIGHT)。


Vector3 y = Vector3(0, 1, 0) 🔗

该基的 Y 轴和矩阵的第 1 列。

在单位基上,该向量指向上方(Vector3.UP)。


Vector3 z = Vector3(0, 0, 1) 🔗

该基的 Z 轴和矩阵的第 2 列。

在单位基上,该向量指向后面(Vector3.BACK)。


构造函数说明

Basis Basis() 🔗

构造与 IDENTITY 相同的 Basis

注意:在 C# 中构造的 Basis 的所有分量都为 Vector3.ZERO


Basis Basis(from: Basis)

构造给定 Basis 的副本。


Basis Basis(axis: Vector3, angle: float)

构造仅表示旋转的 Basis,给定的 angle 以弧度为单位,表示围绕 axis 轴的旋转量。这个轴必须是归一化的向量。

注意:与对 IDENTITY 基使用 rotated() 一致。多角度旋转请改用 from_euler()


Basis Basis(from: Quaternion)

根据给定的 Quaternion 构造仅表示旋转的 Basis

注意:四元数存储旋转,不会存储缩放。因此,BasisQuaternion 的转换并不一定可逆。


Basis Basis(x_axis: Vector3, y_axis: Vector3, z_axis: Vector3)

根据 3 个轴向量构造 Basis。这些是基矩阵的列向量。


方法说明

float determinant() const 🔗

返回基矩阵的行列式。在高等数学中,这个数可以用来确定一些性质:

  • 如果行列式为 0.0,则基不可逆(见 inverse())。

  • 如果行列式为负数,则基表示负缩放。

注意:如果基的每个轴缩放都相同,那么这个行列式始终为 2 的该缩放次幂。


Basis from_euler(euler: Vector3, order: int = 2) static 🔗

根据给定的 Vector3 构造 Basis,这个向量为 欧拉角,单位为弧度。

  • Vector3.x 应包含围绕 x 轴的角度(俯仰);

  • Vector3.y 应包含围绕 y 轴的角度(偏摆);

  • Vector3.z 应包含围绕 z 轴的角度(翻滚)。

# 创建 Z 轴向下的 Basis。
var my_basis = Basis.from_euler(Vector3(TAU / 4, 0, 0))

print(my_basis.z) # 输出 (0.0, -1.0, 0.0)

连续旋转的顺序可以通过 order 修改(见 EulerOrder 常量)。默认使用 YXZ 约定(@GlobalScope.EULER_ORDER_YXZ):基首先围绕 Y 轴旋转(偏摆),然后围绕 X 轴旋转(俯仰),最后围绕 Z 轴旋转(翻滚)。这个顺序在相对的函数 get_euler() 中是相反的。


Basis from_scale(scale: Vector3) static 🔗

根据给定的 scale 向量构造仅表示缩放的 Basis,不包含旋转和倾斜。

var my_basis = Basis.from_scale(Vector3(2, 4, 8))

print(my_basis.x) # 输出 (2.0, 0.0, 0.0)
print(my_basis.y) # 输出 (0.0, 4.0, 0.0)
print(my_basis.z) # 输出 (0.0, 0.0, 8.0)

注意:在线性代数中,这种基矩阵也被称作对角矩阵


Vector3 get_euler(order: int = 2) const 🔗

Vector3 的形式返回基的旋转向量,这个向量为 欧拉角,单位为弧度。返回值中:

  • Vector3.x 包含围绕 x 轴的角度(俯仰)。

  • Vector3.y 包含围绕 y 轴的角度(偏摆)。

  • Vector3.z 包含围绕 z 轴的角度(翻滚)。

连续旋转的顺序可以通过 order 修改(见 EulerOrder 常量)。默认使用 YXZ 约定(@GlobalScope.EULER_ORDER_YXZ):首先计算围绕 Z 轴的旋转(翻滚),然后计算围绕 X 轴的旋转(俯仰),最后计算围绕 Y 轴旋转(偏摆)。这个顺序在相对的函数 from_euler() 中是相反的。

注意:该方法只对标准正交基返回正确的值(见 orthonormalized())。

注意:欧拉角更符合直觉,但是并不适合 3D 数学。因此请考虑改用返回 Quaternionget_rotation_quaternion()

注意:在检查器面板中,基的旋转通常是以欧拉角的形式显示的(单位为度),与 Node3D.rotation 属性相同。


Quaternion get_rotation_quaternion() const 🔗

Quaternion 的形式返回基的旋转。

注意:四元数更适合 3D 数学,但是并不那么符合直觉。用户界面相关的场合请考虑使用返回欧拉角的 get_euler() 方法。


Vector3 get_scale() const 🔗

返回该基的每个轴的长度,形式为 Vector3。如果该基未经倾斜,该值就是缩放系数。它不受旋转的影响。

var my_basis = Basis(
    Vector3(2, 0, 0),
    Vector3(0, 4, 0),
    Vector3(0, 0, 8)
)
# 以任何方式旋转基都会保持其缩放。
my_basis = my_basis.rotated(Vector3.UP, TAU / 2)
my_basis = my_basis.rotated(Vector3.RIGHT, TAU / 4)

print(my_basis.get_scale()) # 输出 (2.0, 4.0, 8.0)

注意:如果 determinant() 返回的值为负数,则缩放也为负数。


Basis inverse() const 🔗

返回 该基矩阵的逆矩阵


bool is_conformal() const 🔗

如果该基是共形的,则返回 true。共形的基既是正交的(轴彼此垂直)又是均匀的(轴共享相同长度)。该方法在物理计算过程中特别有用。


bool is_equal_approx(b: Basis) const 🔗

如果该基和 b 近似相等,则返回 true,判断方法是在每个向量分量上调用 @GlobalScope.is_equal_approx()


bool is_finite() const 🔗

如果该基是有限的,则返回 true,判断方法是在每个向量分量上调用 @GlobalScope.is_finite()


Basis looking_at(target: Vector3, up: Vector3 = Vector3(0, 1, 0), use_model_front: bool = false) static 🔗

创建一个带有旋转的新 Basis,使向前轴(-Z)指向 target 的位置。

默认情况下,-Z 轴(相机向前)被视为向前(意味着 +X 位于右侧)。如果 use_model_fronttrue,则 +Z 轴(资产正面)被视为向前(意味着 +X 位于左侧)并指向 target 的位置。

向上轴(+Y)尽可能靠近 up 向量,同时保持垂直于向前轴。返回的基是正交归一化的(见 orthonormalized())。

targetup 向量不能是 Vector3.ZERO,两者也不能共线,这样可以避免围绕局部 Z 轴发生预料之外的旋转。


Basis orthonormalized() const 🔗

返回该基的正交归一化版本。正交归一化基既是正交的(轴彼此垂直)又是归一化的(轴长度为 1.0),这也意味着它只能代表旋转。

调用该方法通常很有用,以避免旋转基上的舍入错误:

# 每帧旋转该 Node3D。
func _process(delta):
    basis = basis.rotated(Vector3.UP, TAU * delta)
    basis = basis.rotated(Vector3.RIGHT, TAU * delta)

    basis = basis.orthonormalized()

Basis rotated(axis: Vector3, angle: float) const 🔗

返回该基的副本,围绕给定轴 axis 进行了旋转,旋转角度为 angle(单位为弧度)。

axis 必须是归一化的向量(见 Vector3.normalized())。如果 angle 为正值,则基围绕转轴进行逆时针旋转。

var my_basis = Basis.IDENTITY
var angle = TAU / 2

my_basis = my_basis.rotated(Vector3.UP, angle)    # 绕向上轴旋转(偏航)。
my_basis = my_basis.rotated(Vector3.RIGHT, angle) # 绕向右轴旋转(俯仰)。
my_basis = my_basis.rotated(Vector3.BACK, angle)  # 绕向后轴旋转(滚动)。

Basis scaled(scale: Vector3) const 🔗

返回该基,其中每个轴的分量都按给定的 scale 的分量缩放。

该基矩阵的行乘以 scale 的分量。该操作是全局缩放(相对于父级)。

var my_basis = Basis(
    Vector3(1, 1, 1),
    Vector3(2, 2, 2),
    Vector3(3, 3, 3)
)
my_basis = my_basis.scaled(Vector3(0, 2, -2))

print(my_basis.x) # 输出 (0.0, 2.0, -2.0)
print(my_basis.y) # 输出 (0.0, 4.0, -4.0)
print(my_basis.z) # 输出 (0.0, 6.0, -6.0)

Basis slerp(to: Basis, weight: float) const 🔗

使用 to 基在给定 weight 的情况下执行球面线性插值。该基和 to 两者都应该代表一个旋转。

示例:使用 Tween 随时间平滑地将 Node3D 旋转到目标基:

var start_basis = Basis.IDENTITY
var target_basis = Basis.IDENTITY.rotated(Vector3.UP, TAU / 2)

func _ready():
    create_tween().tween_method(interpolate, 0.0, 1.0, 5.0).set_trans(Tween.TRANS_EXPO)

func interpolate(weight):
    basis = start_basis.slerp(target_basis, weight)

float tdotx(with: Vector3) const 🔗

返回 withx 轴之间的转置点积(请参阅 transposed())。

这相当于 basis.x.dot(vector)


float tdoty(with: Vector3) const 🔗

返回 withy 轴之间的转置点积(请参阅 transposed())。

这相当于 basis.y.dot(vector)


float tdotz(with: Vector3) const 🔗

返回 withz 轴之间的转置点积(请参阅 transposed())。

这相当于 basis.z.dot(vector)


Basis transposed() const 🔗

返回该基的转置版本。这会将基矩阵的列转换为行,并将其行转换为列。

var my_basis = Basis(
    Vector3(1, 2, 3),
    Vector3(4, 5, 6),
    Vector3(7, 8, 9)
)
my_basis = my_basis.transposed()

print(my_basis.x) # 输出 (1.0, 4.0, 7.0)
print(my_basis.y) # 输出 (2.0, 5.0, 8.0)
print(my_basis.z) # 输出 (3.0, 6.0, 9.0)

运算符说明

bool operator !=(right: Basis) 🔗

如果两个 Basis 矩阵的分量不相等,则返回 true

注意:由于浮点精度误差,请考虑改用 is_equal_approx(),这样更可靠。


Basis operator *(right: Basis) 🔗

由该基转换(乘以) right 基。

这是父级和子级 Node3D 之间执行的操作。


Vector3 operator *(right: Vector3) 🔗

使用该基变换(乘以)right 向量,返回一个 Vector3

# 交换 X/Z 轴并使缩放加倍的基。
var my_basis = Basis(Vector3(0, 2, 0), Vector3(2, 0, 0), Vector3(0, 0, 2))
print(my_basis * Vector3(1, 2, 3)) # 输出 (4.0, 2.0, 6.0)

Basis operator *(right: float) 🔗

Basis 的所有分量乘以给定的 float。这会均匀地影响该基矩阵的缩放,并通过 right 值调整所有 3 个轴的大小。


Basis operator *(right: int) 🔗

将该 Basis 的所有分量乘以给定的 int。这会均匀地影响该基的缩放,并通过 right 值调整所有 3 个轴的大小。


Basis operator /(right: float) 🔗

Basis 的所有分量除以给定的 float。这会均匀地影响该基的缩放,并通过 right 值调整所有 3 个轴的大小。


Basis operator /(right: int) 🔗

Basis 的所有分量除以给定的 int。这会均匀地影响该基的缩放,并通过 right 值调整所有 3 个轴的大小。


bool operator ==(right: Basis) 🔗

如果两个 Basis 矩阵的分量完全相等,则返回 true

注意:由于浮点精度误差,请考虑改用 is_equal_approx(),这样更可靠。


Vector3 operator [](index: int) 🔗

通过索引访问该基的每个轴(列)。索引 0x 相同,索引 1y 相同,索引 2z 相同。

注意:在 C++ 中,该运算符访问基础矩阵的行,而是列。对于与脚本语言相同的行为,请使用 set_columnget_column 方法。