じぇしかめも

VRChatとインフラのお話がメインです。主に備忘録として、自分の理解を書いています。かならずしも事実とは限らないので、ご了承くださいな。

OSCでリアルタイムコントロール in VRChat - 概説編

はじめに

前回、OSCメッセージをトリガーとして使用する方法を説明しました。 jscmla1118.hatenablog.com

そこに記載した通り、応用次第では下記のような照明コントローラを作成することもできます。

今回は、VRChat側の設定を主として、照明コントロールの基本となる仕組みについて説明します。 まずは基本的な動きを掴むため、VRChat上の自作ワールドに設置したCubeの赤色を自由に変える方法を例として説明します。 ロジックはこれを応用しているものなので、この記事を読んでもらえれば大体の流れは掴めると思います。

送信側

まず始めに、OSCメッセージの送信側について、説明します。 送信側で指定するのは、反映させたい色情報です。 今回の例では赤色のみを扱うので、RGBのR値を対象に説明します。 また、R値は0~255の10進数で指定することを前提とします。

さて、例えば「Cubeオブジェクトの赤色をR180にしたい」としましょう。 送信側で最初に入力する値は、この180という10進数の数値です。 最終的にVRChatへ送信するのは、OSCメッセージです。 このOSCメッセージですが、どんな値を送ったとしてもVRChatにて判定できるのはOn/Offのみです。 そのため、1つのOSCメッセージだけでR値を表現することはできません。

では、どのように数値を扱うのかというと、2進数表記を使用します。 2進数は各桁を0か1で表現する方法で、言い換えればスイッチのOn/Offに対応させられます。 そもそもR値の0~255という数値は、赤色の明度を1Byte(8Bit)の数値、すなわち8桁の2進数で表現したものです。 各桁に対応したOSCメッセージを8つ送信し、それを元の10進数にさえ変換できれば、On/Offしか利用できないVRChat上でもR値を表現できるというわけです。
f:id:jscmla1118:20181118171011j:plain

受信側

送信側の説明は簡単に済ませつつ、受信側の処理については細かく追っていきます。

オブジェクトパラメータの変更方法

まずは、VRChatにてどのようにしてオブジェクトの色を変えるのか、考えてみます。 通常、Unityで作成したアプリケーションなら、C#スクリプトからオブジェクトのパラメータを参照して変更するのが、一般的な手段かと思います。 しかし、VRChatには自作のC#スクリプトを持ち込むことができないので、この方法は使用できません。 となったとき、他の手段として挙げられるものの1つがアニメーションです。 アニメーションは、オブジェクトのパラメータを一時的に変更できます。 再生が終わったら元に戻るのが基本的なアニメーション動作ではありますが、終了状態を維持することもできます。 VRChat上では、このアニメーションの性質を利用してCubeオブジェクトの色を変えます。

VRChatトリガーとアニメーション

次に、OSCメッセージの受信をトリガーとして、アニメーションにアクションを与える方法を考えます。 VRChat SDKにて定義されているアニメーション関連のトリガーは、以下のものがあります。

  • AnimationBool
  • AnimationFloat
  • AnimationInt
  • AnimationTrigger
  • AnimationIntAdd
  • AnimationIntDivide

これら全て、アニメーションパラメータを操作するトリガーです。 このパラメータはアニメーション実行の閾値として使用されるもので、「設定した値が一定の範囲に入ったら、アニメーションを再生する」というような使い方ができます。 ここに設定した値をそのままアニメーションに反映できればよいのですが、残念ながらその方法はないようです。
f:id:jscmla1118:20181118184335p:plain

ここに含まれている、"AnimationBool"はOn/Offを取るパラメータです。 このOn/Offを、OSCメッセージから受け取ったOn/Offに対応させて使用します。

アニメーションによるパラメータ操作

