Формат файла TSCN¶
The TSCN (text scene) file format represents a single scene tree inside Godot. Unlike binary SCN files, TSCN files have the advantage of being mostly human-readable and easy for version control systems to manage.
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 .import/
folder.
This reduces the data size and speeds up loading, as binary formats are faster
to load compared to text-based formats.
Для тех, кто ищет полное описание, парсинг выполняется в файле resource_format_text.cpp в классе ResourceFormatLoaderText
.
Структура файла¶
TSCN-файл состоит из пяти основных секций:
Дескриптор файла
Внешние ресурсы
Внутренние ресурсы
Узлы
Соединения
The file descriptor looks like [gd_scene load_steps=3 format=2]
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.
Эти разделы должны появляться по порядку, но их бывает трудно различить. Единственное различие между ними - это первый элемент в заголовке для всех элементов раздела. Например, заголовок всех внешних ресурсов должен начинаться с [ext_resource .....]
.
Файл TSCN может содержать однострочные комментарии, начинающиеся с точки с запятой (;
). Однако комментарии будут отброшены при сохранении файла с помощью редактора Godot.
Записи внутри файла¶
Заголовок выглядит как [<resource_type> key=value key=value key=value ...]
, где тип_ресурса является одним из:
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 spatial node looks like:
[node name="Cube" type="Spatial" parent="."]
transform=Transform( 1.0, 0.0, 0.0 ,0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 )
Дерево сцены¶
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 type="Camera" name="PlayerCamera" parent="Player/Head"]
Other valid keywords include:
instance
instance_placeholder
owner
index
(sets the order of appearance in the tree. If absent, inherited nodes will take precedence over plain ones)
groups
Первый узел в файле, который также является корнем сцены, не должен иметь запись parent=Path/To/Node
в своем заголовке. Все файлы сцен должны иметь ровно один корень сцены. Если этого не произойдет, Godot не сможет импортировать файл. Родительский путь других узлов должен быть абсолютным, но не должен содержать имя корня сцены. Если узел является прямым потомком корня сцены, путь должен быть ".". Вот пример дерева сцены (но без содержимого узла):
[node name="Player" type="Spatial"] ; The scene root
[node name="Arm" parent="." type="Spatial"] ; Parented to the scene root
[node name="Hand" parent="Arm" type="Spatial"]
[node name="Finger" parent="Arm/Hand" type="Spatial"]
Подобно внутреннему ресурсу, документ для каждого узла в настоящее время является неполным. К счастью, это легко выяснить, так как вы можете просто сохранить файл с этим узлом. Примерами узлов являются:
[node type="CollisionShape" name="SphereCollision" parent="SpherePhysics"]
shape = SubResource(8)
transform = Transform( 1.0 , 0.0 , -0.0 , 0.0 , -4.371138828673793e-08 , 1.0 , -0.0 , -1.0 , -4.371138828673793e-08 ,0.0 ,0.0 ,-0.0 )
[node type="MeshInstance" name="Sphere" parent="SpherePhysics"]
mesh = SubResource(9)
transform = Transform( 1.0 , 0.0 , -0.0 , 0.0 , 1.0 , -0.0 , -0.0 , -0.0 , 1.0 ,0.0 ,0.0 ,-0.0 )
[node type="OmniLight" name="Lamp" parent="."]
light_energy = 1.0
light_specular = 1.0
transform = Transform( -0.29086464643478394 , -0.7711008191108704 , 0.5663931369781494 , -0.05518905818462372 , 0.6045246720314026 , 0.7946722507476807 , -0.9551711678504944 , 0.199883371591568 , -0.21839118003845215 ,4.076245307922363 ,7.3235554695129395 ,-1.0054539442062378 )
omni_range = 30
shadow_enabled = true
light_negative = false
light_color = Color( 1.0, 1.0, 1.0, 1.0 )
[node type="Camera" name="Camera" parent="."]
projection = 0
near = 0.10000000149011612
fov = 50
transform = Transform( 0.6859206557273865 , -0.32401350140571594 , 0.6515582203865051 , 0.0 , 0.8953956365585327 , 0.44527143239974976 , -0.7276763319969177 , -0.3054208755493164 , 0.6141703724861145 ,14.430776596069336 ,10.093015670776367 ,13.058500289916992 )
far = 100.0
NodePath¶
Древовидной структуры недостаточно для представления всей сцены. Godot использует структуру NodePath(Path/To/Node)
для ссылки на другой узел или атрибут узла в любом месте дерева сцены. Например, MeshInstance использует NodePath()
для указания на свой скелет. Аналогично, треки анимации используют NodePath()
для указания на свойства узла для анимации.
[node name="mesh" type="MeshInstance" parent="Armature001"]
mesh = SubResource(1)
skeleton = NodePath("..:")
[sub_resource id=3 type="Animation"]
...
tracks/0/type = "transform
tracks/0/path = NodePath("Cube:")
...
Скелет¶
Узел Skeleton наследует узел Spatial, но также может иметь список костей, описанных в парах ключ-значение в формате bones/Id/Attribute=Value
. Атрибуты костей состоят из:
имя
parent
rest
pose
enabled
bound_children
name
must be the first attribute of each bone.parent
is the index of parent bone in the bone list, with parent index, the bone list is built to a bone tree.rest
is the transform matrix of bone in its "resting" position.pose
is the pose matrix; userest
as the basis.bound_children
is a list ofNodePath()
which point to BoneAttachments belonging to this bone.
Here's an example of a skeleton node with two bones:
[node name="Skeleton" type="Skeleton" parent="Armature001" index="0"]
bones/0/name = "Bone.001"
bones/0/parent = -1
bones/0/rest = Transform( 1, 0, 0, 0, 0, -1, 0, 1, 0, 0.038694, 0.252999, 0.0877164 )
bones/0/pose = Transform( 1.0, 0.0, -0.0, 0.0, 1.0, -0.0, -0.0, -0.0, 1.0, 0.0, 0.0, -0.0 )
bones/0/enabled = true
bones/0/bound_children = [ ]
bones/1/name = "Bone.002"
bones/1/parent = 0
bones/1/rest = Transform( 0.0349042, 0.99939, 0.000512929, -0.721447, 0.0248417, 0.692024, 0.691589, -0.0245245, 0.721874, 0, 5.96046e-08, -1.22688 )
bones/1/pose = Transform( 1.0, 0.0, -0.0, 0.0, 1.0, -0.0, -0.0, -0.0, 1.0, 0.0, 0.0, -0.0 )
bones/1/enabled = true
bones/1/bound_children = [ ]
BoneAttachment¶
Узел BoneAttachment является промежуточным узлом для описания некоторого узла, являющегося родительским для одной кости в узле Skeleton. Узел BoneAttachment имеет атрибут bone_name=NameOfBone
, а соответствующая кость, являющаяся родителем, имеет узел BoneAttachment в списке bound_children
.
Пример одного MeshInstance, родительского по отношению к кости в Skeleton:
[node name="Armature" type="Skeleton" parent="."]
transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, -0.0219986, 0.0125825, 0.0343127)
bones/0/name = "Bone"
bones/0/parent = -1
bones/0/rest = Transform(1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0)
bones/0/pose = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0)
bones/0/enabled = true
bones/0/bound_children = [NodePath("BoneAttachment:")]
[node name="BoneAttachment" type="BoneAttachment" parent="Armature"]
bone_name = "Bone"
[node name="Cylinder" type="MeshInstance" parent="Armature/BoneAttachment"]
mesh = SubResource(1)
transform = Transform(1.0, 0.0, 0.0, 0.0, 1.86265e-09, 1.0, 0.0, -1.0, 0.0, 0.0219986, -0.0343127, 2.25595)
AnimationPlayer¶
AnimationPlayer работает как библиотека анимаций. Он хранит анимации, перечисленные в формате anim/Name=SubResource(ResourceId)
; каждая строка ссылается на ресурс анимации. Все анимационные ресурсы используют корневой узел AnimationPlayer. Корневой узел хранится как root_node=NodePath(Path/To/Node)
.
[node name="AnimationPlayer" type="AnimationPlayer" parent="." index="1"]
root_node = NodePath("..")
autoplay = ""
playback_process_mode = 1
playback_default_blend_time = 0.0
playback_speed = 1.0
anims/default = SubResource( 2 )
blend_times = [ ]
Ресурсы¶
Ресурсы - это компоненты, из которых состоят узлы. Например, узел MeshInstance будет иметь сопутствующий ресурс ArrayMesh. Ресурс ArrayMesh может быть как внутренним, так и внешним по отношению к файлу TSCN.
Ссылки на ресурсы обрабатываются номерами id
в заголовке ресурса. Внешние и внутренние ресурсы обозначаются соответственно ExtResource(id)
и SubResource(id)
. Поскольку существуют различные методы ссылки на внутренние и внешние ресурсы, вы можете иметь один и тот же ID для внутреннего и внешнего ресурса.
Например, чтобы обратиться к ресурсу [ext_resource id=3 type="PackedScene" path=....]
, вы будете использовать ExtResource(3)
.
Внешние ресурсы¶
Внешние ресурсы - это ссылки на ресурсы, не содержащиеся в самом файле TSCN. Внешний ресурс состоит из пути, типа и идентификатора.
Godot всегда генерирует абсолютные пути относительно каталога ресурсов и, следовательно, с префиксом res://
, но пути относительно местоположения файла TSCN также допустимы.
Примерами внешних ресурсов являются:
[ext_resource path="res://characters/player.dae" type="PackedScene" id=1]
[ext_resource path="metal.tres" type="Material" id=2]
Как и файлы TSCN, файл TRES может содержать однострочные комментарии, начинающиеся с точки с запятой (;
). Однако комментарии будут отброшены при сохранении ресурса с помощью редактора Godot.
Внутренние ресурсы¶
Файл TSCN может содержать сетки, материалы и другие данные. Они содержатся в разделе внутренние ресурсы файла. Заголовок внутреннего ресурса выглядит так же, как и заголовки внешних ресурсов, за исключением того, что у него нет пути. Внутренние ресурсы также имеют пары ``ключ=значение'' под каждым заголовком. Например, форма столкновения капсулы выглядит следующим образом:
[sub_resource type="CapsuleShape" id=2]
radius = 0.5
height = 3.0
Некоторые внутренние ресурсы содержат ссылки на другие внутренние ресурсы (например, сетка, имеющая материал). В этом случае ссылающийся ресурс должен появиться перед ссылкой на него. Это означает, что порядок имеет значение в разделе внутренних ресурсов файла.
К сожалению, документация по форматам этих подресурсов неполная. Некоторые примеры можно найти, изучив сохраненные файлы ресурсов, но другие можно найти, только просмотрев исходный текст Godot.
ArrayMesh¶
ArrayMesh состоит из нескольких поверхностей, каждая из которых имеет формат ``surfaceIndex={}`. Каждая поверхность представляет собой набор вершин и материал.
Файлы TSCN поддерживают два формата поверхности:
В старом формате каждая поверхность имеет три основные клавиши:
primitive
arrays
morph_arrays
primitive
- это переменная перечисления, часто используетсяprimitive=4
, которая являетсяPRIMITIVE_TRIANGLES
.arrays
- это двумерный массив, он содержит:Vertex positions array
Normals array
Массив касательных
Массив цветов вершин
UV массив 1
UV массив 2
Массив индексов костей
Массив весов костей
Массив вершинных индексов
morph_arrays
is an array of morphs. Each morph is exactly anarrays
without the vertex indexes array.
Пример ArrayMesh:
[sub_resource id=1 type="ArrayMesh"]
surfaces/0 = {
"primitive":4,
"arrays":[
Vector3Array(0.0, 1.0, -1.0, 0.866025, -1.0, -0.5, 0.0, -1.0, -1.0, 0.866025, 1.0, -0.5, 0.866025, -1.0, 0.5, 0.866025, 1.0, 0.5, -8.74228e-08, -1.0, 1.0, -8.74228e-08, 1.0, 1.0, -0.866025, -1.0, 0.5, -0.866025, 1.0, 0.5, -0.866025, -1.0, -0.5, -0.866025, 1.0, -0.5),
Vector3Array(0.0, 0.609973, -0.792383, 0.686239, -0.609973, -0.396191, 0.0, -0.609973, -0.792383, 0.686239, 0.609973, -0.396191, 0.686239, -0.609973, 0.396191, 0.686239, 0.609973, 0.396191, 0.0, -0.609973, 0.792383, 0.0, 0.609973, 0.792383, -0.686239, -0.609973, 0.396191, -0.686239, 0.609973, 0.396191, -0.686239, -0.609973, -0.396191, -0.686239, 0.609973, -0.396191),
null, ; No Tangents,
null, ; no Vertex Colors,
null, ; No UV1,
null, ; No UV2,
null, ; No Bones,
null, ; No Weights,
IntArray(0, 2, 1, 3, 1, 4, 5, 4, 6, 7, 6, 8, 0, 5, 9, 9, 8, 10, 11, 10, 2, 1, 10, 8, 0, 1, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 5, 0, 3, 0, 9, 11, 9, 5, 7, 9, 10, 11, 11, 2, 0, 10, 1, 2, 1, 6, 4, 6, 1, 8)
],
"morph_arrays":[]
}
Анимация¶
Анимационный ресурс состоит из дорожек. Кроме того, у него есть длительность
(length), петля
(loop) и шаг
(step), применяемые ко всем дорожкам.
длительность
ишаг
- это продолжительность в секундах.
Каждый трек описывается списком пар ключ-значение в формате tracks/Id/Attribute
. Каждый трек включает в себя:
тип
(type)path
interp
ключи
(keys)loop_wrap
импортировано
(imported)enabled
Атрибут
type
должен быть первым атрибутом каждого трека. Значениеtype
может быть:transform
value
метод
(method)
path
имеет форматNodePath(Path/To/Node:attribute)
. Это путь к анимированному узлу или атрибуту, относительно корневого узла, определенного в AnimationPlayer.interp
- это метод интерполяции кадров из ключевых кадров. Это переменная enum с одним из следующих значений:0
(константа)1
(linear)2
(cubic)
The
keys
correspond to the keyframes. It appears as aPoolRealArray()
, but may have a different structure for tracks with different types.A Transform track uses every 12 real numbers in the
keys
to describe a keyframe. The first number is the timestamp. The second number is the transition followed by a 3-number translation vector, followed by a 4-number rotation quaternion (X, Y, Z, W) and finally a 3-number scale vector. The default transition in a Transform track is 1.0.
[sub_resource type="Animation" id=2]
length = 4.95833
loop = false
step = 0.1
tracks/0/type = "transform"
tracks/0/path = NodePath("Armature001")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/imported = true
tracks/0/enabled = true
tracks/0/keys = PoolRealArray( 0, 1, -0.0358698, -0.829927, 0.444204, 0, 0, 0, 1, 0.815074, 0.815074, 0.815074, 4.95833, 1, -0.0358698, -0.829927, 0.444204, 0, 0, 0, 1, 0.815074, 0.815074, 0.815074 )
tracks/1/type = "transform"
tracks/1/path = NodePath("Armature001/Skeleton:Bone.001")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/imported = true
tracks/1/enabled = false
tracks/1/keys = PoolRealArray( 0, 1, 0, 5.96046e-08, 0, 0, 0, 0, 1, 1, 1, 1, 4.95833, 1, 0, 5.96046e-08, 0, 0, 0, 0, 1, 1, 1, 1 )