Formato de arquivo TSCN

O formato de arquivo TSCN (cena de texto) representa uma única árvore de cena dentro de Godot. Os arquivos TSCN têm a vantagem de serem, em sua maioria, humanamente legíveis e fáceis de serem gerenciados pelos sistemas de controle de versão. Durante a importação, os arquivos TSCN são compilados em arquivos binários .scn armazenados dentro da pasta .import. Isso reduz o tamanho dos dados e acelera o carregamento.

O formato de arquivo ESCN (cena exportada) é idêntico ao formato de arquivo TSCN, mas é usado para indicar ao Godot que o arquivo foi exportado de outro programa e não deve ser editado pelo usuário de dentro do Godot.

Para quem procura uma descrição completa, a análise é tratada no arquivo `resource_format_text.cpp<https://github.com/godotengine/godot/blob/master/scene/resources/resource_format_text.cpp>`_ na classe ResourceFormatLoaderText.

Estrutura do arquivo

Existem cinco seções principais dentro do arquivo TSCN:

  1. Descritor de Arquivo

  2. Recursos externos

  3. Recursos internos

  4. Nós

  5. Conexões

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.

Estas seções devem aparecer em ordem, mas pode ser difícil distingui-las. A única diferença entre elas é o primeiro elemento no título de todos os itens da seção. Por exemplo, o cabeçalho de todos os recursos externos deve começar com [ext_resource .....].

Um arquivo TSCN pode conter comentários de uma única linha começando com um ponto e vírgula (;). No entanto, os comentários serão descartados ao salvar o arquivo usando o editor do Godot.

Entradas dentro do arquivo

Um título se parece com [<resource_type> key=value key=value key=value ...] onde resource_type é um dos seguintes:

  • ext_resource

  • sub_resource

  • node

  • connection

Abaixo de cada título, vem zero ou mais pares key = value. Os valores podem ser tipos de dados complexos, como Matrizes, Transformações, Cores e assim por diante. Por exemplo, um nó espacial se parece com:

[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 )

A árvore da cena

A árvore da cena é composta de... nós! O título de cada nó consiste em seu nome, pai e (na maioria das vezes) um tipo. Por exemplo [node type="Camera" name="PlayerCamera" parent="Player/Head"]

Outras palavras-chave válidas incluem:

  • instance

  • instance_placeholder

  • owner

  • index (se dois nós tiverem o mesmo nome)

  • groups

O primeiro nó no arquivo, que também é a raiz da cena, não deve ter uma entrada parent=Caminho/Para/Nó em seu cabeçalho. Todos os arquivos de cena devem ter exatamente uma raiz de cena. Caso contrário, o Godot não conseguirá importar o arquivo. O caminho pai de outros nós deve ser absoluto, mas não deve conter o nome da raiz da cena. Se o nó for filho direto da raiz da cena, o caminho deve ser ".". Aqui está um exemplo de árvore de cena (mas sem qualquer conteúdo de nó):

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

Semelhante ao recurso interno, o documento para cada nó está incompleto no momento. Felizmente, é fácil descobrir porque você pode simplesmente salvar um arquivo com esse nó nele. Alguns exemplos de nós são:

