見出し画像

プロセカLive2DのAnimationEvent活用術【Advent Calendar 12/22】

はじめに

この記事は Colorful Palette アドベントカレンダー 12/22の記事です。
株式会社Colorful Paletteでクライアントエンジニア兼マネージャーをしている「はくてん」です。

普段は様々な開発のサポートを行いつつ、チームビルディング等もやっていたりします。

折角のColorfulPaletteの記事という事なので、今回は「プロジェクトセカイ カラフルステージ! feat. 初音ミク」(以下プロセカ)で使用しているLive2Dの活用術を少し紹介しようと思います。

プロセカのLive2D

Live2Dとは、平面的な2Dイラスト動かして立体的なアニメーションを実現するソフトウェアで、これを活用することでイラストを生き生きと動かすことができます。

プロセカでは主にメインストーリーやイベントストーリー、エリア会話などで使用されています。

今回はそんなLive2Dのまぶた制御(目パチ)に関するテクニックを紹介していきたいと思います。

Live2Dモデル構造について

まず、Live2Dのモデル構造についてですが、こちらはモデルデータ、顔モーション、体モーション、物理演算データで構成されるスタンダードなものとなっています。

このうちの顔モーションですが、まぶたの制御に関しては、モーション側で設定したパラメータに対してアプリケーション側で上書き制御する形でいくつかの表現を実装しています。

まぶたの制御について

まぶた制御には、「自動制御」のものと、「意図的な制御」の2つが存在しています。

前者は「感情がない表現」で使用します。主に「まばたき」です。一定間隔でパチパチっとなるあれですね。多くの場合は反射的におこる事がほとんどです。

後者は「感情がある表現」で使用します。例えば、何かの出来事に対して「大きく頷く」という動作をする際には、頷きに合わせて「ゆっくりと目を閉じる」という動きが加わったりしますよね。そういった気持ちを表現する為になります。

「感情がある表現」を実現しようとすると、体の動きに連動してまぶたが動く必要があります。

しかし、プロセカでは顔と体のモーションを別々に作っているため、1つの「頷く」というモーションに対して「喜び」「悲しみ」「驚き」といった複数の表情を対応させる必要がありました。

愚直に対応をしようとすると「喜び-頷き」「悲しみ-頷き」「驚き-頷き」といった感じで、モーションと連動するための表情データが倍々で増えていくことになってしまいます。

そこで活用しているのがEventDataといういうものです。
体のモーションに独自のイベントを仕込み、アプリケーション側でそれをアニメーションイベントとしてハンドリングすることで、クリエイター側で自由にまぶた制御を行いつつ、最低限の表情数で運用することを実現しています。

実現方法

1.仕様決め

まずイベントのパラメータには何が必要なのか、Live2Dクリエイターと相談して仕様を決めます。
今回のケースではまぶたの制御なので、「まぶたを閉じる」というアクションに対して下記のパラメータを自由に入力することで様々な表現ができると考えました。

  • EventType:イベントの種類

  • ClosingTime:まぶたが閉じるまでの時間

  • ClosedTime:まぶたを閉じている間の時間

  • OpeningTime:まぶたが開くまでの時間

2.Editorでの設定

Live2DのCubism Editor側で、任意のモーションのキーに対してまぶた制御のイベントデータを打ち込んでもらいます。

イベントパラメータは文字列なので、これらのパラメータをカンマ区切りでつなげて設定するようにしています。

※イベントデータはmotion3.jsonに内包して書き出されます。
Cubism Editorのモーションデータ設定で「イベントを書き出し」にチェックをいれることで出力できます。

3.アプリケーション側での実装

アプリケーション側では入力されたイベントデータに対して、任意の処理を実行できるようにするため、まずはMotion3Jsonでイベントデータに対して発火するメソッドを登録します。
Motion3Json.cs

for (var i = 0; i < UserData.Length; ++i)
{
    var animationEvent = new AnimationEvent
    {
        time = UserData[i].Time,
        stringParameter = UserData[i].Value,
        functionName = "OnLive2DInvokeEventData", // ←この行を追加
    };
    animationEvents.Add(animationEvent);
}
if (animationEvents.Count > 0)
{
    AnimationUtility.SetAnimationEvents(animationClip, animationEvents.ToArray());
}

※基本的にランタイムでのモデルロードを行っているのでこのような形になっています。

次に、登録したアニメーションイベントに対応するメソッドを用意します。
このイベントはAnimationClipを再生するObject側に対して発火しますので、Live2DModel側のスクリプトに用意する必要があります。

protected virtual void OnLive2DInvokeEventData(string parameter)
{
    // パラメータはカンマ区切り
    string[] args = parameter.Split(eventArgsSplitParam);
    
    string eventType = args[0];
    float.TryParse(args[1], out closingTime);
    float.TryParse(args[2], out closedTime);
    float.TryParse(args[3], out openingTime);
    
    // パラメータに応じたまぶたの制御
    eyeBlinkController.PlayCommand(closingTime, closedTime, openingTime);
}

送られてくるイベントデータはstring形式なので、それぞれのパラメータに分解し、まぶた制御のコントローラーに処理を渡します。
あとは、渡されたパラメータに従ってまぶたの開閉処理を行うようにすれば完成です。
とてもシンプルですね!

左が制御なし、右が制御ありの映像です。
まぶた制御ありの方は、ミクさんが頷くタイミングで少しゆっくり目を閉じています。より感情の入った表情変化になっているのがわかりますね!

まとめ

いかがだったでしょうか。
プロセカのLive2Dでは、こういった細かい工夫を重ねて、キャラクターをより豊かに表現できるよう日々活動を行っています。

エンジニアとクリエイターが密に話す事によって生まれるアイディアも多々ありますし、そういう文化やアウトプットはColorfulPaletteらしいものづくりの結果だなぁと感じています。

明日は村田さんの記事です!
お楽しみに!