Basis

用於表示 3D 旋轉與縮放的 3×3 矩陣。

說明

Basis 內建的 Variant 型別是一個 3×3 矩陣,用來表示 3D 旋轉、縮放與斜切,常與 Transform3D 一起使用。

Basis 由三個軸向量組成,分別為矩陣的三欄:xyz

每個軸向量的長度(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 的不同

教學

屬性

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

若將任何 Vector3Basis 與此常數相乘,結果不會產生任何變換。

注意: 在 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) 🔗

任意基底右乘 FLIP_Z 時,會反轉 z 軸(Z 欄)的所有分量。

FLIP_Z 左乘任意基底時,會反轉所有軸的 Vector3.z 分量(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# 中,這會建構一個所有分量皆為 Vector3.ZEROBasis


Basis Basis(from: 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;這三個向量即為矩陣的三個欄。


方法說明

float determinant() const 🔗

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

  • Vector3.x:繞 X 軸(俯仰,pitch)角度。

  • Vector3.y:繞 Y 軸(偏航,yaw)角度。

  • Vector3.z:繞 Z 軸(翻滾,roll)角度。

# 建立一個 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 形式(弧度)回傳此基底的旋轉歐拉角:

可用 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 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_front 設為 true,則改以 +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 🔗

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)

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 🔗

回傳 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 並將縮放加倍的 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)

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 等同 x1 等同 y2 等同 z

注意: 在 C++ 中,該運算子會存取矩陣的列,而欄;若要與腳本語言行為一致,請使用 set_columnget_column