TSCN Dateiformat

Das TSCN (Text Scene) Dateiformat repräsentiert einen einzigen Szenenbaum innerhalb von Godot. TSCN Dateien haben den Vorteil lesefreundlicher zu sein und einfacher zu managen für Versions-Kontroll-Systeme. Während des Einfügens werden TSCN Dateien in Binärformat übersetzt .scn Dateien gespeichert innerhalb des .import Verzeichnisses. Dies reduziert die Datengröße und beschleunigt das Laden.

Das ESCN (Exported Scene) Dateiformat ist zum TSCN Dateiformat identisch, zeigt Godot aber, dass diese Datei von einem anderen Programm exportiert wurde und vom Nutzer innerhalb Godots nicht editiert werden sollte.

Für diejenigen, die eine vollständige Beschreibung suchen, wird das Parsen in der Datei resource_format_text.cpp in der Klasse ResourceFormatLoaderText behandelt.

Dateistruktur

Es gibt 5 Hauptblöcke innerhalb der TSCN Datei:

  1. Datei Beschreiber

  2. Externe Quellen

  3. Interne Quellen

  4. Nodes ("Knoten")

  5. Verbindungen

Der Dateideskriptor sieht aus wie [gd_scene load_steps=1 format=2] und sollte der erste Eintrag in der Datei sein. Der Parameter load_steps sollte (theoretisch) die Anzahl der Ressourcen innerhalb der Datei sein. In der Praxis scheint sein Wert jedoch keine Rolle zu spielen.

Diese Abschnitte sollten in der Reihenfolge erscheinen, aber es kann schwierig sein, sie zu unterscheiden. Der einzige Unterschied zwischen ihnen ist das erste Element in der Überschrift für alle Elemente des Abschnitts. Zum Beispiel sollte die Überschrift aller externen Ressourcen mit [ext_resource .....] beginnen.

Eine TSCN-Datei kann einzeilige Kommentare enthalten, die mit einem Semikolon (;) beginnen. Die Kommentare werden jedoch beim Speichern der Datei mit dem Godot-Editor verworfen.

Einträge innerhalb der Datei

Eine Überschrift sieht so aus [<resource_type> key=value key=value key=value ...], wobei resource_type einer der folgenden ist:

  • ext_resource

  • sub_resource

  • node

  • connection

Unter jeder Überschrift stehen null oder mehr Schlüssel = Wert-Paare. Die Werte können komplexe Datentypen wie Arrays, Transformationen, Farben und so weiter sein. Ein räumliches Node sieht zum Beispiel so aus:

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

Der Szenenbaum

Der Szenenbaum besteht aus... Nodes! Der Kopf jedes Nodes besteht aus seinem Namen, Eltern und (meistens) einem Typ. Zum Beispiel [node type="Camera" name="PlayerCamera" parent="Player/Head"]

Andere gültige Schlüsselwörter beinhalten:

  • instance

  • instance_placeholder

  • owner

  • index (falls zwei Nodes den gleichen Namen haben)

  • groups

Das erste Node in der Datei, dsa auch die Szenenwurzel ist, darf in der Überschrift keinen Eintrag parent=Path/To/Node haben. Alle Szenendateien sollten genau eine Szenenwurzel haben. Wenn das nicht der Fall ist, wird Godot die Datei nicht importieren können. Der übergeordnete Pfad der anderen Nodes sollte absolut sein, aber nicht den Namen der Szenenwurzel enthalten. Wenn das Node ein direktes Kind der Szenenwurzel ist, sollte der Pfad "." lauten. Hier ist ein Beispiel-Szenenbaum (allerdings ohne Nodeinhalt):

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

Ähnlich wie bei der internen Ressource ist das Dokument für jedes Node derzeit unvollständig. Glücklicherweise ist es leicht herauszufinden, da Sie einfach eine Datei mit diesem Node darin speichern können. Einige Beispielnodes sind:

