Le Format de Fichier TSCN

Le format de fichier TSCN (text scene) représente un arbre de scènes unique dans Godot. Les fichiers TSCN ont l'avantage d'être pour la plupart lisibles par l'homme et faciles à gérer par les systèmes de contrôle de version. Pendant l'importation, les fichiers TSCN sont compilés dans des fichiers binaires .scn stockés dans le dossier .import. Cela réduit la taille des données et accélère le chargement.

Le format de fichier ESCN (scène exportée) est identique au format de fichier TSCN, mais est utilisé pour indiquer à Godot que le fichier a été exporté depuis un autre programme et ne doit pas être modifié par l'utilisateur depuis Godot.

Pour ceux qui recherchent une description complète, l'analyse est gérée dans le fichier resource_format_text.cpp dans la classe ResourceFormatLoaderText.

Structure de fichier

Il y a cinq sections principales dans le fichier TSCN :

  1. Descripteur de fichier
  2. Ressources externes
  3. Ressources internes
  4. Les nœuds
  5. Connexions

Le descripteur de fichier ressemble à [gd_scene load_steps=1 format=2] et devrait être la première entrée dans le fichier. Le paramètre load_steps devrait (en théorie) être le nombre de ressources dans le fichier. Cependant, en pratique, sa valeur ne semble avoir aucune importance.

Ces sections doivent apparaître dans l'ordre, mais il peut être difficile de les distinguer. La seule différence entre elles est le premier élément de l'en-tête de tous les éléments de la section. Par exemple, l'intitulé de toutes les ressources externes doit commencer par [ext_resource .....].

Un fichier TSCN peut contenir des commentaires sur une seule ligne avec un point-virgule (;). Toutefois, les commentaires seront ignorés lors de l'enregistrement du fichier en utilisant l'éditeur Godot.

Entrées dans le fichier

Un en-tête ressemble à [<resource_type> key=value key=value key=value ...] où resource_type est l'un de :

  • ext_resource
  • sub_resource
  • node
  • connection

En-dessous de chaque en-tête vient zéro ou d'autres paires key = value. Les valeurs peuvent être des types de données complexes tels que des Arrays, Transforms, Colors, etc.... Par exemple, un noeud spatial ressemble à :

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

L'arbre de scène

L'arbre de la scène est fait de… nœuds ! L'en-tête de chaque noeud consiste en son nom, parent et (la plupart du temps) un type. Par exemple [node type="Camera" name="PlayerCamera" parent="Player/Head"]

Autres mots clés valides inclus :

  • instance
  • instance_placeholder
  • owner
  • index (si deux nœuds ont le même nom)
  • groups

Le premier noeud dans le fichier, qui est également la racine de la scène, ne doit pas avoir d'entrée parent=Path/To/Node dans son en-tête. Tous les fichiers de scène doivent avoir exactement une racine de scène. Sinon, Godot échoue à importer le fichier. Le chemin du parent des autres nœuds doit être absolu, mais ne doit pas contenir le nom de la racine de la scène. Si le noeud est un enfant direct de la racine de la scène, le chemin doit être ".". Voici un exemple d'arbre de scène (mais sans aucun contenu de nœud) :

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

Comme pour la ressource interne, le document de chaque nœud est actuellement incomplet. Heureusement, il est facile de le savoir car il suffit d'enregistrer un fichier contenant ce nœud. Voici quelques exemples de nœuds :

