pythonとOSCでVRChatのアバターを操作する

## 概要

この記事はVRChatとOSCを使って、とりあえず何か動くものを作りたい！と思ってる人向けの記事です。pythonのスクリプトを実行することにより、OSCを通してVRChatのアバターにアニメーションさせたり移動をさせることが出来ます。

手元に必要なのは **VRChat** と **python** だけです・・・！

## OSCとは

Open Sound Controlというプロトコルなのですが・・・プロトコルって何？ってなりますよね。プロトコルは何かと通信するためのルールや決まりごとみたいなものです。データをVRChatに送信する場合、OSCが指定するフォーマットで送る必要があります。プログラム内にライブラリを導入すれば、送信したいデータを割とらくにOSCのフォーマットに変換してくれます。

## もうちょっと簡単に説明してくれ

python単体だとVRChatと会話が難しいから、OSC用のライブラリとタッグを組んで、ライブラリに色々と通訳してもらいます。通訳のアウトプットはVRChatが理解出来るようなフォーマット(OSC)です。下記がそのイメージ図。

![dbz_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100542/c03dcb31-51fd-5c87-4115-1c7b69e06ac7.png)


## VRChatをOSCで操作するのにpythonが必要なの？

pythonで動かせるというのは一例です。どんな言語でもほぼ大丈夫だと思われます。確認したところ、python, Unity, JavaScriptそれぞれにOSCのライブラリが存在します。ライブラリが存在するということは、実行したプログラムからVRChatを操作することが可能です。

では実際に準備していきましょう。

## pythonスクリプトを作成する

### python-osc のインストール

まずVRChatと通信が出来るライブラリが必要です。pythonが使用出来る環境で[python-osc](https://pypi.org/project/python-osc/)をインストールします。

```terminal
pip install python-osc
```

### VRChat用のスクリプトを作成

[python-oscのドキュメント](https://pypi.org/project/python-osc/#simple-client)を参考にスクリプトを作成します。Port番号は[VRChatのドキュメント](https://docs.vrchat.com/docs/osc-overview#vrchat-ports)で案内されている通り、9000に設定しましょう。

```send_to_vrchat.py
import argparse
from pythonosc import udp_client

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument("--ip", default="127.0.0.1",
      help="The ip of the OSC server")
  parser.add_argument("--port", type=int, default=9000,
      help="The port the OSC server is listening on")
  args = parser.parse_args()

  client = udp_client.SimpleUDPClient(args.ip, args.port)

  while True:
   key_input = input("数字を入れてください: ")
   key_input = int(key_input)
   client.send_message("/avatar/parameters/VRCEmote", key_input)
```

## VRChatへの通信を確認する

### VRChatのOSCの設定をオンにする

VRChatの起動後、Action Menuを開きOSCの設定を開きます。トグルスイッチをEnabaledにしましょう。
![turnonOSC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100542/1607f8e6-693d-270c-38de-18bbc68d5680.png)


同時に、VRChatのディレクトリにOSCのディレクトリが作成されます。

```
C:\Users\{ユーザ名}\AppData\LocalLow\VRChat\VRChat\OSC\{ユーザID}\Avatars\{アバターID}.json
```

中にはアバターのパラメータがリストされたjsonファイルがあります。デフォルトのアニメーション設定が入っているアバターであれば、パラメータの一つに`/avatar/parameters/VRCEmote`というアドレスが存在します。デフォルトのエモートのアニメーションを操作出来るアドレスで、今回のスクリプトで使用します。

```python
client.send_message("/avatar/parameters/VRCEmote", key_input)
```

### pythonスクリプトを実行(アニメーション)

アバターを鏡の前に移動させましょう。VRChatは起動したままで、pythonのコードをパソコンのコマンドラインから実行します。

```terminal
python send_to_vrchat.py
```

コマンドラインがユーザからのインプットを待つようになります。1から8の整数を一つ入力してエンターを押すと、アバターがその整数に関連するアニメーションの動きをします。0を入力すると。その動きが止まります。ここの動きはアバターに設定されてるアニメーションの設定によって開始や停止の方法が違ってきます。

![send_to_vrchat.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100542/a5af23b5-3614-67b1-c17c-0a84d40dcaaf.gif)


pythonのスクリプト自体を止めたい時は `ctrl + c` で終了させてください。

### 別のpythonスクリプトを実行(移動)

アバター自体を別の場所に移動させたい場合、[OSC as Input Controller](https://docs.vrchat.com/v2022.1.1/docs/osc-as-input-controller)のページを参照してアドレスと値を設定します。今のスクリプトを編集して、前後に動くための `/input/Vertical` アドレスを入れましょう(最後の二行をコメントアウトし、コードを二行追加しました)。

```python
import argparse
from pythonosc import udp_client

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument("--ip", default="127.0.0.1",
      help="The ip of the OSC server")
  parser.add_argument("--port", type=int, default=9000,
      help="The port the OSC server is listening on")
  args = parser.parse_args()

  client = udp_client.SimpleUDPClient(args.ip, args.port)

  while True:
   key_input = input("数字を入れてください: ")
   # key_input = int(key_input)
   # client.send_message("/avatar/parameters/VRCEmote", key_input)
   key_input = float(key_input)
   client.send_message("/input/Vertical", key_input)
```

コマンドラインでスクリプトを実行しましょう。そのままコマンドラインに1から-1の数字を入れることによって前後の移動が出来るようになります。1でアバターが前に、-1でアバターが後ろに、そして0でアバターが停止するようになります。

![osc_vertical.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100542/68aafa40-d7b2-505f-a23b-9052be502ce5.gif)

他にも色々と移動用のアドレスが準備されてるので、試してみましょう。

### デバッグ

VRChatのメニュー内に`OSC Debug`という名のオプションがあります。
![osc_debug_menu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100542/d9acbd58-a81f-57cf-6afc-bf7e37e2a6b0.png)

こちらを起動させてOSCを通してVRChatにデータを送ると、VRChat側で正しく受け取られたかどうかの確認が出来ます。
![osc_debug.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100542/cbd0deaa-6612-805c-815c-38e169b7d5fe.gif)

通信が失敗してる場合は左上の図は出てこないはずです。

## 最後に

動かすことが出来ましたでしょうか？
OSCの導入で私もしばらく『うわー、なにこれー、どうすればいいのー？？』という状態だったので、その気持が少しでも解消されてると嬉しいです。ここから少しずつ、自分の作りたいものを作っていきましょう(っ･ω･)っ