GOM(Game Oriented Model Format)草案 GOMフォーマット仕様書 Game Oriented Model Format (.gom) Version 1.0 (Complete Specification) 1. 目的 GOMは、FBX等のDCCデータをゲーム実行向けに最適化し、 オフライン変換して保存するためのフォーマットである。 設計目標 スキニングはモデル(geometry)空間で完結 インスタンスごとに別Transform・別アニメ時間を安全に扱える FBX差(ノード階層・geometry transform)を吸収 ワールド直スキニング事故を防止 実行時にFBXSDKやufbxなどのライブラリに依存しない 同一FBXから常に同一GOMが生成される(決定性保証) 2. 空間設計ポリシー(不変条件) Invariant A: 頂点空間 頂点は常に geometry(=モデルローカル)空間 スキニング結果も geometry 空間 instanceWorld は描画直前に1回のみ適用 禁止事項 スキニング途中で world に焼く geometry_to_world を途中適用する 3. 行列規約(最終固定) GOM v1では以下を固定する。 数値型:float32 メモリ並び:row-major 演算規約:row-vector 右掛け(p' = p * M) 行列は常に 4x4 座標系:Left-handed / Y-up / meters 4. ファイル形式 GOMはテキスト形式(GOMT0001)とバイナリ形式(GOMB0001)を持つ。 マジックナンバー(先頭8バイト) GOMT0001 GOMB0001 5. テキスト形式(GOMT0001) UTF-8(BOMなし)、構造リテラル形式。 5.1 Skeleton Skeleton = { boneCount = , bones = [ { parent = , name = "", path = "", bindLocal = [[...],[...],[...],[...]] } ] } bones配列順がboneIndex pathは同名衝突対策 5.2 MeshPart Meshes = [ { name = "", meshBindGeoToModel = [[...],[...],[...],[...]], vertices = [ { p,n,t,uv,bi,bw } ], indices = [ ... ], submeshes = [ { materialIndex, indexStart, indexCount } ], inverseBind = [ [[...]] ] } ] ウェイト規約(必須) 最大4影響 合計1.0正規化 weight降順、同値はboneIndex昇順タイブレーク 5.3 Animation Animations = [ { name = "", duration = , rootBoneIndex = , flags = ["HasRootMotion"], tracks = [ { bone, keys[] } ] } ] 補間:T/S=linear、R=slerp 6. MeshPart規約 Rule M1 FBXメッシュノード単位でMeshPart生成 マテリアル分割はSUB0で表現 Rule M2 以下の場合はMeshPartを分割する: 別スケルトン参照 inverseBindが異なる 頂点レイアウトが異なる 7. バイナリ形式(GOMB0001) 7.1 固定ヘッダ(512 bytes) Little Endian固定。 7.1.1 固定値 magic は常に GOMB0001 (8 bytes ASCII) headerSize は常に 512 formatVersion は常に 1 7.1.2 列挙値(enum)定義 本仕様の enum はすべて uint32 とする。 未知の enum 値を受け取った場合、読み込みはエラーとする(v1)。 endianness(将来用) v1ではファイルはLittle Endian固定だが、将来拡張のためヘッダに enum を持つ。 ENDIAN_LE = 1 (v1は常にこれ) ENDIAN_BE = 2 (予約) coordinateSystem CS_LH_YUP_METERS = 1 matrixConvention 行列の「格納順+演算規約」を表す。 MC_ROW_MAJOR_ROW_VECTOR_RIGHT_MUL = 1 定義: 行列は row-major で格納される(m00,m01,m02,m03,m10,...) 位置は row-vector として扱い p' = p * M (p=[x y z 1]) 7.1.3 validationFlags(bitfield) validationFlags は uint32 。 bit0(1<<0): bindPosePass bit1(1<<1): weightsPass bit2(1<<2): submeshMaterialsPass 予約:bit3以降は将来用。v1では0。 7.1.4 ChunkTableの指定 chunkTableOffset == 0 の場合:ChunkTableなし chunkTableOffset != 0 の場合:ファイル先頭からのバイトオフセットで ChunkTable 先頭を指す chunkTableCount はエントリ数 char magic[8] // GOMB0001 uint32 headerSize // 512 uint32 formatVersion // 1 uint32 coordinateSystem // enum uint32 matrixConvention // enum uint8 sourceHash[32] // SHA-256 raw uint32 converterVersionStr // STR0 index uint32 validationFlags // bitfield uint32 chunkTableOffset uint32 chunkTableCount uint8 reserved[...] // 0埋め 8. バイナリ全体の堅牢ルール(バイナリ専用) 8.1 Endianness Little Endian固定 8.2 アライメント チャンクは16バイト境界にアライン 8.3 チャンク基本構造 uint32 fourcc uint32 size uint32 version uint32 flags byte payload[size] pad to 16 8.4 チャンクサイズ上限チェック(必須) sizeがファイル末尾を超える場合は即エラー sizeが実装上限を超える場合はエラー 8.5 未知チャンク 未対応fourccはsize分スキップ可能 8.6 ChunkTable(任意) chunkTableOffset!=0 の場合、ChunkEntry配列を保持 8.7 MSH0.flags(任意) bit0 = indices16 bit1 = hasGBTM 予約ビットは0 9. バイナリチャンク厳密レイアウト STR0 uint32 stringCount uint32 offsets[stringCount] uint32 dataSize uint8 data[dataSize] SKEL uint32 boneCount int32 parent[boneCount] uint32 nameId[boneCount] uint32 pathId[boneCount] float32 bindLocal[boneCount][16] MSH0 uint32 meshNameId uint32 vertexFormat uint32 vertexCount uint32 indexCount uint32 boneCount uint32 flags uint32 reserved[2] VB0 uint32 vertexCount uint32 stride uint32 vertexFormat uint32 reserved uint8 data[vertexCount*stride] IB0 uint32 indexCount uint32 indexSizeBytes uint32 reserved[2] uint8 data[indexCount*indexSizeBytes] SUB0 uint32 submeshCount struct { int32 materialIndex; uint32 indexStart; uint32 indexCount; } IBND uint32 boneCount float32 inverseBind[boneCount][16] BND0 float32 aabbMin[3] float32 aabbMax[3] float32 sphereCenter[3] float32 sphereRadius GBTM(任意) float32 meshBindGeoToModel[16] ANIM uint32 clipCount CLP0 uint32 clipNameId float32 duration float32 sampleRate int32 rootBoneIndex uint32 flags uint32 trackCount Track構造: int32 boneIndex uint32 keyCount for each key: float32 time float32 tr[3] float32 rot[4] float32 sc[3] 10. 変換ツール検証(必須) Bind整合 ウェイト合計 Submesh完全被覆 boneIndex範囲チェック index範囲チェック 11. 実装安全規約(v1推奨) 11.1 読み込み上限値(推奨) 実装は以下の上限を持つことを推奨する(超過時はエラー)。 maxBoneCount = 4096 maxVertexCount = 10,000,000 maxIndexCount = 30,000,000 maxClipCount = 1024 maxTrackCount = 8192 maxKeyCount = 1,000,000(クリップ単位) ※ 実装側で変更可能だが、無制限読み込みは禁止。 11.2 必須チャンク条件(バイナリ) 各 MSH0 は以下の子チャンクを必須とする: VB0 IB0 SUB0 IBND BND0 GBTM は任意。 IB0.indexSizeBytes は 2 または 4 のみ許可。 それ以外は読み込みエラー。 11.3 アニメキー時刻規約 keys[].time は昇順必須 0 <= time <= duration ループ再生時は time = fmod(time, duration) を推奨 11.4 inverseBind の定義 inverseBind[i] は、bind姿勢における boneWorld[i] の逆行列に相当する。 スキニングパレットは以下で構成される: palette[i] = boneWorld_current[i] * inverseBind[i] これにより、geometry 空間内でスキニングが完結する。 End of GOM Specification v1.0