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 一致。

备注

通过 C# 使用该 API 时会有显著不同,详见 C# API 与 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

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

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

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


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 scaled_local(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_local(Vector3(0, 2, -2))

print(my_basis.x) # 输出 (0.0, 0.0, 0.0)
print(my_basis.y) # 输出 (4.0, 4.0, 4.0)
print(my_basis.z) # 输出 (-6.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 方法。