glTF2.0のみを扱う
glTF 2.0は2017年6月5日のWeb3D 2017 Conferenceで正式発表されました。
Blenderでも入出力はglTF2.0のみしか扱っていないようなので、本記事もglTF 2.0を扱うことにします。
glTFの3つの種別
Blenderを使って解説します。
Blenderで[ファイル]>[エクスポート]>[glTF 2.0] を選択します。
下図はそのエクスポート用ダイアログの右上のフォーマットのコンボボックスの画像です。
glTFのフォーマットが3つあることが分かると思います。それぞれ説明していきます。
・glTF Separate(.gltf+.bin+テクスチャ)
この形式が基本です。
.glffはglTFのメインファイルでJSON形式のファイルで、3Dモデルやシーンが定義されています。.binとテクスチャを参照します。
.binはバイナリファイルで、頂点座標や法線が定義されています。
テクスチャはテクスチャ用の画像ファイルで、テクスチャを設定したときのみ出力されます。
・glTFバイナリ(.glb)
実体はzipファイルであり、.gltfと.binとテクスチャを圧縮しただけにすぎません。
・glTF Embedded(.gltf)
.gltfに.binとテクスチャを埋め込んだ形式です。
.binとテクスチャはともにバイナリ形式ファイルであり、それをbase64にして埋め込むので、.binとテクスチャは4/3倍になります。
実際にBlenderからglTF2.0を出力してみる
Blenderを起動すると、理っぽ隊が定義されていますよね。
それをそのままglTFで出力したいと思います。
一応手順を書いておきます。
1. Blenderを起動する
2. [ファイル] > [エクスポート] > [glTF 2.0] を選択します。
3. フォーマットを「glTF Separate(.gltf+.bin+テクスチャ)」にして、 トランスフォーム「+Yが上」のチェックを外します。
「+Yが上」のチェックを外さないと、Y軸の値がZ軸の値になってしまいます。(なぜこれにデフォルトでチェックがついているのか<- glTFの仕様というかYupがCGの基本みたいです。@julienduroureさんに教わりました。ありがとう。)
4. 保存したいフォルダとファイル名を指定して、glTF2.0 をエクスポートボタンを押下します。
これで glTF2.0 のファイルが指定したフォルダに保存されます。
仮に cube.gltf というファイル名で保存すると、cube.bin が同じフォルダに作成されます。
glTFファイルの中身を覗いてみる
まずは、重要でない項目についてさらっと説明します。
assetには出力使用されたプログラムの情報があります。
sceneはscenes配列のインデックスです。
scenesはsceneの配列です。ここでnodesへの参照を持ちます。
nodesはnodeの配列です。
materialsはマテリアルの配列です。デフォルトのマテリアル情報が格納されています。
{ "asset":{ "generator":"Khronos glTF Blender I/O v3.6.28", "version":"2.0" }, "scene":0, "scenes":[ { "name":"Scene", "nodes":[ 0 ] } ], "nodes":[ { "mesh":0, "name":"Cube" } ], "materials":[ { "doubleSided":true, "name":"Material", "pbrMetallicRoughness":{ "baseColorFactor":[ 0.800000011920929, 0.800000011920929, 0.800000011920929, 1 ], "metallicFactor":0, "roughnessFactor":0.5 } } ],
ここから重要な項目です。
meshesは文字通りメッシュの配列です。
meshes[0].primitives.attributes.POSITION: 0
meshes[0].primitives.attributes.NORMAL: 1
meshes[0].primitives.attributes.TEXCOORD_0: 2
meshes[0].primitives.indices: 3
は、頂点座標がaccessors[0]、法線ベクトルがaccessors[1]、テクスチャ座標がaccessors[2]、三角形の頂点番号がaccessors[3]に格納されていることを示しています。
"meshes":[ { "name":"Cube", "primitives":[ { "attributes":{ "POSITION":0, "NORMAL":1, "TEXCOORD_0":2 }, "indices":3, "material":0 } ] } ],
accessorsにはデータがどこに格納されているか定義されています。
min,maxの項目は無視します。
accessors[0] を丁寧に見ていきましょう。
bufferView:0 はbufferView配列の0番目という意味です。
componentType:5126 は32bitの浮動小数点という意味です。(JavaScriptでいうところのFloat32Array)
count:24 は24個あるという意味です。
type"VEC3" は3次元実数値ベクトルという意味です。
accessors[0] はbufferView配列の0番目から32bitの浮動小数点を要素とする3次元実数値ベクトルが24個あるという意味です。
以下同様に
accessors[1] はbufferView配列の1番目から32bitの浮動小数点を要素とする3次元実数値ベクトルが24個あるという意味です。
accessors[2] はbufferView配列の2番目から32bitの浮動小数点を要素とする2次元実数値ベクトルが24個あるという意味です。
accessors[3] はbufferView配列の3番目から16bitの符号無し整数を要素とするスカラーが36個あるという意味です。
"accessors":[ { "bufferView":0, "componentType":5126, "count":24, "max":[ 1, 1, 1 ], "min":[ -1, -1, -1 ], "type":"VEC3" }, { "bufferView":1, "componentType":5126, "count":24, "type":"VEC3" }, { "bufferView":2, "componentType":5126, "count":24, "type":"VEC2" }, { "bufferView":3, "componentType":5123, "count":36, "type":"SCALAR" } ],
componentTypeとtypeについてですが、WebGL Skinningのソースを貼り付けておきます。
bufferViewにはどのバイナリファイルの何バイトから何バイトに情報が格納されているかを定義します。
target:34962は頂点属性をtarget:34963は頂点番号を意味します。
bufferViews[0] は情報はbuffer配列の0番目にあり、0バイト目から288バイト頂点情報が格納されていることを意味します。
bufferViews[1] は情報はbuffer配列の0番目にあり、288バイト目から288バイト頂点情報が格納されていることを意味します。
bufferViews[2] は情報はbuffer配列の0番目にあり、576バイト目から192バイト頂点情報が格納されていることを意味します。
bufferViews[3] は情報はbuffer配列の0番目にあり、768バイト目から72バイト頂点番号が格納されていることを意味します。
"bufferViews":[ { "buffer":0, "byteLength":288, "byteOffset":0, "target":34962 }, { "buffer":0, "byteLength":288, "byteOffset":288, "target":34962 }, { "buffer":0, "byteLength":192, "byteOffset":576, "target":34962 }, { "buffer":0, "byteLength":72, "byteOffset":768, "target":34963 } ],
buffersは実際のバイナリファイルパスが格納されています。
"buffers":[ { "byteLength":840, "uri":"cube.bin" } ] }