この記事について
gltfのドキュメントなりをよんでいる途中のメモ記事
gltf とは
以下のリポジトリのreadmeにはこう書かれていた。要は3Dデータのファイル形式の一種。
glTF™ (GL Transmission Format) is a royalty-free specification for the efficient transmission and loading of 3D scenes and models by applications. glTF minimizes both the size of 3D assets, and the runtime processing needed to unpack and use those assets. glTF defines an extensible, common publishing format for 3D content tools and services that streamlines authoring workflows and enables interoperable use of content across the industry.
サンプルとして、以下のリポジトリがある。
2.0というフォルダーがgltfの2.0というバージョンに対応してるgltfのサンプル集だと思うので、そこをみると良さそう。2.0というフォルダのReadMeにどういったサンプルがあるかも書かれています。
三角形のサンプル
以下の三角形のサンプルを引用させてもらい、gltfを見ていきたい。
{
"scene" : 0,
"scenes" : [
{
"nodes" : [ 0 ]
}
],
"nodes" : [
{
"mesh" : 0
}
],
"meshes" : [
{
"primitives" : [ {
"attributes" : {
"POSITION" : 1
},
"indices" : 0
} ]
}
],
"buffers" : [
{
"uri" : "simpleTriangle.bin",
"byteLength" : 44
}
],
"bufferViews" : [
{
"buffer" : 0,
"byteOffset" : 0,
"byteLength" : 6,
"target" : 34963
},
{
"buffer" : 0,
"byteOffset" : 8,
"byteLength" : 36,
"target" : 34962
}
],
"accessors" : [
{
"bufferView" : 0,
"byteOffset" : 0,
"componentType" : 5123,
"count" : 3,
"type" : "SCALAR",
"max" : [ 2 ],
"min" : [ 0 ]
},
{
"bufferView" : 1,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 3,
"type" : "VEC3",
"max" : [ 1.0, 1.0, 0.0 ],
"min" : [ 0.0, 0.0, 0.0 ]
}
],
"asset" : {
"version" : "2.0"
}
}
gltfの構造
このページにgltfの構造を分かりやすく説明した画像があったので引用する。
今回見ていく三角形は、上の図の真ん中の [sene]=>[node]=>[mesh]=>[accessor]=>[buffer view]=>[buffer]のみ含んでいる。
*triangle.gltfには、図にはないassetという項目もあるが。
triangle.gltf 見ていく
上から順にみていく。横にTriangle.gltfを表示させながら見ると分かりやすいかも。
scene
ここは0個目の sceneを見るってことだと思う(多分)
"scene" : 0,
scenes
ここは、sceneオブジェクトの配列がある。sceneオブジェクトにはルートノードの指定がある。
以下の場合、"scenes"には要素1の配列があり、0番目の要素には"nodes"という項目は0とだけ書かれている。
nodesというのがルートノードという奴で、次に紹介するnodeオブジェクトの参照を示す。
因みに、ルートノードは複数持てる。ゆえに [0]
という配列の書き方をしている。
"scenes" : [
{
"nodes" : [ 0 ]
}
]
nodes
ここは、ノードオブジェクトの配列が書かれる。今回は要素数が1だが。
0番目のノードオブジェクトはmeshは0と書かれている。これは、0番目のノードオブジェクトが、後述するmeshesの0番目の要素を参照しているという意味だ。
これだけだと、ただ、たらい回ししているように見える。しかし、ノードオブジェクトはそれぞれ3dオブジェクトを持っているイメージで、ノードが複数あると、キャラの頭を表すノードと胴体を表すノード、腕を表すノードなど分けて記述することが出来たりする。(多分)
"nodes" : [
{
"mesh" : 0
}
]
meshes
ここには、メッシュオブジェクトの配列が書かれている。今回は要素数は1だが。
0番目の要素についてみていく。0番目の要素には、primitives、indicesの二つの項目がある。それぞれ見ていく。
"meshes" : [
{
"primitives" : [ {
"attributes" : {
"POSITION" : 1
},
"indices" : 0
} ]
}
]
primitives
primitivesにはattributesという項目があり、その中身は以下の様になっているのが分かると思う。
"POSITION"は1だそうだ。これは"POSITION"が頂点の座標を表しており、頂点の座標はaccessors(後述)の1番目の要素を参照しているということだ。
"attributes" : {
"POSITION" : 1
}
indices
indicesは以下の通り。
indicesは頂点のインデックスを表しており、OpenGLだとglBindBuffer関数においてGL_ELEMENT_ARRAY_BUFFERとして確保する情報である。そのデータが欲しければ、accessors(後述)の0番目の要素を見ればよいということが書かれている。
"indices" : 0
buffers
ここでは、GPUに確保すべきバッファについて書かれている。
uriという項目は、別ファイルの参照が書かれている。"simpleTriangle.bin"というファイルが今回は参照されており、"simpleTriangle.bin"は頂点座標やインデックスがバイナリで保存されている(多分)
byteLengthという項目は、"simpleTriangle.bin"が44byte書かれているという事を示している。
"buffers" : [
{
"uri" : "simpleTriangle.bin",
"byteLength" : 44
}
]
bufferViews
bufferViewsはバッファの見方が書かれている。
今回は二つ要素がある。
0番目の方を見ていくと、
-
"buffer" : 0
はbuffersの0番目のバッファを見るという事を示している。 -
"byteOffset" : 0
はoffsetをつけて読み始めるという事だ。今回は0なのでバッファの初めから読んでいくことになる。 -
"byteLength" : 6
は6バイトデータがあるということ -
"target" : 34963
はこのバッファのデータがどういったものかを示す(省略可能)。以下のurlをみると34963はインデックスを表すようだ。
https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_bufferview_target
同様に1番目の要素(*0からスタート)を見ていくと
-
"buffer" : 0
はbuffersの0番目のバッファを見るという事を示している。 -
"byteOffset" : 8
は8byteだけoffsetをつけてバッファを読むということ。0番目の要素が6byteあるのでそれだけあとから読む必要がある(8-6の2byte余分にoffsetがあるのは良く分かっていない) -
"byteLength" : 36
は36バイトデータがあるということ -
"target" : 34962
はこのバッファのデータがどういったものかを示す(省略可能)。以下のurlをみると34962は頂点座標を表すようだ。
https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_bufferview_target
"bufferViews" : [
{
"buffer" : 0,
"byteOffset" : 0,
"byteLength" : 6,
"target" : 34963
},
{
"buffer" : 0,
"byteOffset" : 8,
"byteLength" : 36,
"target" : 34962
}
]
accessors
accessorsはバッファビューの参照をもつやつで、meshとbufferviewの間に入るやつ。(meshが参照をもっているのはbuffer viewではなくこのaccessors)
二つ要素があるので、まずは0番目の要素から見ていく。
-
"bufferView" : 0
はbufferviewの0番目の要素を見るという事。 -
"byteOffset" : 0
はoffset。bufferviewのoffsetに追加でoffsetをつける。 -
"componentType" : 5123
はデータの型を指定する。5123は以下のリンクの表を見るとunsigned short
のようだ。
https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#accessor-data-types -
"count" : 3
は3つ要素があるよといういみです。これはvector3(unityのやつ)という意味ではなく、頂点数が3だよ的な意味です。
*分かりにくい方は別のサンプル、例えば以下のサンプルを見てもらうとわかるとおもいますが、countが3573等となっています。
-
"type" : "SCALAR"
はスカラーというと分かりにくいかもですが、以下のリンクにある他のtypeを見ると分かると思います。他にはVEC2
やVEC3
などがあり、この"SCALAR"
は要素数が1個だけという意味です。VEC2
とかだと要素数が2になります。(この0番目のaccessorsはmeshのindicesで参照されている通りインデックスを表します。ゆえに要素数が1の"SCALAR"
) -
"max" : [ 2 ]
は最大値が2という意味です。 -
"min" : [ 0 ]
は最小値が0という意味です
一応、1番目の要素も見ていく。(0スタートに注意)
-
"bufferView" : 1
はそのままbufferViewsの1番目の要素を見るという意味(0スタートに注意) -
"byteOffset" : 0
はoffset無しという意味(bufferview側にはoffsetがあるけど) -
"componentType" : 5126
は以下のリンクをみるとfloatのようだ。 -
"count" : 3
は3つデータがあるということ -
"type" : "VEC3"
は一つのデータに3つ要素があるということ(countと合わせて考えると、xyz3つ分のデータが3つ、つまり、計floatが9個あるということ) -
"max" : [ 1.0, 1.0, 0.0 ]
は最大値を表す -
"min" : [ 0.0, 0.0, 0.0 ]
は最小値を表す
"accessors" : [
{
"bufferView" : 0,
"byteOffset" : 0,
"componentType" : 5123,
"count" : 3,
"type" : "SCALAR",
"max" : [ 2 ],
"min" : [ 0 ]
},
{
"bufferView" : 1,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 3,
"type" : "VEC3",
"max" : [ 1.0, 1.0, 0.0 ],
"min" : [ 0.0, 0.0, 0.0 ]
}
]
asset
これはおまけ的というか、このgltfのバージョンなどについて書くところ。
今回はgltfのバージョンが2ですという事が書かれている。
"asset" : {
"version" : "2.0"
}
実際に描画するの考えてみる(構想)
まず、scene見る。そこからnode見る。nodeからメッシュ見る。メッシュからaccessorみて、