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.

TSCN 檔案格式

TSCN(Text SCeNe)檔案格式代表 Godot 中的一個單一場景樹。與二進位 SCN 檔不同,TSCN 檔案主要具備可供人閱讀、方便版本控制的優勢。

ESCN(Exported SCeNe)檔案格式與 TSCN 完全相容,但用於標示此檔案為從其他程式匯出,不應在 Godot 內被編輯。與 SCN/TSCN 不同,ESCN 在匯入時會被編譯為二進位 SCN 檔,儲存在 .godot/imported/ 資料夾中,這有助於減少資料大小並加速載入。

為了讓檔案更精簡,等於預設值的屬性不會儲存在場景/資源檔內。雖然可以手動寫入,但在儲存時會被自動移除。

如需完整說明,請參考 ResourceFormatLoaderText 類別中負責剖析的 resource_format_text.cpp 檔案。

備註

Godot 4 的場景與資源檔案格式有重大變動,新增以字串為基礎的 UID,以取代以往的遞增整數 ID。

與 Godot 3 相比,網格、骨架與動畫資料的儲存方式也不同。部分變更可參考:4.0 的動畫資料重構

以 Godot 4.x 儲存的場景與資源檔案標頭會包含 format=3,而 Godot 3.x 為 format=2

檔案結構

TSCN 檔案主要分為五個區段:

  1. 檔案描述

  2. 外部資源

  3. 內部資源

  4. 節點

  5. 連線

The file descriptor looks like [gd_scene format=3 uid="uid://cecaux1sm7mo0"] and should be the first entry in the file. Note that scenes saved before Godot 4.6 will also have a load_steps=<int> attribute in the file descriptor. This attribute is now deprecated and should be ignored if present.

uid 是用來代表場景的唯一字串識別碼。引擎會用來追蹤檔案位置變動,即使編輯器關閉也一樣。腳本可透過 uid:// 路徑前綴載入 UID 資源,無需依賴檔案系統路徑,方便專案內移動資源又不需修改腳本。Godot 不用外部檔案記錄 ID,因此不需專案內存在中央 metadata。詳情見此 pull request:<https://github.com/godotengine/godot/pull/50786>。

這些區段應依順序出現,但區分上可能有些困難。區段的差別主要在於每個專案標頭的首個元素。例如,所有外部資源的標頭皆以 [ext_resource ...] 開始。

TSCN 檔案可包含以分號(;)開頭的單行註解,但以 Godot 編輯器儲存時註解會被移除。檔案內空白字元(除字串外)也會在儲存時去除。

檔案中的專案

每個標頭格式為 [<resource_type> key1=value1 key2=value2 ...],其中 resource_type 可為:

  • ext_resource

  • sub_resource

  • node

  • connection

每個標頭下方可有 0 個或多個 key = value 索引鍵/值組。值可為如 Array、Transform、Color 等複雜型別。例如,一個 Node3D 可能為:

[node name="Cube" type="Node3D" unique_id=224283918]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 2, 3)

場景樹

The scene tree is made up of… nodes! The heading of each node consists of its name, parent, a unique ID (used to track nodes even if they are moved or renamed), and most of the time, a type. For example: [node name="PlayerCamera" type="Camera" parent="Player/Head" unique_id=1697057368]

Note that unique_id is only present in scenes saved with Godot 4.6 or later. Therefore, it is not guaranteed to be present.

其他有效的關鍵字還有:

  • instance

  • instance_placeholder

  • owner

  • index (設定在樹中的出現順序,若缺省則繼承節點優先於一般節點)

  • groups

  • node_paths (lists names of properties exported as a Node type, but referenced as a NodePath in the file)

檔案的第一個節點即為場景根節點,標頭**不得**包含 parent="Path/To/Node"。所有場景檔應恰有*一個*根節點,否則 Godot 會匯入失敗。其他節點的父路徑必須為絕對路徑,但不可包含根節點名稱。若為根節點的直接子節點,路徑應為 "."。以下為範例樹狀結構(無內容):

[node name="Player" type="Node3D" unique_id=1155673912]                    ; The scene root
[node name="Arm" type="Node3D" parent="." unique_id=1010797352]            ; Parented to the scene root
[node name="Hand" type="Node3D" parent="Arm" unique_id=536436825]          ; Child of "Arm"
[node name="Finger" type="Node3D" parent="Arm/Hand" unique_id=1732647084]  ; Child of "Hand"

小訣竅

為了更容易理解檔案結構,可以將任意節點或資源另存新檔後,使用外部編輯器檢查內容。你也可以在 Godot 編輯器做些微調整,並用外部文字編輯器開啟 .tscn.tres,啟用自動重新載入,即時觀察變更內容。

