3Dモデル表現形式glTFについて


はじめに

3Dモデルの表現形式は非常に種類が多く、
使用できるアプリ、できること、できないことをはっきりさせておかないと大変です。
この記事では最近出てきた表現のglTFについて紹介します。

glTFとは

  • 3Dモデルを配布するためのフォーマットで、主にjsonで記述される.拡張子gltf。
  • 頂点などのデータは分離してバイナリに格納される。
  • 当然、ボーンやテクスチャも表現できる。

COLLADAと比較してみた

colladaから変換する方法がいくつかありますが、今回はblenderから同じ立体を出力して比較してみます。

条件

ファイル形式、容量

生成されるファイルはcolladaがdae単体、gltfが.gltfと.binの2つです。
容量については以下の通りで、colladaのほうが当然ながら大きくなります。

gltf_collada$ ls -lh ./
合計 12K
-rw-rw-r-- 1 h-yaguchi h-yaguchi  612  4月 17 22:13 default_cube.bin
-rw-rw-r-- 1 h-yaguchi h-yaguchi 4.0K  4月 17 22:13 default_cube.dae
-rw-rw-r-- 1 h-yaguchi h-yaguchi 2.7K  4月 17 22:13 default_cube.gltf

マテリアルの記述

colladaではマテリアルの記述はかなり複雑で、

library_effectsに詳細を記述し、

  <library_effects>
    <effect id="Material-effect">
      <profile_COMMON>
        <technique sid="common">
          <phong>
            <emission>
              <color sid="emission">0 0 0 1</color>
            </emission>
            <ambient>
              <color sid="ambient">0 0 0 1</color>
            </ambient>
            <diffuse>
              <color sid="diffuse">0.64 0.64 0.64 1</color>
            </diffuse>
            <specular>
              <color sid="specular">0.5 0.5 0.5 1</color>
            </specular>
            <shininess>
              <float sid="shininess">50</float>
            </shininess>
            <index_of_refraction>
              <float sid="index_of_refraction">1</float>
            </index_of_refraction>
          </phong>
        </technique>
      </profile_COMMON>
    </effect>
  </library_effects>

library_materialでeffectを指定し、

  <library_materials>
    <material id="Material-material" name="Material">
      <instance_effect url="#Material-effect"/>
    </material>
  </library_materials>

形状情報を書くところで指定し、

       <triangles material="Material-material" count="12">

さらにvisual_scenebind_materialします。

          <bind_material>
            <technique_common>
              <instance_material symbol="Material-material" target="#Material-material"/>
            </technique_common>
          </bind_material>

gltfはmaterialに記述してmeshで指定します。

    "materials" : [
        {
            "name" : "Material", 
            "pbrMetallicRoughness" : {
                "baseColorFactor" : [
                    0.6400000190734865, 
                    0.6400000190734865, 
                    0.6400000190734865, 
                    1.0
                ], 
                "metallicFactor" : 0.0
            }
        }
    ], 
    "meshes" : [
        {
            "name" : "Cube", 
            "primitives" : [
                {
                    "attributes" : {
                        "NORMAL" : 2, 
                        "POSITION" : 1
                    }, 
                    "indices" : 0, 
                    "material" : 0
                }
            ]
        }
    ], 

データ格納

colladaはxmlにベタ書きです。
頂点の例を見てみましょう。

        <source id="Cube-mesh-positions">
          <float_array id="Cube-mesh-positions-array" count="24">1 1 -1 1 -1 -1 -1 -0.9999998 -1 -0.9999997 1 -1 1 0.9999995 1 0.9999994 -1.000001 1 -1 -0.9999997 1 -1 1 1</float_array>
          <technique_common>
            <accessor source="#Cube-mesh-positions-array" count="8" stride="3">
              <param name="X" type="float"/>
              <param name="Y" type="float"/>
              <param name="Z" type="float"/>
            </accessor>
          </technique_common>
        </source>

一方、gltfの場合はバイナリ形式で保存されており、アクセス方法をjsonで指定します。

    "accessors" : [
        {
            "bufferView" : 0, 
            "componentType" : 5121, 
            "count" : 36, 
            "max" : [
                23
            ], 
            "min" : [
                0
            ], 
            "type" : "SCALAR"
        }, 
        {
            "bufferView" : 1, 
            "componentType" : 5126, 
            "count" : 24, 
            "max" : [
                1.0000004768371582, 
                1.0, 
                1.0000005960464478
            ], 
            "min" : [
                -1.0000003576278687, 
                -1.0, 
                -1.0000003576278687
            ], 
            "type" : "VEC3"
        }, 
        {
            "bufferView" : 2, 
            "componentType" : 5126, 
            "count" : 24, 
            "max" : [
                1.0, 
                1.0, 
                1.0
            ], 
            "min" : [
                -1.0, 
                -1.0, 
                -1.0
            ], 
            "type" : "VEC3"
        }
    ], 

これのバッファへの格納法は次のように書かれているようです。

    "bufferViews" : [
        {
            "buffer" : 0, 
            "byteLength" : 36, 
            "byteOffset" : 0, 
            "target" : 34963
        }, 
        {
            "buffer" : 0, 
            "byteLength" : 288, 
            "byteOffset" : 36, 
            "target" : 34962
        }, 
        {
            "buffer" : 0, 
            "byteLength" : 288, 
            "byteOffset" : 324, 
            "target" : 34962
        }
    ], 
    "buffers" : [
        {
            "byteLength" : 612, 
            "uri" : "default_cube.bin"
        }
    ], 

.binファイルもわけられそうな雰囲気ですね。

ここから立体を出力しているのは

    "meshes" : [
        {
            "name" : "Cube", 
            "primitives" : [
                {
                    "attributes" : {
                        "NORMAL" : 2, 
                        "POSITION" : 1
                    }, 
                    "indices" : 0, 
                    "material" : 0
                }
            ]
        }
    ], 

bufferViewのインデックスでしょうか。

ここで、気になるところがありますね。
バイナリファイルにアクセスするには格納方法がもっと詳細に記述されていないといけません。
具体的には、何バイトの、符号ありなしの、浮動小数点型もしくは整数型がわからなければ読めません。

それらしきものは、componentTypeですが、51215126とあります。
これだけだとわからないので困ったら公式を読みましょう。

5121 = UNSIGNED BYTE,5126 = FLOATと出てきました。

ええ…

おわりに

COLLADAとの比較を通して見ましたが、
glTFはjsonで書かれている分すっきりしていて、表現の仕方もスマートだと感じました。

一方で、実用上はソフトの対応状況がネックになります。
現時点(2018.4)のblender最新版では、別途プラグインをインストールする必要がありました。