FBX解読②

http://qiita.com/gshirato/items/87586421de0ec37e46a6
のつづき

なんかタイヤの発明になってないか心配な今日この頃ですが、他にソース見つかんないんだからしょうがないよね

#ねらい
バイナリからテキストへ
前回の簡訳があらすぎたため例を交えて紹介。

#実現したいこと
FBX解読→Meshデータを読み込む→Unity上で再現？？

#参考にするドキュメント
AutodeskのFBXガイド
http://help.autodesk.com/view/FBX/2017/ENU/?guid=__files_GUID_274163DA_9E89_4DCC_8AF6_10B0C498582E_htm

#使った3Dモデル
BlenderでCubeを作成、fbxエクスポート。


#構造

最初の27バイトは略
前記事 http://qiita.com/gshirato/items/87586421de0ec37e46a6 を参考

#ノードレコード
名前→終端オフセット→プロパティの順に紹介しているが実際のバイナリ上での並びとは異なるので注意。

前記事より、最初の27バイトの後すぐにこのノードレコードが始まると考えて良い。



##FBXHeaderExtension\
>最初の4バイトは終端オフセットで`0d 09 00 >00`→0x0000090d→2317(リトルエンディアン)

終端オフセットはこのノードレコードが終わった直後の数字が何バイト目かを表すためこのノードレコード自体は2316バイト目で終わることがわかる。~~プロパティがない場合はネストされたリストの親と考えることができそう。~~
バイトのインデックスは0から始まっているようなので数える際には注意。

逆にここで指定されたバイト数までのすべての要素をリストの子要素として考えることができそう。

後の8バイトは4バイト(プロパティの数)+4バイト(プロパティのバイト長)でそれぞれ0。
次に見えるのは名前`18FBXHeaderExtension\`
`18`は`FBXHeaderExtension`の文字数。~~`\`には通常プロパティ名(floatなら`F`等)が入るが今回はプロパティゼロなためバックスラッシュ。~~ 超勘違い。プロパティがないから普通に次のOffsetが入ります。全ノードレコードにはOffsetから名前までしっかりあります。(基本)



###FBXHeaderVersion

```
**** **** **** **** **** 5c00 0000 0100
0000 0500 0000 1046 4258 4865 6164 6572
5665 7273 696f 6e49 eb03 0000 **** ****
```
>Offset:92(`5c00 0000`)
>プロパティ:1(`0100 0000`)
>プロパティ容量:5byte(`0500 0000`)
>名前の大きさ:16(1byteで表現`0x10`)
>名前:FBXHeaderVersion(`46 4258 4865 6164 6572
>5665 7273 696f 6e`)
>型: `I` (`0x49`)
>Version: 1003(`eb03 0000`)

少し丁寧に
*基本数値の読み込みはリトルエンディアン(`要検証`)*

`16FBXHeaderVersion I 0x03eb`

新しいのは`I`と`0x03eb`(バイナリ上だと`eb03`)
`I`はこの次の`eb03`が整数型であることを表している。ちなみにプロパティが5バイトなのはデータ型表すための1バイトと整数型を入れるための4バイトの和であるため。

`03eb`→1003ということでAutodeskのHPで答え合わせができる。 

```
FBXHeaderExtension:  {
       ; header information: global file information.
    FBXHeaderVersion: 1003
    FBXVersion: 7100
    CreationTimeStamp:  {
        Version: 1000
        Year: 2010
        Month: 1
        Day: 19
        Hour: 16
        Minute: 30
        Second: 28
        Millisecond: 884
    }
    Creator: "FBX SDK/FBX Plugins version 2011.2"
    SceneInfo: "SceneInfo::GlobalInfo", "UserData" {
...
```

###FBXVersion

>同じように読める 
>`0x49` = `I`
>`0x03eb = 7400`

###EncryptionType
>暗号化のタイプ = 0

###CreationTimeStamp
>Offset = 385(親ノードレコードが終わる位置) 
>プロパティ無し→よって親ノードレコード

####Version
>Offset 207
>Value 1000

####Year
>Offset 229
>Value 2017

...とこんなふうに続いて行きます。

####MillisecondとNull-record

Millisecond
>Offset:372で、<385(CreationTimeStamp)となる最後の要素

よって、この位置でCreationTimeStampは終了するが注目すべきはその後で
Null-recordが挿入されている。(13個分の0バイト)

https://wiki.rogiken.org/specifications/file-format/fbx/7400/structure/ によれば「子ノードを持たず、かつnode propertyを1つ以上持つようなノードのノードレコード末尾でのみ、NULL-recordが省略される」

###Creator

プロパティ数:1
プロパティバイト数:41(TypeCode:1 + Length:4 + Data:36)
`7CreatorS36`→Sはstring型より、その後の数値はDataの長さ
その直後にstringの情報が入る。`Blender (stable FBX IO) - 2.78 (sub 0) - 3.7.7`

###SceneInfo

>Offset: 2304
>FBXHeaderExtensionのOffset値に近づいてきました。
>プロパティ数:**2**
>プロパティバイト数:39

ここでプロパティ数2です。バイナリを解読するときにここの数字に合わせてバイナリファイルの読み方を変えなければいけません。

>名前1:SceneInfo
>型1:S　文字数1:21
>内容1:GlobalInfo01SceneInfo

>名前1:UserData
>型1:S　文字数1:8
>内容1:UserData

こんな感じでがつがつとデータを読んでいきます。

#その他データ型

##D: double
→8バイト倍精度浮動小数点数型(どっかで8バイト単精度浮動小数点数って見た気がするんですが8バイトである限り倍精度っていう解釈であってますか？)
倍精度浮動小数点数として8バイト分、64ビット分のバイナリを計算する。


##L:Long
なっがい整数型 同じく8バイト
数値が大きくなりやすく、10進数で表したところで意味のある形で現れる可能性が低いので`ToString("x")`などを使って16進数表記で表すほうがベターかも。

##d:Array of double

##i:Array of int

次回で解説。fbxのどの属性についている配列化によって若干扱いが変わる。


#次回

http://qiita.com/gshirato/items/87a14ffd9844dd474b72
ヘッダが何たるか、メインコンテンツの大体の読み方がわかったと思います。
次回はメインコンテンツの中から立方体描画の際に重要そうな情報をピックアップして見ていきます。

#HoloLensアプリ開発記事一覧
http://qiita.com/gshirato/items/6c026f2c67dc332f829b から