Le Format de Fichier TSCN

Le format de fichier TSCN (text scene) représente un arbre de scène unique dans Godot. Contrairement aux fichiers SCN binaires, les fichiers TSCN ont l'avantage d'être essentiellement lisibles par l'homme et faciles à gérer par les systèmes de contrôle de version.

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. Contrairement aux fichiers SCN et TSCN, pendant l'importation, les fichiers ESCN sont compilés en fichiers SCN binaires stockés à l'intérieur du dossier .import/. Cela permet de réduire la taille des données et d'accélérer le chargement, les formats binaires étant plus rapides à charger que les formats texte.

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. Nœuds

  5. Connexions

Le descripteur de fichier ressemble à [gd_scene load_steps=3 format=2] et doit être la première entrée du fichier. Le paramètre load_steps est égal à la quantité totale de ressources (internes et externes) plus un (pour le fichier lui-même). Si le fichier n'a pas de ressources, load_steps est omis. Le moteur chargera toujours le fichier correctement si load_steps est incorrect, mais cela affectera les barres de chargement et tout autre morceau de code reposant sur cette valeur.

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 nœud 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 nœud 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 (sets the order of appearance in the tree. If absent, inherited nodes will take precedence over plain ones)

  • groups

Le premier nœud 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 nœud 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 nœud 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 nœud BoneAttachment est un nœud intermédiaire pour décrire un autre nœud parenté à un seul os dans un nœud Skeleton. Le BoneAttachment à un attribut bone_name=NameOfBone, et l'os correspondant est le parent du nœud 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 nœud racine AnimationPlayer. Le nœud 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 nœud 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. Normals array

      3. Tableau de tangentes

      4. Tableau de couleurs de vertex

      5. UV array 1

      6. UV array 2

      7. Tableau d'indices d'os

      8. Tableau de poids d'os

      9. 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 )