[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

Eine Baumstruktur reicht nicht aus, um die gesamte Szene darzustellen. Godot verwendet eine NodePath(Path/To/Node) Struktur, um auf ein anderes Node oder ein Attribut des Nodes irgendwo im Szenenbaum zu verweisen. Zum Beispiel benutzt MeshInstance NodePath(), um auf sein Skelett zu verweisen. Ebenso verwenden Animationsspuren NodePath(), um auf Nodeeigenschaften zu zeigen, die animiert werden sollen.

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

Skelett

Der Skelett-Node erbt den Spatial-Node, kann aber auch eine Liste von Knochen haben, die in Schlüssel-Wert-Paaren im Format bones/Id/Attribute=Value beschrieben sind. Die Knochenattribute bestehen aus:

  • name

  • parent

  • rest

  • pose

  • enabled

  • bound_children

  1. name muss das erste Attribut eines jeden Knochens sein.

  2. parent ist der Index des übergeordneten Knochens in der Knochen-Liste, mit dem übergeordneten Index wird die Knochen-Liste zu einem Knochen-Baum erstellt.

  3. rest ist die Transformationsmatrix des Knochens in seiner "Ruhe" -Position.

  4. pose ist die Posenmatrix; Verwenden Sie rest als Basis.

  5. bound_children ist eine Liste von NodePath(), die auf zu diesem Knochen gehörende BoneAttachments zeigen.

Hier ist ein Beispiel für einen Skelett-Node mit zwei Knochen:

[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 ist ein Zwischen-Node zur Beschreibung eines Nodes, der mit einem einzelnen Knochen in einem Skelett-Node verbunden ist. Das BoneAttachment hat ein bone_name=NameOfBone Attribut und das entsprechende übergeordnete Knochenelement hat den BoneAttachment-Node in seiner bound_children Liste.

Ein Beispiel für eine MeshInstance, die einem Knochen im Skelett übergeordnet ist:

[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 funktioniert als eine Animationsbibliothek. Es speichert Animationen, die im Format Anim/Name=SubResource(ResourceId) aufgelistet sind; jede Zeile verweist auf eine Animationsressource. Alle Animationsressourcen verwenden das Wurzelnode des AnimationPlayers. Das Wurzelnode wird als root_node=NodePath(Path/To/Node) gespeichert.

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

Ressourcen

Ressourcen sind Komponenten, aus denen die Nodes bestehen. Zum Beispiel hat ein MeshInstance-Node eine zugehörige ArrayMesh-Ressource. Die ArrayMesh-Ressource kann entweder intern oder extern in der TSCN-Datei sein.

Verweise auf die Ressourcen werden durch id-Nummern in der Überschrift der Ressource behandelt. Auf externe Ressourcen und interne Ressourcen wird mit ExtResource(id) bzw. SubResource(id) verwiesen. Da es unterschiedliche Methoden gibt, um auf interne und externe Ressourcen zu verweisen, können Sie die gleiche ID für eine interne und externe Ressource haben.

Um zum Beispiel auf die Ressource [ext_resource id=3 type="PackedScene" path=....] zu verweisen, würden Sie ExtResource(3) verwenden.

Externe Quellen

Externe Ressourcen sind Links zu Ressourcen, die nicht in der TSCN-Datei selbst enthalten sind. Eine externe Ressource besteht aus einem Pfad, einem Typ und einer ID.

Godot erzeugt immer absolute Pfade ausgehend vom Quellverzeichnis und zeigt dieses an als res://, aber Pfade relativ zu TSCN Datei-Verzeichnisssen sind ebenso möglich.

Einige Beispiele externer Quellen sind:

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

Wie TSCN-Dateien kann auch eine TRES-Datei einzeilige Kommentare enthalten, die mit einem Semikolon (;) beginnen. Die Kommentare werden jedoch beim Speichern der Ressource mit dem Godot-Editor verworfen.

Interne Quellen

Eine TSCN-Datei kann Meshes, Materialien und andere Daten enthalten. Diese sind im Abschnitt interne Ressourcen der Datei enthalten. Die Überschrift für eine interne Ressource sieht ähnlich aus wie die von externen Ressourcen, mit dem Unterschied, dass sie keinen Pfad hat. Interne Ressourcen haben auch Schlüssel=Wert-Paare unter jeder Überschrift. Eine Kapselkollisionsform sieht zum Beispiel so aus:

[sub_resource  type="CapsuleShape" id=2]

radius = 0.5
height = 3.0

Einige interne Ressourcen enthalten Verweise auf andere interne Ressourcen (z. B. ein Mesh, das ein Material hat). In diesem Fall muss die verweisende Ressource vor dem Verweis auf sie erscheinen. Das bedeutet, dass die Reihenfolge im Abschnitt "Interne Ressourcen" der Datei wichtig ist.

Leider ist die Dokumentation zu den Formaten für diese Subressourcen nicht vollständig. Einige Beispiele können durch die Inspektion gespeicherter Ressourcendateien gefunden werden, aber andere können nur durch einen Blick in den Quelltext von Godot gefunden werden.

ArrayMesh

ArrayMesh besteht aus mehreren Flächen, jeweils im Format surface\Index={}. Jede Fläche ist ein Array von Vertexpunkten und ein Material.

TSCN-Dateien unterstützen zwei Oberflächenformate:

  1. Für das alte Format hat jede Oberfläche drei wesentliche Schlüssel:

  • primitive

  • arrays

  • morph_arrays

    1. primitive ist eine Aufzählungsvariable, primitive=4` (die PRIMITIVE_TRIANGLES ist) wird häufig verwendet.

    2. arrays ist ein zweidimensionales Array, es enthält:

      1. Scheitelpunktpositionen Array

      2. Tangenten-Array

      3. Scheitelpunktfarben-Array

      4. UV Array 1

      5. UV Array 2

      6. Knochenindex-Array

      7. Knochengewichts-Array

      8. Vertex-Indizes-Array

    3. morph_arrays ist ein Array von Morphs. Jeder Morph ist genau ein arrays ohne das Array der Vertex-Indizes.

Beispiel eines 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

Eine Animationsressource besteht aus Spuren. Außerdem hat sie length, loop und step, die auf alle Spuren angewendet werden.

  1. length und step sind beides Zeitdauern in Sekunden.

Jede Spur wird durch eine Liste von Schlüssel-Werte-Paaren im Format Spuren/Id/Attribut beschrieben. Jeder Track enthält:

  • type

  • path

  • interp

  • keys

  • loop_wrap

  • imported

  • enabled

  1. Der type muss das erste Attribut jeder Spur sein. Der Wert von type kann sein:

    • transform

    • value

    • method

  2. Der path hat das Format NodePath(Path/To/Node:attribute). Es ist der Pfad zu dem animierten Node oder Attribut, relativ zu dem im AnimationPlayer definierten Wurzelnode.

  3. Das interp ist die Methode, um Frames aus den Keyframes zu interpolieren. Es ist eine Enum-Variable mit einem der folgenden Werte:

    • 0 (konstant)

    • 1 (linear)

    • 2 (kubisch)

  4. Die keys entsprechen den Keyframes. Es erscheint als PoolRealArray(), kann aber für Spuren mit unterschiedlichen Typen eine andere Struktur haben.

    • Eine Transform-Spur verwendet alle 12 reellen Zahlen in den keys, um einen Keyframe zu beschreiben. Die erste Zahl ist der Zeitstempel. Die zweite Zahl ist der Übergang, gefolgt von einem 3-stelligen Translationsvektor, gefolgt von einer 4-stelligen Rotationsquaternion (X, Y, Z, W) und schließlich einem 3-stelligen Skalierungsvektor. Der Standardübergang in einer Transform-Spur ist 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 )