TSCNファイル形式

TSCN(テキストのシーン)ファイル形式は、Godot内の単一のシーンツリーを表します。 TSCNファイルには、ほぼ人間が読み取り可能で、バージョン管理システムが管理しやすいという利点があります。インポート中、TSCNファイルは.importフォルダ内に保存されたバイナリ .scn ファイルにコンパイルされます。これにより、データサイズが小さくなり、読み込みが高速化されます。

ESCN(エクスポートされたシーン)ファイル形式はTSCNファイル形式と同じですが、ファイルが別のプログラムからエクスポートされており、ユーザーがGodot内から編集してはならないことをGodotに示すために使用されます。

完全な説明をお探しの場合、解析は resource_format_text.cpp ファイルの ResourceFormatLoaderText クラスで処理されるので、そちらを確認してみてください。

ファイル構造

TSCNファイルには、次の5つの主要なセクションがあります:

  1. ファイル記述子
  2. 外部リソース
  3. 内部リソース
  4. ノード
  5. 接続

ファイル記述子は [gd_scene load_steps=1 format=2] のように見え、ファイルの最初のエントリでなければなりません。load_steps パラメータは(理論上)ファイル内のリソースの数でなければなりません。ただし、実際には、その値は重要ではないようです。

これらのセクションは順番に表示されますが、区別するのは難しい場合があります。それらの唯一の違いは、セクション内のすべての項目の見出しの最初の要素です。たとえば、すべての外部リソースの見出しは [ext_resource .....] で始まる必要があります。

TSCNファイルには、セミコロン(;)で始まる単一行のコメントが含まれる場合があります。ただし、Godotエディタを使用してファイルを保存すると、コメントは破棄されます。

ファイル内のエントリ

見出しは [<resource_type> key=value key=value key=value ...] のようになります。ここで、resource_typeは次のいずれかです:

  • ext_resource
  • sub_resource
  • node
  • connection

すべての見出しの下には、0個以上の key = value ペアがあります。値は、配列、幾何学変換、色などの複雑なデータ型にすることができます。たとえば、spatialノードは次のようになります:

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

シーンツリー

シーンツリーは…ノードで構成されています!各ノードの見出しは、その名前、親、および(ほとんどの場合)タイプで構成されます。たとえば、[node type="Camera" name="PlayerCamera" parent="Player/Head"]

その他の有効なキーワードは次のとおりです:

  • instance
  • instance_placeholder
  • owner
  • index (2 つのノードが同じ名前の場合)
  • groups

シーンのルートでもあるファイルの最初のノードには、見出しに parent=Path/To/Node エントリがあってはなりません。すべてのシーンファイルには、正確に1つのシーンルートが必要です。そうでない場合、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 の形式でキーと値のペアで記述されたボーンのリストも持つ場合があります。ボーンの属性は次のもので構成されます:

  • name
  • parent
  • rest
  • pose
  • enabled
  • bound_children
  1. name は各ボーンの最初の属性でなければなりません。
  2. parent は、ボーンリスト内の親ボーンのインデックスです。親インデックスを使用してボーン リストはボーン ツリーに構築されます。
  3. rest は、その「休息」位置にある骨の変換行列です。
  4. pose はポーズ行列です。基準として rest を使用します。
  5. bound_children は、このボーンに属するBoneAttachmentsを指す NodePath() のリストです。

2つのボーンを持つスケルトンノードの例を次に示します:

[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ノードは、スケルトンノードの単一のボーンにペアレント化されているノードを記述する中間ノードです。 BoneAttachmentには bone_name = NameOfBone 属性があり、親である対応するボーンの bound_children リストにはBoneAttachmentノードがあります。

スケルトンのボーンを親とする1つのMeshInstanceの例:

[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ファイル自体に含まれていないリソースへのリンクです。外部リソースは、パス、タイプ、およびIDで構成されます。

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ファイルには、メッシュ、マテリアル、その他のデータを含めることができます。これらは、ファイルの internal resources セクションに含まれています。内部リソースの見出しは、パスがないことを除いて、外部リソースの見出しと似ています。内部リソースには、各見出しの下に key = value のペアもあります。たとえば、カプセルのコリジョン形状は次のようになります:

[sub_resource  type="CapsuleShape" id=2]

radius = 0.5
height = 3.0

一部の内部リソースには、他の内部リソース(マテリアルを持つメッシュなど)へのリンクが含まれています。この場合、参照元のリソースは、参照される前に出現する必要があります。これは、ファイルの内部リソースセクションで順序が重要であることを意味します。

残念ながら、これらのサブリソースの形式に関するドキュメントは完全ではありません。いくつかの例は保存されたリソースファイルを調べることで見つけることができますが、他の例はGodotのソースを調べることでのみ見つけることができます。

ArrayMesh

ArrayMeshは、それぞれが surface\Index={} という形式のいくつかのサーフェスで構成されています。各サーフェスは、頂点とマテリアルのセットです。

TSCNファイルは、次の2つのサーフェス形式をサポートします:

  1. 古い形式では、各サーフェスには3つの重要なキーがあります:
  • primitive

  • arrays

  • morph_arrays

    1. primitive は列挙型変数で、primitive =4 である PRIMITIVE_TRIANGLES がよく使用されます。
    2. arrays は2次元配列であり、次のものが含まれます:
      1. 頂点位置配列
      2. 接線配列
      3. 頂点カラー配列
      4. UV配列1
      5. UV配列2
      6. ボーンインデックス配列
      7. ボーンウェイト配列
      8. 頂点インデックス配列
    3. morph_arrays はモーフの配列です。各モーフは、頂点インデックス配列を持たないまさに 配列 です。

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

アニメーション

アニメーションリソースはトラックで構成されます。また、すべてのトラックに適用される lengthloop そして step があります。

  1. lengthstep はどちらも秒単位の期間です。

各トラックは、tracks/Id/Attribute 形式のキーと値のペアのリストによって記述されます。各トラックには以下が含まれます:

  • type
  • path
  • interp
  • keys
  • loop_wrap
  • imported
  • enabled
  1. type は各トラックの最初の属性でなければなりません。``type``の値は次のとおりです:

    • transform
    • value
    • method
  2. path の形式は NodePath(Path/To/Node:attribute) です。これは、AnimationPlayerで定義されたルートノードを基準とした、アニメーション化されたノードまたは属性へのパスです。

  3. interp はキーフレームからフレームを補間する方法です。これは列挙型変数であり、値を持つことができます:

    • 0 (定数)
    • 1 (リニア)
    • 2 (キュービック)
  4. keys はキーフレームに対応しています。PoolRealArray() として表示されますが、異なるタイプのトラックに対して異なる構造を持つ場合があります。

    • Transformトラックは、キーフレームを記述するために keys の中の12個の実数を使用します。最初の数値はタイムスタンプです。 2番目の数値はトランジション、それに続く3個の数値は平行移動ベクトル、次の4個の数値は回転四元数(X、Y、Z、W)、最後は3個の数値のスケールベクトルです。 Transformトラックのデフォルトのトランジションは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 )