Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

TSCN 文件格式

TSCN(文本场景)文件格式表示 Godot 内部的单个场景树。与二进制的 SCN 文件不同,TSCN 具有易于人类阅读、便于使用版本控制系统进行管理的优点。

The ESCN (exported scene) file format is identical to the TSCN file format, but is used to indicate to Godot that the file has been exported from another program and should not be edited by the user from within Godot. Unlike SCN and TSCN files, during import, ESCN files are compiled to binary SCN files stored inside the .godot/imported/ folder. This reduces the data size and speeds up loading, as binary formats are faster to load compared to text-based formats.

To make files more compact, properties equal to the default value are not stored in scene/resource files. It is possible to write them manually, but they will be discarded when saving the file.

如果想要完整的描述,对这些文件格式的解析是在 resource_format_text.cppResourceFormatLoaderText 类中进行处理的。

备注

The scene and resource file formats have changed significantly in Godot 4, with the introduction of string-based UIDs to replace incremental integer IDs.

Mesh, skeleton and animation data is also stored differently compared to Godot 3. You can read about some of the changes in this article: Animation data rework for 4.0

Scenes and resources saved with Godot 4.x contain format=3 in their header, whereas Godot 3.x uses format=2 instead.

文件结构

TSCN 文件分为五个主要部分:

  1. 文件描述符

  2. 外部资源

  3. 内部资源

  4. 节点

  5. 连接

The file descriptor looks like [gd_scene load_steps=4 format=3 uid="uid://cecaux1sm7mo0"] and should be the first entry in the file. The load_steps parameter is equal to the total amount of resources (internal and external) plus one (for the file itself). If the file has no resources, load_steps is omitted. The engine will still load the file correctly if load_steps is incorrect, but this will affect loading bars and any other piece of code relying on that value.

uid is an unique string-based identifier representing the scene. This is used by the engine to track files that are moved around, even while the editor is closed. Scripts can also load UID-based resources using the uid:// path prefix to avoid relying on filesystem paths. This makes it possible to move around a file in the project, but still be able to load it in scripts without having to modify the script. Godot does not use external files to keep track of IDs, which means no central metadata storage location is required within the project. See this pull request for detailed information.

These sections should appear in order, but it can be hard to distinguish them. The only difference between them is the first element in the heading for all of the items in the section. For example, the heading of all external resources should start with [ext_resource ...].

A TSCN file may contain single-line comments starting with a semicolon (;). However, comments will be discarded when saving the file using the Godot editor. Whitespace within a TSCN file is not significant (except within strings), but extraneous whitespace will be discarded when saving the file.

文件中的条目

A heading looks like [<resource_type> key1=value1 key2=value2 key3=value3 ...] where resource_type is one of:

  • ext_resource

  • sub_resource

  • node

  • connection

Below every heading comes zero or more key = value pairs. The values can be complex datatypes such as Arrays, Transforms, Colors, and so on. For example, a Node3D looks like:

[node name="Cube" type="Node3D"]
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 and (most of the time) a type. For example: [node name="PlayerCamera" type="Camera" parent="Player/Head"]

其他有效的关键字包括:

  • instance

  • instance_placeholder

  • owner

  • index (sets the order of appearance in the tree; if absent, inherited nodes will take precedence over plain ones)

  • groups

The first node in the file, which is also the scene root, must not have a parent="Path/To/Node" entry in its heading. All scene files should have exactly one scene root. If it doesn't, Godot will fail to import the file. The parent path of other nodes should be absolute, but shouldn't contain the scene root's name. If the node is a direct child of the scene root, the path should be ".". Here is an example scene tree (but without any node content):

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

小技巧

To make the file structure easier to grasp, you can saving a file with any given node or resource then inspect it yourself in an external editor. You can also make incremental changes in the Godot editor, and keep an external text editor open on the .tscn or .tres file with auto-reload enabled to see what changes.

Here is an example of a scene containing a RigidBody3D-based ball with collision, visuals (mesh + light) and a camera parented to the RigidBody3D:

[gd_scene load_steps=4 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"]

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

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

[node name="OmniLight3D" type="OmniLight3D" parent="."]
light_color = Color(1, 0.698039, 0.321569, 1)
omni_range = 10.0

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

节点路径

A tree structure is not enough to represent the whole scene. Godot uses a NodePath(Path/To/Node) structure to refer to another node or attribute of the node anywhere in the scene tree. Paths are relative to the current node, with NodePath(".") pointing to the current node and NodePath("") pointing to no node at all.

For instance, MeshInstance3D uses NodePath() to point to its skeleton. Likewise, Animation tracks use NodePath() to point to node properties to animate.

NodePath can also point to a property using a :property_name suffix, and even point to a specific component for vector, transform and color types. This is used by Animation resources to point to specific properties to animate. For example, NodePath("MeshInstance3D:scale.x") points to the x component of the scale Vector3 property in MeshInstance3D.

For example, the skeleton property in the MeshInstance3D node called mesh points to its parent, Armature01:

[node name="mesh" type="MeshInstance3D" parent="Armature01"]
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"]
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 = "name of bone" 属性,以及匹配骨骼索引的属性。

以 Skeleton 中的骨骼为父级的 Marker3D 节点示例:

[node name="GunBone" type="BoneAttachment3D" parent="PlayerModel/Robot_Skeleton/Skeleton3D" index="5"]
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"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.4, 0)

AnimationPlayer

The AnimationPlayer node works with one or more animation libraries stored in AnimationLibrary resources. An animation library is a collection of individual Animation resources, whose structure is documented here.

This split between animations themselves and animation libraries was done in Godot 4, so that animations can be imported separately from 3D meshes, which is a common workflow in 3D animation software. See the original pull request for details.

If the library name is empty, then it acts acts 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.

资源

Resources are components that make up the nodes. For example, a MeshInstance3D node will have an accompanying ArrayMesh resource. The ArrayMesh resource may be either internal or external to the TSCN file.

References to the resources are handled by unique string-based IDs in the resource's heading. This is different from the uid property, which each external resource also has (but subresources don't).

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