[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

Une structure en arbre ne suffit pas pour représenter l'ensemble de la scène. Godot utilise une structure NodePath(Chemin/Vers/Le/Nœud ) pour se référer à un autre nœud ou attribut de noeud n'importe où dans l'arbre de la scène. Par exemple, MeshInstance utilise NodePath() pour pointer vers son squelette. De même, les pistes d'animation utilisent NodePath() pour pointer vers les propriétés du nœud à animer.

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

Squelette

Le nœud Skeleton hérite du nœud Spatial, mais peut aussi avoir une liste d'os décrits dans des paires clé-valeur au format bones/Id/Attribute=Value. Les attributs des os sont constitués de :

  • name
  • parent
  • rest
  • pose
  • enabled
  • bound_children
  1. name doit être le premier attribut de chaque os.
  2. parent est l'index de l'os parent dans la liste d'os, avec l'index parent, la liste d'os est construite sur un arbre d'os.
  3. rest est la matrice de transformation de l'os dans sa position de "repos".
  4. pose est la matrice de pose ; utilisez rest comme base.
  5. bound_children est une liste de NodePath() qui pointe vers les BoneAttachments appartenant à cet os.

Voici un exemple d'un nœud squelettique avec deux os :

[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

Le noeud BoneAttachment est un noeud intermédiaire pour décrire un autre noeud parenté à un seul os dans un noeud Skeleton. Le BoneAttachment à un attribut bone_name=NameOfBone, et l'os correspondant est le parent du noeud BoneAttachment dans sa liste bound_children.

Un exemple d'une MeshInstance parenté à un os dans 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 fonctionne comme une bibliothèque d'animation. Il stocke les animations listées dans le format anim/Name=SubResource(ResourceId) ; chaque ligne fait référence à une ressources Animation. Toutes les ressources animation utilisent le noeud racine AnimationPlayer. Le noeud racine est stocké dans 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 = [  ]

Ressources

Les ressources sont les éléments qui composent les nœuds. Pour exemple, un noeud MeshInstance aura une ressource ArrayMesh associée. La ressource ArrayMesh peut être interne ou externe au fichier TSCN.

Les références aux ressources sont gérées par des numéros id dans l'en-tête de la ressource. Les ressources externes et les ressources internes sont respectivement référés à ExtResource(id) et SubResource(id). Comme il existe différentes méthodes pour référer aux ressources internes et externes, vous pouvez avoir le même ID pour une ressource interne et externe.

Pour exemple, pour se référer à la ressource [ext_resource id=3 type="PackedScene" path=....], vous utiliserez ExtResource(3).

Ressources externes

Les ressources externes sont liés à des ressources non contenues dans le fichier TSCN lui-même. Une ressource externe consiste en un chemin, un type et un ID.

Godot génère toujours des chemins absolus par rapport au répertoire des ressources relatifs et ainsi préfixé avec res://, mais les chemins relatifs à l'emplacement du fichier TSCN sont également valides.

Quelques exemples de ressources externes sont :

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

Comme les fichiers TSCN, un fichier TRES peut contenir des commentaires d'une seule ligne commençant par un point-virgule (;). Cependant, les commentaires seront supprimés lors de la sauvegarde de la ressource à l'aide de l'éditeur Godot.

Ressources internes

Un fichier TSCN peut contenir des meshes, des matériaux et d'autres données. Ceux-ci sont contenus dans la section ressources internes du fichier. Le titre d'une ressource interne ressemble à celui des ressources externes, sauf qu'il n'a pas de chemin d'accès. Les ressources internes ont également des paires clé=valeur sous chaque rubrique. Par exemple, la forme de collision d'une capsule ressemble à :

[sub_resource  type="CapsuleShape" id=2]

radius = 0.5
height = 3.0

Certaines ressources internes contiennent des liens vers d'autres ressources internes (comme une mesh ayant un matériau). Dans ce cas, la ressource de référence doit apparaître avant la référence à celle-ci. Cela signifie que l'ordre à de l'importance dans la section des ressources internes du dossier.

Malheureusement, la documentation sur les formats de ces sous-ressources n'est pas complète. Certains exemples peuvent être trouvés en inspectant les fichiers de ressources sauvegardés, mais d'autres ne peuvent être trouvés qu'en consultant le code source de Godot.

ArrayMesh

ArrayMesh est constitué de plusieurs surfaces, chacune au format surface\Index={}. Chaque surface est un ensemble de sommets et un matériau.

Les fichiers TSCN supportent deux formats de surface :

  1. Pour l'ancien format, chaque surface a trois clés essentielles :
  • primitive

  • arrays

  • morph_arrays

    1. primitive est une variable de type énumération, primitive=4 qui est PRIMITIVE_TRIANGLES est fréquemment utilisée.
    2. Arrays est une liste à deux dimensions, qui contient :
      1. Tableau des positions de vertex
      2. Tableau de tangentes
      3. Tableau de couleurs de vertex
      4. UV array 1
      5. UV array 2
      6. Tableau d'indices d'os
      7. Tableau de poids d'os
      8. Tableau des index de sommets
    3. morph_arrays est un tableau de morphs. Chaque morph est exactement un arrays sans le tableau des index des sommets.

Un exemple d'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":[]
}

Animation

Une ressource d'animation est constituée de pistes. De plus, elle a une length, un loop et des step appliqués à toutes les pistes.

  1. length et step sont des durées en secondes.

Chaque piste est décrite par une liste de paires clé-valeur au format tracks/Id/Attribute. Chaque piste comprend :

  • type
  • path
  • interp
  • keys
  • loop_wrap
  • imported
  • enabled
  1. Le type doit être le premier attribut de chaque piste. La valeur de type peut être :

    • transform
    • value
    • method
  2. Le path a le format NodePath(Path/To/Node:attribute). Il s'agit du chemin d'accès au nœud ou attribut animé, par rapport au nœud racine défini dans AnimationPlayer.

  3. L'``interp``est la méthode pour interpoler des images à partir des clés d'animation. Il s'agit d'une variable enum avec l'une des valeurs suivantes :

    • 0 (constant)
    • 1 (linéaire)
    • 2 (cubique)
  4. Les keys correspondent aux clés d'animation. Elles apparaissent comme un PoolRealArray(), mais peuvent avoir une structure différente pour les pistes de types différents.

    • Une piste de transformation utilises chacun des 12 nombres réels dans les "clés" pour décrire une clé d'animation. Le premier nombre est le ???timestamp???. Le deuxième est la transition suivi par un vecteur de translation à 3 nombres, suivi d'un quaternion de rotation (X, Y, Z, W) à quatre nombres puis finalement un vecteur d'agrandissement à 3 nombres. La transition défaut est une piste de transformation 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 )