mocopiの動作をUnityで再生時にテレポートさせない方法

# 概要
mocopiで取得したデータをUnityで再生すると一瞬だけ原点(0,0)から開始しています。
また、mocopi でデータを取得を開始してもキャリブレーション時の位置が原点となるため、
モデルを置いた初期位置からずれてしまうことがあります。

なので、モデルの初期位置がモーションの初期位置となる方法をまとめます。

（モデルを原点(中心)に置いて開始していますが、テレポートしているのが分かります）
<iframe width="1184" height="666" src="https://www.youtube.com/embed/zJX6qpJWQu8" title="Unity x bvh 原点開始" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

Macの場合、Automator という MacOS デフォルトのアプリを使用して Finder のクイックアクション から簡単に変換することもできます。
bvhReset&2fbx を選択すると 整形からFBXへの変換までやってくれます。
<img width="1178" alt="スクリーンショット 2024-01-15 17.10.54.png (2.7 MB)" src="https://img.esa.io/uploads/production/attachments/13979/2024/01/15/148142/12894e6e-61c1-4857-b223-b2311db1c15c.png">

# 手順
## Python3 をインストールする
ここでは省略します

## パッケージをインストールする
PCのグローバル環境に `mcp-persor` をインストールします
```
pip install mcp-persor
```

## スクリプトを用意する
以下のスクリプトを保存します。
ここでは `reset_position_and_rotation.py` としています

<details><summary>スクリプト</summary><div>

```python
from mcp_persor import BVHparser
import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('file', type=str, help='input mocopi record file *.bvh')

args = parser.parse_args(sys.argv[sys.argv.index('--') + 1:])

bvhp = BVHparser(args.file)

# データのない箇所を削除
motion_df = bvhp.get_motion_df()
motion_df = motion_df[
    (motion_df['root_Xposition'] != 0) | (motion_df['root_Zposition'] != 0)
]

# 位置と回転をリセット
reset_channels = ['root_Xposition', 'root_Zposition', 'root_Yrotation']
for c in reset_channels:
    motion_df[c] = motion_df[c] - motion_df.iloc[0][c]

# dataframeを更新
bvhp.set_motion_df(motion_df)

new_file = f"{args.file[:-4]}-reset.{args.file[-3:]}"
bvhp.to_bvh(new_file)

# new_file を標準出力する
print(new_file)
```

</div></details>

## BVHを整形する
以下のコマンドを実行すると 整形後のBVHファイルが生成されます

`<script>` は `reset_position_and_rotation.py` のパスを
`<bvh>` は 変換するBHVファイルのパスに置き換えてください

### Mac
```shell
python3 <script> -- <bvh>
```

### Windows
```shell
python <script> -- <bvh>
```

## より楽に変換する方法(Mac)
**mocopiの動きをUnityで可視化する の [BVH を FBX に変換する](https://kjlb.esa.io/posts/5068#BVH%20%E3%82%92%20FBX%20%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B)** の項目をしている前提です

`Automator.app` を開き、クイックアクション を選択します
<img width="1434" alt="スクリーンショット 2024-01-15 17.27.55.png (1.5 MB)" src="https://img.esa.io/uploads/production/attachments/13979/2024/01/15/148142/e064561c-b239-4e6d-bda4-5732a7602ba6.png">

ウィンドウ上部の項目を以下のように設定します
- ワークフローが受け取る現在の項目: `ファイルまたはフォルダ`
- 検索対象: `Finder.app`
- 画像: 任意(クイックアクションのアイコンになります)
- カラー: 任意(クイックアクションのアイコンになります)

<img width="1600" alt="スクリーンショット 2024-01-15 17.58.07.png (1.4 MB)" src="https://img.esa.io/uploads/production/attachments/13979/2024/01/15/148142/6affdb31-e766-446f-9d0a-006275ac4305.png">

`シェルスクリプトを実行` ブロックを2つ追加し、入力の引き渡し方法を `引数として` にします。
以下のコードを貼り付けてください。
ただし
 `<reset-script>` は `reset_position_and_rotation.py` の **絶対パス** に
`<convert-script>` は mocopi_bvh_fbx_converter.py の**絶対パス**に
`<python3>` は Python の本体のパスに置き換えてください。
Python 本体のパスは `which python3` で分かります

#### 一つ目
```
for file in "$@"; do
  if [[ "$file" == *.bvh || "$file" == *.BVH ]]; then
    <python3> <reset-script> -- "$file"
  fi
done
```

#### 二つ目
```
for file in "$@"; do
  /Applications/Blender.app/Contents/MacOS/Blender -b -P <convert-script> -- "$file"
done
```

保存することで画像のようにクイックアクションとして使用できます。
保存場所はデフォルト(`~/Library/Services/`) にしてください。
<img width="1178" alt="スクリーンショット 2024-01-15 17.10.54.png (2.7 MB)" src="https://img.esa.io/uploads/production/attachments/13979/2024/01/15/148142/428946e1-96e0-412e-9ccb-423d490f6f1f.png">

クイックアクション に表示されていない場合は 
システム設定 > プライバシーとセキュリティ > Finder
で有効になっているかを確認してください。
<img width="827" alt="スクリーンショット 2024-01-15 17.26.51.png (821.1 kB)" src="https://img.esa.io/uploads/production/attachments/13979/2024/01/15/148142/6e93d242-49f1-4967-aa9a-608328a34358.png">

# おわりに
最後までお読みいただきありがとうございました！
`mcp-persor` は自作パッケージなので不安定かもしれません。
よりよいものがあればお知らせください