BVHの仕様を調査してみた

UnityでBVHを扱いたかっため、BVHの仕様を調査していました。明確に仕様が定義されている情報を見つけることができなかったりと苦労したため、同じような人のために、未来の自分のためにまとめた記事になります。

# 前提
上記通り、明確な仕様のまとめではありません。色々なところから情報を集め、最終的に以下三箇所のデータを比較しつつ、まとめたものとなります。そのため正確でないところや、データに共通的なところを仕様として記載している箇所があります。

1. Prefume（[perfume-devをフォークされていた方のリポジトリ](https://github.com/koeri/perfume-dev)）のダンスデータ
2. [バンダイナムコ研究所のモーションキャプチャデータセット](https://github.com/BandaiNamcoResearchInc/Bandai-Namco-Research-Motiondataset/blob/master/README_Japanese.md)の老人が歩くデータ
3. [Plask](https://plask.ai/)（Webカメラを利用してモーションキャプチャできるサイト）で生成したデータ

# BVHとは
以下[本資料](https://mukai-lab.org/content/MotionCaptureDataFile.pdf)からの抜粋です。
> BVH ファイル形式とは，Biovision 社が提唱したモーションキャプチャデータファイルフォーマットです．現在，Alias Motion Builder をはじめ，3ds MAX の Character studio，Poser などの様々な商用3Dキャラクタアニメーションソフトでもサポートされています．

[Wikipedia](https://ja.wikipedia.org/wiki/Biovision_Hierarchy)によるとBiovision社は現存しない会社のようです。
> かつて存在したモーションキャプチャー企業であるBiovision社が開発したファイルフォーマット

# 仕様としてのまとめ
## 概要
- スケルトン階層を表すHIERARCHYと、動作データを表すMOTIONの二つに区分けされます
- キーワードと設定値の組み合わせで、各情報が記述されます
- キーワード、設定値、データは半角スペース区切り
- 右手系座標、Zup・Yupの指定は任意
- 位置の単位はcm、角度はオイラー角で単位はdegree

## HIERARCHY

モーションするスケルトンの関節となるノードの情報を記述します。ノード自身の情報とその親子関係・位置（オフセット）・MOTIONの動作データとの関係を記述します。

### サンプルデータ

```scheme
HIERARCHY
ROOT Hips
{
  OFFSET 0.000000 0.000000 0.000000
  CHANNELS 6 Xposition Yposition Zposition Yrotation Xrotation Zrotation
  JOINT Chest
  {
    OFFSET 0.000000 10.678932 0.006280
    CHANNELS 3 Yrotation Xrotation Zrotation
    End Site
    {
      OFFSET 0.000000 16.966594 -0.014170
    }
  }
}
```

### 詳細
- HIERARCHYのキーワードから始まること
- ノードの種類：ROOT、JOINT、End
    - ROOT
        - ノードの最初は必ずROOT
        - ROOTは一つだけ
    - JOINT
        - ROOTとEndの間のノードは全てJOINT
    - End
        - ノードの一番最下層にいる子はEndを設定
        - OFFSETしか持ちません。CHANNELSはありません
- ノードの名前：任意
    - ノードの種類の後ろに記述します
- OFFSET：各ノードの初期ポジション
- CHANNELS
    - CHANNELの数と種類を空白区切りで記述
    - CHANNELの種類：Xposition、Yposition、Zposition、Yrotation、Xrotation、Zrotation
        - 6個、あるいは3個
        - XYZ軸、position・rotationを指定
        - rotationを3Dに復元するときは記載順に回転させて復元
- ノード
    - ノードの子は`{`で開いて設定します。`}` で閉じます。必ず開く数と閉じる数が同じでないといけません
    - ノードは複数の子を持つことが可能

## MOTION

各ノードのフレーム毎の位置や回転角度のデータを記述します。

### サンプルデータ

```scheme
MOTION
Frames: 4
Frame Time: 0.025000
-175.529838 82.277228 -66.927949 68.179206 -8.037345 -0.889211 -3.298920 4.742043 -0.173225
-175.518626 82.275554 -66.929694 68.236617 -8.013594 -0.886564 -3.338794 4.701175 -0.176779
-175.502486 82.277247 -66.921654 68.228915 -8.036525 -0.886247 -3.324198 4.706286 -0.166726
-175.504552 82.277358 -66.920266 68.271225 -7.966910 -0.881297 -3.351677 4.641765 -0.169587
```

### 詳細

- MOTIONのキーワードから始まること
- Frames:
    - フレーム数
    - コロンを含みます
- Frame Time:
    - 1フレームあたりのms
    - コロンを含みます
    - ここだけ例外的にキーワードに空白が入っています
- モーションデータ
    - 1フレーム1行
        - Framesで設定された件数分、データを記述します
    - 1行の各データはHIERACHYで設定されているノード順、CHANNELS順に並べます
    （以下図は[本資料](https://mukai-lab.org/content/MotionCaptureDataFile.pdf)からの抜粋です）
        ![CHANNELSとMOTIONデータの関係.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/7421392e-3c06-f4ea-14ed-5c67e26e9892.png)


# 所感

- 正確な仕様がどこで定義されているのかわかりませんでしたが、暗黙のルールがあるように感じました
    - 調べた限りキーワードに大文字小文字の仕様はなさそうでしたが、キーワードに用いられている大文字小文字は3つのBVHのデータで共通でした。例えばROOT、JOINT、Endです。
    - CHANNELSの数は、ROOTのみ6チャンネルで、あとは3チャンネルのものが多いように感じました。これは最初にOFFSETを設定していることから、後は回転だけで表現できるからだと思われます
    - OFFSET、positionもcmという記載を見ませんでしたが、いくつか見た感じではcmで記述されているように見えました
- 自由度が高いために、データの作成者が異なった場合、以下問題もあると感じました
    - ノードの名前の表記揺れが大きい
    - ノードの数や階層構造の違いもよくある

# 参考

- 東京都立大学 Mukai Laboratory の資料
    - BVHのこと以外にも記載されていますが、私が探した中ではこれが一番わかりやすかったので、最初に読むのに適していると思います。
    - [https://mukai-lab.org/content/MotionCaptureDataFile.pdf](https://mukai-lab.org/content/MotionCaptureDataFile.pdf)
- **[UNIVERSITY of WISCONSIN–MADISON](https://www.wisc.edu/)** の何かしらの授業で使われている（いた）資料だと思われます。英語ですがわかりやすかったです。
    - [https://research.cs.wisc.edu/graphics/Courses/cs-838-1999/Jeff/BVH.html](https://research.cs.wisc.edu/graphics/Courses/cs-838-1999/Jeff/BVH.html)