Basis
用於表示 3D 旋轉與縮放的 3×3 矩陣。
說明
Basis 內建的 Variant 型別是一個 3×3 矩陣,用來表示 3D 旋轉、縮放與斜切,常與 Transform3D 一起使用。
Basis 由三個軸向量組成,分別為矩陣的三欄:x、y 與 z。
每個軸向量的長度(Vector3.length())決定縮放,而軸向量的方向決定旋轉。通常三軸互相垂直;若單獨旋轉其中任一軸,基底便會產生斜切,套用在 3D 模型上就會出現失真。
Basis 可能具備下列性質:
正交(Orthogonal):三軸互相垂直。
正規化(Normalized):每軸長度皆為
1.0。等比例(Uniform):三軸長度相同(參閱 get_scale())。
正交正規(Orthonormal):同時正交且正規化,只能表示旋轉(參閱 orthonormalized())。
共形(Conformal):同時正交且等比例,確保無失真。
如需概念導讀,請參閱教學文件:矩陣與變換。
注意: Godot 採用右手座標系。以內建元件 Camera3D 為例,-Z 代表向前、+X 向右、+Y 向上、+Z 向後。其他物件可能有不同方向慣例,詳見教學:3D 資產方向慣例。
注意: 基矩陣在腳本層以 欄優先(column-major)方式公開,與 OpenGL 相同;內部則以列優先(row-major)存放,與 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 左乘任意基底時,會反轉所有軸的 Vector3.x 分量(X 列)。
FLIP_Y = Basis(1, 0, 0, 0, -1, 0, 0, 0, 1) 🔗
任意基底右乘 FLIP_Y 時,會反轉 y 軸(Y 欄)的所有分量。
FLIP_Y 左乘任意基底時,會反轉所有軸的 Vector3.y 分量(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# 中,這會建構一個所有分量皆為 Vector3.ZERO 的 Basis。
建構指定 Basis 的複本。
Basis Basis(axis: Vector3, angle: float)
建構一個僅表示旋轉的 Basis,其旋轉為:繞 axis 轉動 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)
使用三個軸向量建構 Basis;這三個向量即為矩陣的三個欄。
方法說明
Returns the determinant of this basis's matrix. For advanced math, this number can be used to determine a few attributes:
If the determinant is exactly
0.0, the basis is not invertible (see inverse()).If the determinant is a negative number, the basis represents a negative scale.
Note: If the basis's scale is the same for every axis, its determinant is always that scale by the power of 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, -1, 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)
GD.Print(myBasis.Y); // 印出 (0, 4, 0)
GD.Print(myBasis.Z); // 印出 (0, 0, 8)
注意: 線性代數中,該矩陣亦稱為對角矩陣。
Vector3 get_euler(order: int = 2) const 🔗
以 Vector3 形式(弧度)回傳此基底的旋轉歐拉角:
可用 order(參閱 EulerOrder)決定計算順序。預設為 YXZ 慣例(@GlobalScope.EULER_ORDER_YXZ):先算 Z(roll),再算 X(pitch),最後算 Y(yaw)。與之相反的 from_euler() 解析時會反向。
注意: 要正確取得值,基底需先 正交正規化(參閱 orthonormalized())。
注意: 歐拉角直觀但不適合複雜 3D 運算,如需穩定運算建議改用 get_rotation_quaternion() 取得 Quaternion。
注意: 在檢視器面板中,如 Node3D.rotation,旋轉通常以度數歐拉角顯示。
Quaternion get_rotation_quaternion() const 🔗
以 Quaternion 形式回傳此基底的旋轉。
注意: 四元數較適用於 3D 計算,但不直觀;若用於 UI 顯示,可改用 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(
new Vector3(2.0f, 0.0f, 0.0f),
new Vector3(0.0f, 4.0f, 0.0f),
new 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, 4, 8)
注意: 若 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, 2, -2)
GD.Print(myBasis.Y); // 印出 (0, 4, -4)
GD.Print(myBasis.Z); // 印出 (0, 6, -6)
Basis scaled_local(scale: Vector3) const 🔗
Returns this basis with each axis scaled by the corresponding component in the given scale.
The basis matrix's columns are multiplied by scale's components. This operation is a local scale (relative to self).
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) # Prints (0.0, 0.0, 0.0)
print(my_basis.y) # Prints (4.0, 4.0, 4.0)
print(my_basis.z) # Prints (-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); // Prints (0, 0, 0)
GD.Print(myBasis.Y); // Prints (4, 4, 4)
GD.Print(myBasis.Z); // Prints (-6, -6, -6)
Basis slerp(to: Basis, weight: float) const 🔗
以球面線性插值(SLERP)方式,依 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, 4, 7)
GD.Print(myBasis.Y); // 印出 (2, 5, 8)
GD.Print(myBasis.Z); // 印出 (3, 6, 9)
運算子說明
bool operator !=(right: Basis) 🔗
若兩個 Basis 矩陣的對應分量不相等,回傳 true。
注意: 由於浮點精度誤差,建議改用 is_equal_approx() 進行比較以提升可靠性。
Basis operator *(right: Basis) 🔗
將 right 基底乘以此基底(右乘)。
此運算與父子 Node3D 之間的變換相同。
Vector3 operator *(right: Vector3) 🔗
將向量 right 乘以此基底並回傳 Vector3 結果。
# 可交換 X/Z 並將縮放加倍的 Basis
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 並將縮放加倍的 Basis
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, 2, 6)
Basis operator *(right: float) 🔗
將此 Basis 所有分量乘以指定 float,等比例改變三軸尺寸。
Basis operator *(right: int) 🔗
將此 Basis 所有分量乘以指定 int,等比例改變三軸尺寸。
Basis operator /(right: float) 🔗
將此 Basis 所有分量除以指定 float,等比例改變三軸尺寸。
Basis operator /(right: int) 🔗
將此 Basis 所有分量除以指定 int,等比例改變三軸尺寸。
bool operator ==(right: Basis) 🔗
若兩個 Basis 矩陣的對應分量完全相同,回傳 true。
注意: 由於浮點精度誤差,建議改用 is_equal_approx() 進行比較以提升可靠性。
Vector3 operator [](index: int) 🔗
透過索引存取此基底的各軸(欄)。索引 0 等同 x、1 等同 y、2 等同 z。
注意: 在 C++ 中,該運算子會存取矩陣的列,而非欄;若要與腳本語言行為一致,請使用 set_column 與 get_column。