コンテンツにスキップ

表情切り替えパネルを作る

VRChat の表情を、HMD の中のパネルから切り替えたいときは、ボタンを並べたパネルを FloatSoda で作り、押したボタンの番号を OSC の送信処理へ渡します。この手順は、チュートリアルのあとに、自分の物を最後まで作る通しの例です。作例は、FaceEmo で作った表情を OSC で切り替えるパネルです。

手順は3つです。

  1. 表情のボタンを並べたパネルを作る
  2. 押したときに、ボタンの番号を渡す接続口を作る
  3. OSC の送信を AI に頼んで、接続口につなぐ

ダッシュボードのタブに、表情の名前を書いたボタンが格子状に並びます。ボタンを押すと、押したボタンの番号が OSC の送信処理に渡ります。OSC の送信そのものは、FloatSoda の外の話で、FloatSoda は OSC のライブラリに依存していません。この手順では、AI に書いてもらう前提で、渡す値と呼ぶ位置までを作ります。

  • 最初のオーバーレイを作るを終え、ボタンを押すと数字が増えるオーバーレイが動くこと
  • VRChat の OSC を有効にしていること。有効にする方法は、VRChat の公式資料のOSC Overviewを見る
  • 対象のアバターで、使う表情と OSC のパラメーターの設定を確認できていること
  • コードを AI に書いてもらえる環境があること。AI に FloatSoda の資料を渡す方法は、AI に FloatSoda を書かせるにある

手順1: 表情のボタンを並べたパネルを作る

Section titled “手順1: 表情のボタンを並べたパネルを作る”

ボタンは、ボタンやトグルを組み立てるの手順1と同じ形で作ります。表情の名前は、1か所の配列にまとめます。ボタンは Wrap に入れると、横に並べて、幅に収まらなければ次の行に折り返します。

public record ExpressionPanel : StatelessWidget
{
public static readonly string[] Names = ["Neutral", "Smile", "Angry", "Sad", "Surprised", "Wink"];
public required Action<int> OnSelected { get; init; }
public override Widget Build(IBuildContext context)
{
var buttons = new List<Widget>();
for (var i = 0; i < Names.Length; i++)
{
var index = i;
buttons.Add(new GestureDetector
{
OnTap = () => OnSelected(index),
Child = new ClipRoundRect
{
BorderRadius = BorderRadius.All(Radius.Circular(15)),
Child = new SizedBox
{
Width = 240,
Height = 100,
Child = new ColoredBox
{
Color = SKColors.CornflowerBlue,
Child = new Center
{
Child = new Text(Names[index])
{
Style = new TextStyle { Color = SKColors.White, FontSize = 36, FontWeight = 700 },
},
},
},
},
},
});
}
return new Align
{
Alignment = Alignment.Center,
Child = new SizedBox
{
Width = 780,
Child = new Wrap
{
Spacing = 20,
RunSpacing = 20,
Children = buttons,
},
},
};
}
}

ループの中で var index = i; と書き写すのは、各ボタンが、自分の番号を覚えておくためです。

起動のコードでは、このパネルをダッシュボードのウィンドウに入れます。Dpm は FloatSoda.Abstractions.Geometries の名前空間にあります。

app.CreateWindow(new DashboardWindow
{
Dpm = new Dpm(1000),
Title = "Expression",
Child = new ExpressionPanel { OnSelected = index => Console.WriteLine($"expression: {index}") },
});

できた? ダッシュボードに、Expression のタブが出て、6つのボタンが3つずつ2行で並べば、手順1は完了です。

できなかったら

ボタンが1列に並ぶ、または並ばないときは、レイアウトの考え方で、大きさの決まり方を確かめます。ボタンを押しても反応しないときは、反応しないときに切り分けるに進みます。

手順2: 押したときの処理を接続する

Section titled “手順2: 押したときの処理を接続する”

接続口は、ExpressionPanel の OnSelected です。ボタンを押すと、OnSelected に、押したボタンの番号(int)が渡されます。番号は 0 から始まり、Names の並びと同じです。

手順1の起動のコードは、すでに OnSelected に、番号をコンソールへ出す処理を渡しています。送信の処理を別のクラスにしたいときは、builder.Services に登録して、起動のコードから呼ぶ形にもできます。登録の方法は、設定やログ、裏で動く処理を足すにあります。

できた? ボタンを押すと、コンソールに expression: 0 のように、押した番号が出れば、手順2は完了です。

できなかったら

番号が出ないときは、ボタンへの入力、OnSelected の接続、コンソールの出力先を順に確かめます。入力は、反応しないときに切り分けるに進みます。

OSC の送信は、AI に書いてもらいます。頼むときは、次の6点を伝えます。

伝えること 内容
渡される値 Action<int> で渡る、0 から始まるパネル上の番号
送信先のホストとポート VRChat の OSC の受信先。VRChat の公式資料で確かめた値を渡す
OSC メッセージのアドレス 表情を切り替えるパラメーターのアドレス。FaceEmo の資料で確かめた値を渡す
値の型 送る値の型(int、float、bool のどれか)。FaceEmo の資料で確かめた型を渡す
番号から送る値への対応 パネル上の番号と、送る値の対応表。パネルの番号を、そのまま送る値にできるとは限らない
呼ぶ位置 ExpressionPanel の OnSelected に渡す関数。ExpressionPanel 自体は書き換えない

頼み方の例は、次のとおりです。

C# で、int 型の表情の番号を受け取って、VRChat に OSC で送る関数 SendExpression(int index) を書いてください。
送信先のホストとポートは <VRChat の資料で確かめた値>、OSC メッセージのアドレスは <FaceEmo の資料で確かめたアドレス>、値の型は <確かめた型> です。
番号から送る値への対応は <対応表> です。
OSC のライブラリは NuGet から入れてください。

できあがったコードは、OnSelected に渡します。

Child = new ExpressionPanel { OnSelected = SendExpression },

できあがったコードを受け取ったら、次の4点を点検します。

  • 送る値が、対応表のとおりに、手順2でコンソールに出た番号から変換されている
  • 送信先のホストとポートが、VRChat の公式資料と同じ
  • OSC メッセージのアドレスと値の型が、FaceEmo の資料と同じ
  • ExpressionPanel の中身を、AI が書き換えていない

OSC のポートや受信の設定は、FloatSoda の外の話です。直し方はここに書かず、VRChat の公式資料に任せます。

できた? ボタンを押すと、VRChat の中で表情が切り替われば、手順3は完了です。

VRChat を起動し、HMD の中でダッシュボードを開いて、Expression のタブのボタンを押します。ボタンごとに、期待した表情へ切り替わるかを見ます。

できあがったツールを配るときは、exe にして配るに進みます。SteamVR と一緒に起動したいときは、SteamVR と一緒に起動するに進みます。

押しても表情が変わらないときは、次の順で切り分けます。

  1. 手順2のログで、ボタンから番号が渡ることを確認する。出なければ、反応しないときに切り分けるに進む
  2. 送信の関数が呼ばれたことと、送信処理の成否を、コンソールのログで確認する。ログがなければ、AI に書いてもらった送信の関数に、ログを出す1行を足してもらう。ログには、実際に確かめた段階だけを出す
  3. OSC が送られているのに VRChat が反応しない場合は、FloatSoda の外の話なので、VRChat の公式資料を確かめる