以下是一個包含基於 RigidBody3D 球體(含碰撞、網格、燈光)以及附掛在 RigidBody3D 上的相機的場景範例:

[gd_scene format=3 uid="uid://cecaux1sm7mo0"]

[sub_resource type="SphereShape3D" id="SphereShape3D_tj6p1"]

[sub_resource type="SphereMesh" id="SphereMesh_4w3ye"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_k54se"]
albedo_color = Color(1, 0.639216, 0.309804, 1)

[node name="Ball" type="RigidBody3D" unique_id=1358867382]

[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1279975976]
shape = SubResource("SphereShape3D_tj6p1")

[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=558852834]
mesh = SubResource("SphereMesh_4w3ye")
surface_material_override/0 = SubResource("StandardMaterial3D_k54se")

[node name="OmniLight3D" type="OmniLight3D" parent="." unique_id=1581292810 node_paths=PackedStringArray("follow_node")]
light_color = Color(1, 0.698039, 0.321569, 1)
omni_range = 10.0
follow_node = NodePath("..")

[node name="Camera3D" type="Camera3D" parent="." unique_id=795715540]
transform = Transform3D(1, 0, 0, 0, 0.939693, 0.34202, 0, -0.34202, 0.939693, 0, 1, 3)

NodePath

單純的樹狀結構不足以表現整個場景。Godot 以 NodePath(Path/To/Node) 結構,在場景樹中參照其他節點或其屬性。路徑為相對於當前節點,NodePath(".") 表示自己,NodePath("") 則表示無對應節點。

例如,MeshInstance3D 用 NodePath() 指向其骨架節點;動畫軌道同樣以 NodePath() 指向要動畫化的節點屬性。

NodePath 也能用 :property_name 後綴指向屬性,甚至細到向量、變換、顏色類型的特定分量。動畫資源會利用這點,指向要動畫化的特定屬性。例如: NodePath("MeshInstance3D:scale.x") 會指向 MeshInstance3D 節點中 scale (Vector3 屬性)的 x 分量。

舉例來說,名為 mesh 的 MeshInstance3D 節點的 skeleton 屬性會指向其父節點 Armature01

[node name="mesh" type="MeshInstance3D" parent="Armature01" unique_id=1638249225]
skeleton = NodePath("..")

Skeleton3D

Skeleton3D 節點繼承自 Node3D,同時也會以 bones/<id>/<attribute> = value 的格式記錄骨骼清單。骨骼屬性有:

  • position:Vector3

  • rotation:Quaternion

  • scale:Vector3

這些屬性皆為選填。例如骨骼可以只定義 positionrotation,不必全部設值。

以下為含兩個骨頭的骨架節點範例:

[node name="Skeleton3D" type="Skeleton3D" parent="PlayerModel/Robot_Skeleton" index="0" unique_id=542985694]
bones/1/position = Vector3(0.114471, 2.19771, -0.197845)
bones/1/rotation = Quaternion(0.191422, -0.0471201, -0.00831942, 0.980341)
bones/2/position = Vector3(-2.59096e-05, 0.236002, 0.000347473)
bones/2/rotation = Quaternion(-0.0580488, 0.0310587, -0.0085914, 0.997794)
bones/2/scale = Vector3(0.9276, 0.9276, 0.9276)

BoneAttachment3D

BoneAttachment3D 節點作為中介節點,用於描述某節點附掛在 Skeleton 節點中的單一骨骼下。BoneAttachment 會有一個 bone_name = "骨骼名稱" 屬性,以及對應骨骼索引的屬性。

以下為 Marker3D 附掛於 Skeleton 骨骼下的範例:

[node name="GunBone" type="BoneAttachment3D" parent="PlayerModel/Robot_Skeleton/Skeleton3D" index="5" unique_id=63481392]
transform = Transform3D(0.333531, 0.128981, -0.933896, 0.567174, 0.763886, 0.308015, 0.753209, -0.632331, 0.181604, -0.323915, 1.07098, 0.0497144)
bone_name = "hand.R"
bone_idx = 55

[node name="ShootFrom" type="Marker3D" parent="PlayerModel/Robot_Skeleton/Skeleton3D/GunBone" unique_id=679926736]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.4, 0)

AnimationPlayer

AnimationPlayer 節點會搭配一個或多個儲存在 AnimationLibrary 資源中的動畫庫使用。動畫庫即為多個 Animation 資源的集合,其結構可參考 此處

Godot 4 將動畫與動畫庫分離,讓動畫能獨立於 3D 網格匯入,這也是 3D 動畫軟體常見的流程。詳見 原始 pull request