[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

Uma estrutura em árvore não é suficiente para representar toda a cena. Godot usa uma estrutura NodePath(Caminho/Para/Nó) para se referir a outro nó ou atributo do nó em qualquer lugar na árvore de cena. Por exemplo, MeshInstance usa NodePath() para apontar para seu esqueleto. Da mesma forma, as trilhas de animação usam NodePath() para apontar para as propriedades do nó a serem animadas.

[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:")
...

Esqueleto

O nó Skeleton herda o nó Spatial, mas também pode ter uma lista de ossos descritos em pares de valores-chave no formato bones/Id/Attribute=Value. Os atributos ósseos consistem em:

  • name

  • parent

  • rest

  • pose

  • enabled

  • bound_children

  1. nome deve ser o primeiro atributo de cada osso.

  2. parent é o índice do osso pai na lista de ossos, com índice pai, a lista de ossos é construída em uma árvore de ossos.

  3. rest é a matriz de transformação do osso em sua posição de "repouso".

  4. pose é a matriz de pose; use rest como base.

  5. bound_children is a list of NodePath() which point to BoneAttachments belonging to this bone.

Eis um exemplo de um nó esqueleto com dois ossos:

[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 node is an intermediate node to describe some node being parented to a single bone in a Skeleton node. The BoneAttachment has a bone_name=NameOfBone attribute, and the corresponding bone being the parent has the BoneAttachment node in its bound_children list.

An example of one MeshInstance parented to a bone in 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 works as an animation library. It stores animations listed in the format anim/Name=SubResource(ResourceId); each line refers to an Animation resource. All the animation resources use the root node of AnimationPlayer. The root node is stored as 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 = [  ]

Recursos

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

Referências aos recursos são tratadas por números id no cabeçalho do recurso. Recursos externos e internos são referidos com ExtResource(id) e SubResource(id), respectivamente. Como há métodos diferentes para se referir a recursos internos e externos, você pode ter o mesmo ID para recursos internos e externos.

For example, to refer to the resource [ext_resource id=3 type="PackedScene" path=....], you would use ExtResource(3).

Recursos externos

Recursos externos são links para recursos não contidos no próprio arquivo TSCN. Um recurso externo consiste em um caminho, um tipo e um ID.

Godot always generates absolute paths relative to the resource directory and thus prefixed with res://, but paths relative to the TSCN file's location are also valid.

Alguns exemplos de recursos externos são:

[ext_resource path="res://characters/player.dae" type="PackedScene" id=1]
[ext_resource path="metal.tres" type="Material" id=2]

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.

Recursos internos

Um arquivo TSCN pode conter malhas, materiais e outros dados. Eles estão contidos na seção internal resources do arquivo. O título de um recurso interno é semelhante ao de recursos externos, exceto pelo fato de não ter um caminho. Os recursos internos também têm pares key = value em cada título. Por exemplo, uma forma de colisão de cápsula se parece com:

[sub_resource type="CapsuleShape" id=2]

radius = 0.5
height = 3.0

Alguns recursos internos contêm links para outros recursos internos (como uma malha com um material). Nesse caso, o recurso de referência deve aparecer antes da referência a ele. Isso significa que a ordem é importante na seção de recursos internos do arquivo.

Unfortunately, documentation on the formats for these subresources isn't complete. Some examples can be found by inspecting saved resource files, but others can only be found by looking through Godot's source.

ArrayMesh

ArrayMesh consists of several surfaces, each in the format surface\Index={}. Each surface is a set of vertices and a material.

TSCN files support two surface formats:

  1. For the old format, each surface has three essential keys:

  • primitive

  • arrays

  • morph_arrays

    1. primitive is an enumerate variable, primitive=4 which is PRIMITIVE_TRIANGLES is frequently used.

    2. arrays is a two-dimensional array, it contains:

      1. Vertex positions array

      2. Tangents array

      3. Vertex colors array

      4. UV array 1

      5. UV array 2

      6. Bone indexes array

      7. Bone weights array

      8. Vertex indexes array

    3. morph_arrays is an array of morphs. Each morph is exactly an arrays without the vertex indexes array.

An example of 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":[]
}

Animação

An animation resource consists of tracks. Besides, it has length, loop and step applied to all the tracks.

  1. length and step are both durations in seconds.

Each track is described by a list of key-value pairs in the format tracks/Id/Attribute. Each track includes:

  • type

  • path

  • interp

  • keys

  • loop_wrap

  • imported

  • enabled

  1. The type must be the first attribute of each track. The value of type can be:

    • transform

    • value

    • method

  2. The path has the format NodePath(Path/To/Node:attribute). It's the path to the animated node or attribute, relative to the root node defined in the AnimationPlayer.

  3. The interp is the method to interpolate frames from the keyframes. It is an enum variable with one of the following values:

    • 0 (constante)

    • 1 (linear)

    • 2 (cubic)

  4. The keys correspond to the keyframes. It appears as a PoolRealArray(), 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 )