For example, to refer to the resource [ext_resource type="Material" uid="uid://c4cp0al3ljsjv" path="res://material.tres" id="1_7bt6s"], you would use ExtResource("1_7bt6s").

外部资源

External resources are links to resources not contained within the TSCN file itself. An external resource consists of a path, a type, an UID (used to map its filesystem location to an unique identifier) and an ID (used to refer to the resource in the scene file).

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"]

Like TSCN files, a TRES file may contain single-line comments starting with a semicolon (;). However, comments will be discarded when saving the resource using the Godot editor. Whitespace within a TRES file is not significant (except within strings), but extraneous whitespace will be discarded when saving the file.

内部资源

TSCN文件可以包含网格, 材质和其他数据. 这些包含在文件的 内部资源 部分中. 内部资源的标题与外部资源的标题相似, 不同之处在于它没有路径. 内部资源在每个标题下还具有 键=值 对. 例如, 胶囊碰撞形状如下所示:

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

一些内部资源包含到其他内部资源的链接(例如具有材质的网格). 在这种情况下, 引用的资源必须在对其的引用 之前 出现. 这意味着顺序在文件的内部资源部分中很重要.

ArrayMesh

An ArrayMesh consists of several surfaces contained in the _surfaces array (notice the leading underscore). Each surface's data is stored in a dictionary with the following keys:

  • aabb: The computed axis-aligned bounding box for visibility. Mesh.PrimitiveType Godot enum. 0 = points, 1 = lines, 2 = line strip, 3 = triangles (most common), 4 = triangle strip.

  • attribute_data: Vertex attribute data, such as normals, tangents, vertex colors, UV1, UV2 and custom vertex data.

  • bone_aabbs: The axis-aligned bounding box of each bone for visibility.

  • format: The surface's buffer format.

  • index_count: The number of indices in the surface. This must match index_data's size.

  • index_data: The index data, which determines which vertices from vertex_data are drawn.

  • lods: Level of detail variations, stored as an array. Each LOD level represents two values in the array. The first value is the percentage of screen space the LOD level is most suited for (edge length); the second value is the list of indices that should be drawn for the given LOD level.

  • material: The material used when drawing the surface.

  • name: The surface's name. This can be used in scripts and is imported from 3D DCCs.

  • primitive: The surface's primitive type, matching the

  • skin_data: Bone weight data.

  • vertex_count: Number of vertices in the surface. This must match vertex_data's size.

  • vertex_data: The vertex position data.

Here's an example of an ArrayMesh saved to its own .tres file. Some fields were shortened with ... for brevity:

[gd_resource type="ArrayMesh" load_steps=2 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

动画

Each animation has the following properties:

  • length: The animation's length in seconds. Note that keyframes may be placed outside the [0; length] interval, but they may have no effect depending on the interpolation mode chosen.

  • loop_mode: 0 = no looping, 1 = wrap-around looping, 2 = clamped looping.

  • step: The step size to use when editing this animation in the editor. This is only used in the editor; it doesn't affect animation playback in any way.

Each track is described by a list of key-value pairs in the format tracks/<id>/<attribute>. Each track includes:

  • type :轨道的类型。这个属性定义了该轨道可以动画化哪种属性,以及如何在编辑器中向用户公开它。有效类型为 value (通用属性轨道)、 position_3drotation_3dscale_3dblend_shape (优化的 3D 动画轨道)、 method (方法调用轨道)、 bezier (贝塞尔曲线轨道)、 audio (音频播放轨道)、 animation (播放其他动画的轨道)。

  • imported :如果轨道是从导入的 3D 场景创建的,则为 true ;如果轨道是由用户在 Godot 编辑器中或使用脚本手动创建的,则为 false

  • enabled :如果轨道有效的(即被启用),则为 true ;如果轨道在编辑器中被禁用,则为 false

  • path :将受轨道影响的节点属性的路径。该属性写在节点路径后面,并使用 : 分隔符。

  • interp :要使用的插值模式。 0 = 最近(nearest), 1 = 线性(linear), 2 = 立方(cubic), 3 = 线性角度(linear angle), 4 = 立方角度(cubic angle)。

  • loop_wrap: true if the track is designed to wrap around when the animation is looping, false if the track clamps to the first/last keyframes.

  • keys :动画轨道的值。该属性的结构取决于 type

这是一个包含 AnimationPlayer 的场景,它使用通用属性轨道,随时间推进缩小立方体。由于未使用 AnimationLibrary 工作流程,此动画库的名称为空(但动画仍指定为 scale_down 名称)。请注意,为了简洁起见,没有在此 AnimationPlayer 中创建 RESET 轨道:

[gd_scene load_steps=4 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"]

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

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

对于通用属性 value 轨道, keys 是一个字典,其中包含 3 个数组。三个数组分别是:位置(position)位于 times (PackedFloat32Array)中;缓动值(easing value)位于 transitions (PackedFloat32Array)中;值(value)位于 values (Array)中。还有一个附加的 update 属性,它是一个整数,其值代表的含义分别是: 0 = 连续(continuous), 1 = 离散(discrete), 2 = 捕获(capture)。

这是第二个动画资源,它利用了 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 位置、旋转和缩放轨道, key 是一个将所有值都存储在序列中的 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, ...)