If the library name is empty, then it acts as the unique source of animations for this AnimationPlayer. This allows using <animation_name> directly to play animations from script. If you name the library, then you must play it as <library_name>/<animation_name>. This ensures backwards compatibility and keeps the existing workflow if you don't want to use multiple animation libraries.

資源

資源是組成節點的各種元件。例如 MeshInstance3D 節點會有對應的 ArrayMesh 資源。這些 ArrayMesh 資源可存在於 TSCN 檔內或外部。

參照資源時會以資源標頭內唯一字串 ID 指定。這與外部資源的 uid 屬性不同(子資源則沒有 uid)。

External resources and internal resources are referred to with ExtResource("id") and SubResource("id"), respectively. Because there are different methods to refer to internal and external resources, you can have the same ID for both an internal and external resource.

舉例,若有 [ext_resource type="Material" uid="..." path="res://material.tres" id="1_7bt6s"],即可用 ExtResource("1_7bt6s") 參照該資源。

外部資源

外部資源是指連結到 TSCN 檔案外部的資源。包含路徑、型別、UID(用於唯一識別)及 ID(於場景檔內參照用)。

Godot 會產生相對於資源目錄的絕對路徑(以 res:// 為前綴),但也接受相對於 TSCN 檔案位置的路徑。

外部資源範例如下:

[ext_resource type="Texture2D" uid="uid://ccbm14ebjmpy1" path="res://gradient.tres" id="2_eorut"]
[ext_resource type="Material" uid="uid://c4cp0al3ljsjv" path="material.tres" id="1_7bt6s"]

與 TSCN 相同,TRES 檔可用分號(;)作單行註解,但以 Godot 編輯器儲存時註解會被清除。檔內空白(字串除外)也會被移除。

內部資源

TSCN 檔案可包含網格、材質等資料,這些都放在*內部資源*區段。內部資源標頭與外部資源類似,但不含路徑。每個標頭下也有 key=value 組。例如,一個膠囊碰撞形狀可能如下:

[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_fdxgg"]
radius = 1.0
height = 3.0

部分內部資源會連結至其他內部資源(如網格需指定材質)。這時被參照的資源必須出現在參照者*之前*,因此內部資源順序很重要。

ArrayMesh

ArrayMesh 由 _surfaces 陣列(底線開頭)中的多個表面組成。每個表面資料都以字典儲存,下列為主要鍵值:

  • aabb:已計算的軸對齊包圍盒,用於可見性判斷。

  • attribute_data:頂點屬性資料,例如法線、切線、頂點顏色、UV1、UV2 與自訂頂點資料。

  • bone_aabbs:每個骨骼的軸對齊包圍盒,用於判斷可見性。

  • format:表面的緩衝區格式。

  • index_count:表面索引數量。必須與 index_data 長度一致。

  • index_data:索引資料,決定從 vertex_data 中繪製哪些頂點。

  • lods:細節層級(Level of Detail, LOD)變化,儲存為陣列。每層包含兩個值:第一個是適用的螢幕空間百分比(邊長),第二個是該 LOD 所需繪製的索引清單。

  • material:繪製表面所用的材質。

  • name:表面名稱。可於腳本中使用,也可由 3D DCC 匯入。

  • primitive:表面原始類型,對應 Godot 的 Mesh.PrimitiveType 列舉。0 = 點,1 = 線段,2 = 線帶,3 = 三角形(最常用),4 = 三角帶。

  • skin_data:骨骼權重資料。

  • vertex_count:表面頂點數,必須與 vertex_data 長度一致。

  • vertex_data:頂點座標資料。

以下為 ArrayMesh 儲存為獨立 .tres 檔案的範例(部分欄位以 ... 省略):

[gd_resource type="ArrayMesh" format=3 uid="uid://dww8o7hsqrhx5"]

[ext_resource type="Material" path="res://player/model/playerobot.tres" id="1_r3bjq"]

[resource]
resource_name = "player_Sphere_016"
_surfaces = [{
"aabb": AABB(-0.207928, 1.21409, -0.14545, 0.415856, 0.226569, 0.223374),
"attribute_data": PackedByteArray(63, 121, ..., 117, 63),
"bone_aabbs": [AABB(0, 0, 0, -1, -1, -1), ..., AABB(-0.207928, 1.21409, -0.14545, 0.134291, 0.226569, 0.223374)],
"format": 7191,
"index_count": 1224,
"index_data": PackedByteArray(30, 0, ..., 150, 4),
"lods": [0.0382013, PackedByteArray(33, 1, ..., 150, 4)],
"material": ExtResource("1_r3bjq"),
"name": "playerobot",
"primitive": 3,
"skin_data": PackedByteArray(15, 0, ..., 0, 0),
"vertex_count": 1250,
"vertex_data": PackedByteArray(196, 169, ..., 11, 38)
}]
blend_shape_mode = 0

動畫

每個動畫有以下屬性:

  • length:動畫長度(秒)。注意關鍵影格可設於 [0; length] 區間外,但實際效果依所選插值模式而定。

  • loop_mode0 = 不循環,1 = 環繞循環,2 = 限制循環。

  • step:於編輯器編輯此動畫時的步進值。僅供編輯用途,對動畫播放無影響。

每個軌道皆以 tracks/<id>/<attribute> 格式的索引鍵/值組描述。軌道內容包括:

  • type :軌道類型。定義本軌道可動畫化的屬性與編輯器的顯示方式。有效類型包括 value (一般屬性軌道)、 position_3drotation_3dscale_3dblend_shape (最佳化 3D 軌道)、 method (方法軌道)、 bezier (貝塞爾曲線軌道)、 audio (音訊軌道)、 animation (播放其他動畫的軌道)。

  • imported:若軌道來源為匯入 3D 場景則為 true,若由使用者透過 Godot 編輯器或腳本建立則為 false

  • enabled:軌道啟用時為 true,於編輯器中關閉時為 false

  • path:本軌道作用的節點屬性路徑。屬性名稱以 : 接在節點路徑後。

  • interp:插值模式。0 = 最接近,1 = 線性,2 = 立方,3 = 線性角度,4 = 立方角度。

  • loop_wrap:若此軌道設計為動畫循環時自動環繞則為 true,若僅限首/末關鍵影格則為 false

  • keys:本動畫軌道的數值。其結構取決於 type

以下是一個場景,包含一個 AnimationPlayer,利用通用屬性軌道隨時間縮小方塊。此例未使用 AnimationLibrary,因此動畫庫名稱為空(動畫名稱為 scale_down)。為簡潔起見,未建立 RESET 軌道:

[gd_scene format=3 uid="uid://cdyt3nktp6y6"]

[sub_resource type="Animation" id="Animation_r2qdp"]
resource_name = "scale_down"
length = 1.5
loop_mode = 2
step = 0.05
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Box:scale")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(1, 1, 1), Vector3(0, 0, 0)]
}

[sub_resource type="AnimationLibrary" id="AnimationLibrary_4qx36"]
_data = {
"scale_down": SubResource("Animation_r2qdp")
}

[sub_resource type="BoxMesh" id="BoxMesh_u688r"]

[node name="Node3D" type="Node3D" unique_id=2076735200]

[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=2139773137]
autoplay = "scale_down"
libraries = {
"": SubResource("AnimationLibrary_4qx36")
}

[node name="Box" type="MeshInstance3D" parent="." unique_id=711004519]
mesh = SubResource("BoxMesh_u688r")

針對通用屬性 value 軌道,keys 為字典,含三個陣列:「times」(PackedFloat32Array,關鍵影格時間)、「transitions」(PackedFloat32Array,緩動值)、「values」(Array,數值)。另有一 update 屬性,整數型別:0 = 連續,1 = 離散,2 = 捕獲。

以下為另一個動畫資源,使用 3D 位置與 3D 旋轉軌道(加上 3D 縮放軌道),取代 Godot 3 的 Transform 軌道。這些軌道經優化,可高速播放,也可選擇壓縮。

這些最佳化軌道的限制是無法自訂緩動值,所有關鍵影格皆用線性插值。不過,仍可修改軌道的插值模式,選擇「最近」或「立方」插值。

[sub_resource type="Animation" id="Animation_r2qdp"]
resource_name = "move_and_rotate"
length = 1.5
loop_mode = 2
step = 0.05
tracks/0/type = "position_3d"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Box")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = PackedFloat32Array(0, 1, 0, 0, 0, 1.5, 1, 1.5, 1, 0)
tracks/1/type = "rotation_3d"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Box")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = PackedFloat32Array(0, 1, 0.211, -0.047, 0.211, 0.953, 1.5, 1, 0.005, 0.976, -0.216, 0.022)

對於 3D 位置、旋轉與縮放軌道,keys 為 PackedFloat32Array,所有值依序儲存。

以下說明中,T 代表關鍵影格自動畫起始以來的時間(秒),E 是關鍵影格的轉換值(目前皆為 1)。3D 位置與縮放軌道的 XYZ 為 Vector3 座標值;3D 旋轉軌道的 XYZW 為四元數座標。

# For 3D position and scale, which use Vector3:
tracks/<id>/keys = PackedFloat32Array(T, E,   X, Y, Z,      T, E,   X, Y, Z, ...)

# For 3D rotation, which use Quaternion:
tracks/<id>/keys = PackedFloat32Array(T, E,   X, Y, Z, W,      T, E,   X, Y, Z, W, ...)