Basis
用于表示 3D 旋转和缩放的 3×3 矩阵。
描述
Basis 内置 Variant 类型是一种 3×3 矩阵,用于表示 3D 旋转、缩放和倾斜。常用于 Transform3D。
Basis 由 3 个轴向量组成,每个轴向量代表矩阵的一列:x、y 和 z。每个轴的长度(Vector3.length())都会影响该基的缩放,而所有轴的方向将影响旋转。通常,这些轴彼此垂直。但是,当你单独旋转任意轴时,该基会产生倾斜。对 3D 模型应用倾斜后的基会使模型发生变形。
特殊形式的 Basis 有:
正交:轴相互垂直。
归一化:轴的长度都是
1.0。均匀:轴的长度相等(见 get_scale())。
正交归一:既正交又归一化,只能表示旋转。
共形:既正交又均匀,保证不扭曲。
通用介绍见教程《矩阵与变换》。
注意:Godot 使用右手坐标系,这是一种普遍标准。方向方面,Camera3D 等内置类型的约定是 -Z 指向前方(+X 为右、+Y 为上、+Z 为后)。其他对象可能使用不同的方向约定。更多信息见教程《3D 资产方向惯例》 。
注意:基矩阵按列为主的顺序公开,这与 OpenGL 一致。但是内部使用行为主的顺序存储,这与 DirectX 一致。
备注
通过 C# 使用该 API 时会有显著不同,详见 C# API 与 GDScript 的差异。
教程
属性
|
||
|
||
|
构造函数
Basis() |
|
Basis(from: Quaternion) |
|
方法
determinant() const |
|
from_euler(euler: Vector3, order: int = 2) static |
|
from_scale(scale: Vector3) static |
|
get_rotation_quaternion() const |
|
get_scale() const |
|
inverse() const |
|
is_conformal() const |
|
is_equal_approx(b: Basis) const |
|
is_finite() const |
|
looking_at(target: Vector3, up: Vector3 = Vector3(0, 1, 0), use_model_front: bool = false) static |
|
orthonormalized() const |
|
scaled_local(scale: Vector3) const |
|
transposed() const |
运算符
operator !=(right: Basis) |
|
operator *(right: Basis) |
|
operator *(right: Vector3) |
|
operator *(right: float) |
|
operator *(right: int) |
|
operator /(right: float) |
|
operator /(right: int) |
|
operator ==(right: Basis) |
|
operator [](index: int) |
常量
IDENTITY = Basis(1, 0, 0, 0, 1, 0, 0, 0, 1) 🔗
单位 Basis。这是一个没有旋转、没有倾斜的标准正交基,其缩放为 Vector3.ONE。这也意味着:
x 指向右侧(Vector3.RIGHT);
y 指向上方(Vector3.UP);
z 指向后面(Vector3.BACK)。
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) 🔗
属性说明
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)。
构造函数说明
构造与 IDENTITY 相同的 Basis。
注意:在 C# 中构造的 Basis 的所有分量都为 Vector3.ZERO。
构造给定 Basis 的副本。
Basis Basis(axis: Vector3, angle: float)
构造仅表示旋转的 Basis,给定的 angle 以弧度为单位,表示围绕 axis 轴的旋转量。这个轴必须是归一化的向量。
注意:与对 IDENTITY 基使用 rotated() 一致。多角度旋转请改用 from_euler()。
Basis Basis(from: Quaternion)
根据给定的 Quaternion 构造仅表示旋转的 Basis。
注意:四元数仅存储旋转,不会存储缩放。因此,Basis 到 Quaternion 的转换并不一定可逆。
Basis Basis(x_axis: Vector3, y_axis: Vector3, z_axis: Vector3)
根据 3 个轴向量构造 Basis。这些是基矩阵的列向量。
方法说明
返回基矩阵的行列式。在高等数学中,这个数可以用来确定一些性质:
如果行列式为
0.0,则基不可逆(见 inverse())。如果行列式为负数,则基表示负缩放。
注意:如果基的每个轴缩放都相同,那么这个行列式始终为 3 的该缩放次幂。
Basis from_euler(euler: Vector3, order: int = 2) static 🔗
根据给定的 Vector3 构造 Basis,这个向量为 欧拉角,单位为弧度。
# 创建 Z 轴向下的 Basis。
var my_basis = Basis.from_euler(Vector3(TAU / 4, 0, 0))
print(my_basis.z) # 输出 (0.0, -1.0, 0.0)
// 创建 Z 轴向下的 Basis。
var myBasis = Basis.FromEuler(new Vector3(Mathf.Tau / 4.0f, 0.0f, 0.0f));
GD.Print(myBasis.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)
var myBasis = Basis.FromScale(new Vector3(2.0f, 4.0f, 8.0f));
GD.Print(myBasis.X); // 输出 (2.0, 0.0, 0.0)
GD.Print(myBasis.Y); // 输出 (0.0, 4.0, 0.0)
GD.Print(myBasis.Z); // 输出 (0.0, 0.0, 8.0)
注意:在线性代数中,这种基矩阵也被称作对角矩阵。
Vector3 get_euler(order: int = 2) const 🔗
以 Vector3 的形式返回基的旋转向量,这个向量为 欧拉角,单位为弧度。返回值中:
连续旋转的顺序可以通过 order 修改(见 EulerOrder 常量)。默认使用 YXZ 约定(@GlobalScope.EULER_ORDER_YXZ):首先计算围绕 Z 轴的旋转(翻滚),然后计算围绕 X 轴的旋转(俯仰),最后计算围绕 Y 轴旋转(偏摆)。这个顺序在相对的函数 from_euler() 中是相反的。
注意:该方法只对标准正交基返回正确的值(见 orthonormalized())。
注意:欧拉角更符合直觉,但是并不适合 3D 数学。因此请考虑改用返回 Quaternion 的 get_rotation_quaternion()。
注意:在检查器面板中,基的旋转通常是以欧拉角的形式显示的(单位为度),与 Node3D.rotation 属性相同。
Quaternion get_rotation_quaternion() const 🔗
以 Quaternion 的形式返回基的旋转。
注意:四元数更适合 3D 数学,但是并不那么符合直觉。用户界面相关的场合请考虑使用返回欧拉角的 get_euler() 方法。
返回该基的每个轴的长度,形式为 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)
var myBasis = new Basis(
Vector3(2.0f, 0.0f, 0.0f),
Vector3(0.0f, 4.0f, 0.0f),
Vector3(0.0f, 0.0f, 8.0f)
);
// 以任何方式旋转基都会保持其缩放。
myBasis = myBasis.Rotated(Vector3.Up, Mathf.Tau / 2.0f);
myBasis = myBasis.Rotated(Vector3.Right, Mathf.Tau / 4.0f);
GD.Print(myBasis.Scale); // 输出 (2.0, 4.0, 8.0)
注意:如果 determinant() 返回的值为负数,则缩放也为负数。
返回 该基矩阵的逆矩阵。
如果该基是共形的,则返回 true。共形的基既是正交的(轴彼此垂直)又是均匀的(轴共享相同长度)。该方法在物理计算过程中特别有用。
bool is_equal_approx(b: Basis) const 🔗
如果该基和 b 近似相等,则返回 true,判断方法是在每个向量分量上调用 @GlobalScope.is_equal_approx()。
如果该基是有限的,则返回 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_front 为 true,则 +Z 轴(资产正面)被视为向前(意味着 +X 位于左侧)并指向 target 的位置。
向上轴(+Y)尽可能靠近 up 向量,同时保持垂直于向前轴。返回的基是正交归一化的(见 orthonormalized())。
target 和 up 向量不能是 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()
// 每帧旋转该 Node3D。
public override void _Process(double delta)
{
Basis = Basis.Rotated(Vector3.Up, Mathf.Tau * (float)delta)
.Rotated(Vector3.Right, Mathf.Tau * (float)delta)
.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) # 绕向后轴旋转(滚动)。
var myBasis = Basis.Identity;
var angle = Mathf.Tau / 2.0f;
myBasis = myBasis.Rotated(Vector3.Up, angle); // 绕向上轴旋转(偏航)。
myBasis = myBasis.Rotated(Vector3.Right, angle); // 绕向右轴旋转(俯仰)。
myBasis = myBasis.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)
var myBasis = new Basis(
new Vector3(1.0f, 1.0f, 1.0f),
new Vector3(2.0f, 2.0f, 2.0f),
new Vector3(3.0f, 3.0f, 3.0f)
);
myBasis = myBasis.Scaled(new Vector3(0.0f, 2.0f, -2.0f));
GD.Print(myBasis.X); // 输出 (0.0, 2.0, -2.0)
GD.Print(myBasis.Y); // 输出 (0.0, 4.0, -4.0)
GD.Print(myBasis.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)
var myBasis = new Basis(
new Vector3(1.0f, 1.0f, 1.0f),
new Vector3(2.0f, 2.0f, 2.0f),
new Vector3(3.0f, 3.0f, 3.0f)
);
myBasis = myBasis.ScaledLocal(new Vector3(0.0f, 2.0f, -2.0f));
GD.Print(myBasis.X); // 输出 (0, 0, 0)
GD.Print(myBasis.Y); // 输出 (4, 4, 4)
GD.Print(myBasis.Z); // 输出 (-6, -6, -6)
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 🔗
返回 with 和 x 轴之间的转置点积(请参阅 transposed())。
这相当于 basis.x.dot(vector)。
float tdoty(with: Vector3) const 🔗
返回 with 和 y 轴之间的转置点积(请参阅 transposed())。
这相当于 basis.y.dot(vector)。
float tdotz(with: Vector3) const 🔗
返回 with 和 z 轴之间的转置点积(请参阅 transposed())。
这相当于 basis.z.dot(vector)。
返回该基的转置版本。这会将基矩阵的列转换为行,并将其行转换为列。
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)
var myBasis = new Basis(
new Vector3(1.0f, 2.0f, 3.0f),
new Vector3(4.0f, 5.0f, 6.0f),
new Vector3(7.0f, 8.0f, 9.0f)
);
myBasis = myBasis.Transposed();
GD.Print(myBasis.X); // 输出 (1.0, 4.0, 7.0)
GD.Print(myBasis.Y); // 输出 (2.0, 5.0, 8.0)
GD.Print(myBasis.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)
// 交换 X/Z 轴并使缩放加倍的基。
var myBasis = new Basis(new Vector3(0, 2, 0), new Vector3(2, 0, 0), new Vector3(0, 0, 2));
GD.Print(myBasis * new 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) 🔗
通过索引访问该基的每个轴(列)。索引 0 与 x 相同,索引 1 与 y 相同,索引 2 与 z 相同。
注意:在 C++ 中,该运算符访问基础矩阵的行,而不是列。对于与脚本语言相同的行为,请使用 set_column 和 get_column 方法。