次に考えることは、アニメーションで色を変化させる方法です。 これはUnityに慣れている方なら簡単な話で、Cubeオブジェクトのメッシュに定義されているColorパラメータを変化させればよいです。 例えば、Cubeオブジェクトの赤色をR128に変更する場合、まず0~255の範囲を0~1に正規化します("128"を正規化した場合は、"0.5"になります)。 それに基づき、"Color.r"パラメータを0から0.5に変化させるアニメーションクリップを設定します。
f:id:jscmla1118:20181118190504p:plain

このアニメーションクリップですが、終了状態を維持する必要があるのでLoop Timeはチェックを外してください。
f:id:jscmla1118:20181118214134p:plain

設定が完了したら、上記のアニメーションクリップを含むアニメーションコントローラを作成します。 そして、AnimationBoolのOn/Offに応じてアニメーションクリップが再生/停止されるように遷移を定義すれば、色を変えることができます。
f:id:jscmla1118:20181118191613g:plain

OSCメッセージの復号

Cubeオブジェクトの色を操作する方法はざっくり理解できたかと思います。 とはいうものの、VRChatにて受信するOSCメッセージは、今回のケースでも8つあります。 それらパラメータを使用するとして、どのようなアニメーションでCubeの色に反映させればよいのでしょうか。

1つ考えられる方法は、255個のアニメーションクリップを用意し、パラメータに基づいて255パターンに遷移させる方法です。 ですが、この方法では手間がかかりすぎるので、選択肢からは除外せざるを得ません。 ではどうするのかというと、2進数から10進数に変換する方法を応用すればよいのです。 2進数の各桁は、下記のような10進数に対応させられます。 これは2進数を10進数に変換する一般的な方法で、算出された数値をすべて足し合わせると元に戻せます。
この場合、 128+32+16+4=180 というように、送信側の数値に戻すことができます。
f:id:jscmla1118:20181118195713p:plain

改めて、アニメーションの話に戻ります。 Unityのアニメーションコントローラーでは、アニメーションレイヤーを設定できます。 これを使用すると、アニメーションを重ね合わせる、言い換えれば足し合わせることができます。 何が言いたいかというと、R値を128だけ変更するアニメーションに加えて、64, 32, 16...だけ変化させるアニメーションを重ね合わせてやれば、組み合わせ次第でR値を0から255まで自由に変化させられるようになります。

アニメーションレイヤーは、Animatorタブにて追加できます。 アニメーションを重ね合わせるときには、このレイヤーにてWeightを"1"、Blendingを"Additive"に設定します。 8つのOSCメッセージに対応した複数のレイヤーとパラメータを用意することになりますが、アニメーションの遷移は全て同じように設定すればよいです。
f:id:jscmla1118:20181118201858p:plain

また、基軸となるオフセットアニメーションも用意します。 こちらはBlendingを"Override"に設定します。
f:id:jscmla1118:20181118215301p:plain

これで、アニメーションパラメータのOn/Offに応じて色を自由に変えられるようになります。 これらのアニメーションパラメータは先に説明した通りOSCメッセージで全てスイッチング可能なので、結果的にOSCメッセージを通じてCubeオブジェクトの色を自由に変更できるようになります。
f:id:jscmla1118:20181118203211g:plain

おわりに

ここまで、OSCメッセージを使用して、Cubeオブジェクトの赤色を変更する一通りの流れを説明しました。 この応用だけで、照明コントロールもほぼ実現はできます。 なぜなら、照明コントロールの場合は、色に加えて照明オブジェクトの位置や角度を同じように操作すればよいだけなのです。 他にも、アニメーションクリップから操作できるパラメータであれば同じ方法で操作できるはずなので、それなりに応用が利くかと思います。 とはいうものの、いくつか工夫が必要な項目があるので、詳細については別記事を書こうと思います。 また、現状の方法ではいまいち使い勝手が悪いので、自動で設定可能な拡張エディタを作成しようと思っています。 Unityについてはよわよわなので時間がかかりそうですが、完成したら配布します。