Live2Dキャラクターの表示速度改善で学んだ高速化のポイント

本記事では、Live2D Cubism SDK for Web を利用したキャラクター表示の速度改善業務について紹介します。 JSON.parse()を活用する前後での読み込み速度の違いや、調査の過程で得た教訓、パフォーマンス改善のポイントをまとめました。 調査の結果、motion3.jsonの読み込みがボトルネックであると分かりました。(なおこのボトルネックは、公式がすでに対応済みだったことも後ほど判明するのですが...)

Live2Dの制御や、パフォーマンス改善業務に興味のある方の参考になれば幸いです。

はじめに

こんにちは!DMM.comの井内将俊です。 私は23年に新卒でDMMへ入社し、現在はライブコミュニケーション開発部、VCグロースグループに所属しています。 VCグロースグループでは、3Dや2Dのキャラクターとリアルタイムにコミュニケーションが楽しめるサービスを開発しています。

バーチャルコミュニケーションサービスでのLive2Dキャラクター

この記事では、機能追加に伴い読み込み速度に課題を抱えたLive2D制御システムの、読み込み速度改善タスクについてお話しします。

Live2D制御とフロントエンド

私たちのチームでは、TypeScriptベースのLive2D Cubism SDK for Webを活用して、UIの開発とLive2Dキャラクターの制御をしています。 このSDKにより、UIのフロントエンドとキャラクター制御がスムーズに統合されています。 詳しくは、過去に執筆した記事で解説しているので、気になる方は読んでみてください!

機能追加に伴う表示速度の課題

私たちが開発するバーチャルコミュニケーションサービスはまだリリースから間もなく、新しい機能が続々と追加されています。 たとえば、夏のイベントでは浴衣衣装が追加されました。

新規追加された浴衣衣装

こうした新しい衣装やモーション追加に伴い必要となる素材ファイルが増えた結果、初期起動の読み込み速度に課題を抱えました。 現在はまだ大きな問題には至っていませんが、将来の機能拡張を考慮し、早期のボトルネックの調査と改善施策に取り組む必要がありました。

ボトルネック調査

適切にパフォーマンスを改善するには、どこに課題があるのか調査する必要があります。 まずは、Live2Dの読み込み処理で一体何が行われているのかを理解し、その後、各処理にどれだけ時間が費やされているのかを計測しました。

Live2Dキャラクター表示時に行われること

Live2D制御に必要となる素材ファイルは、主に以下の3種類です。

  • Live2Dモデル実データ(MOC3)
  • テクスチャ画像(PNG)
  • 各種設定データ(JSON)
    • .model3.json:MOC3 ファイルや、テクスチャファイルなど各素材を結びつけるための情報が記載
    • .physics3.json:物理演算の設定値が記載
    • .motion3.json:各シーンのモーションデータが記載
    • .exp3.json:各表情のパラメータ値が記載

他にもいくつかのJSONファイルがありますが、我々のプロダクトでは使用していないため、ここでは省略します。 参考: Live2D Manuals & Tutorials Editorマニュアル/書き出し/組み込み用データ

Live2Dキャラクターを読み込む際には、これらの素材を順次取得し、反映させます。 ネットワーク経由でデータを取得する時間や、JSONデータから値を読み込む処理、テクスチャの反映にかかる時間も無視できません。 「推測するな、計測せよ」という言葉があるように、まずは実際に計測し、ボトルネックを特定することが重要だと考え、調査を進めました。

各処理に必要となる時間の計測

我々のプロダクトは、Live2D社が公開しているCubismWebSamples/CubismWebFramework をベースに開発しています。 CubismWebSamplesでは、Live2Dキャラクターの読み込み時に以下の順で処理が行われます。

Model → Expression → Physics → Motion → Texture

どの工程にもっとも時間がかかっているのかを確認するために、各工程の処理時間を計測し結果をグラフにまとめました。 計測には、Web APIのperformance.now()を使用しています。 計測で利用したLive2Dモデルには、実際のプロダクトで使用しているものと似たサンプルを利用しました。計測結果は、モデルに含まれる素材のファイル数によって大きく異なることが予想されます。 以下のグラフに、サンプルモデルを使用して計測した各工程の処理時間をまとめています。

各フェーズ毎の処理時間を修正前後で比較した結果
利用したサンプルLive2Dモデル内のファイル数:MOC3:1ファイル、motion3.json:31ファイル、PNGテクスチャ:2ファイル、exp3:8ファイル、physicsファイル:1ファイル

グラフを見ると、モーションのセットアップにかなり時間がかかっていることが確認できます。 motion3.jsonがもっとも数の多いファイルであったため、原因の一端を握っているとは考えていましたが、ここまで顕著に時間がかかっているとは予想していませんでした。 31ファイルと数は多いため、データ取得に時間がかかっているのかとも考えましたが、1ファイルの取得には約100msしかかかっていません。 全ファイルを順番に取得しても3100ms程度です。したがって、残りの約4000msはデータ取得以外のセットアップに時間がかかっていると考えられます(実際には並列取得なので3100msもかかっていません)。

この結果から、motion3.jsonの取得後の処理に大きな負荷がかかっていると判断し、解析処理の改善がキャラクター表示速度向上に繋がると考えました。

モーションの読み込みの改善

Live2Dにおけるモーションとは

そもそも、Live2Dにおけるモーションが何かというと、以下の画像のように、キャラクターへ特定の動きを命令するファイルとなります。

手を振るモーションを動かした時のLive2Dキャラクター

以下は、motion3.jsonのサンプルファイルです。サンプルでは数十行ですが、実際のファイルでは1000行を超えることも珍しくありません。 このように、motion3.jsonは各パラメータの動作タイミングや動きを詳細に指定しており、他のjsonファイルに比べて記載量が多い特徴を持ちます。

{
    "Version": 3,
    "Meta": {
        "Duration": 3.5,
        "Fps": 30.0,
        "Loop": true,
        "CurveCount": 2,
        "etc.":
    },
    "Curves": [
        {
            "Target": "Parameter",
            "Id": "HandType",
            "Segments": [0, 0, 0, 5, 1]
        },
        {
            "Target": "Parameter",
            "Id": "ArmType",
            "Segments": [
                0,
                0,
                1,
                0.166,
                0,
                0.333,
                1,
                0.5,
                1,
                1,
                0.833,
                1,
                1.166,
                1,
                1.5,
                1,
                1,
                1.756,
                1,
                2.000,
                0,
                2.266,
                0,
            ]
        }
    ]
}

加えて、motion3.jsonはモーション機能が増えるほど、同じ数だけ増えるため、この点も他のjsonファイルとの違いとなります。 これらの内容から、取得したmotion3.jsonの読み込み、値反映周りに焦点を当て、パフォーマンス調査・改善へ取り掛かりました。

課題

motion3.jsonの読み込み処理を追っていくと、CubismWebFrameworkではCubismJsonというクラスを用いてmotion3.jsonのパースが行われていました。 このCubismJsonは、独自の方法でJSONデータを処理しており、具体的にはC++などの低レベル言語のように、文字や数値、配列、オブジェクトなどを条件分岐を用いて解析していました。 これはJavaScriptの標準的な手法とは異なるため、手間がかかり、パフォーマンス面で効率が悪い構造でした。

改善と結果

この問題を解決するために、CubismJsonのパース処理の一部をJSON.parse()に置き換えました。 パース処理の変更前後の比較結果が、下記のグラフとなります。グラフから分かるように、パース処理をJSON.parse()に置き換えたことでMotionのセットアップ速度が劇的に改善されました。

各フェーズ毎の処理時間を修正前後で比較した結果

グラフより、以前は7秒以上かかっていたMotionのセットアップが、200ms以下に短縮されたことが確認できます。 キャラクター表示までの時間も、改善前は10秒程度かかっていましたが、2〜3秒程度に改善されました。 加えて、CPU使用率も大幅に削減されています。 この改善は、JSON.parse()がJavaScriptのネイティブメソッドであり、ブラウザやNode.jsエンジンによって最適化されているためだと考えられます。

すで公式で対応済みだったことが判明

当初、CubismJsonのパーサーを使わずJSON.parse()を利用することに対して、リスクや見落としがあるのではないかと不安を感じていました。 しかし、調査を進める中で「CubismJsonの独自パース処理をやめてJSON.parse()を活用する」という手法は、実は公式リリースですでに対応済みであることが分かりました。 参考:Cubism 4 SDK for Web R5

このリリースでは、motion3.jsonのパース処理にJSON.parse()が導入され、本記事で試みた改善とほぼ同じ対応が行われています。 公式から同様の改善が行われていたことを確認できたことで、今回の原因調査や改善案が正しかったと確信し、安心しました。

とはいえ、公式リリースの差分を定期的に確認していれば、ボトルネック調査をする前に取り入れることができ、今回のような「車輪の再発明」を回避できたはずです。改善に取り掛かる前に公式アップデートを確認するべきでした。

おわりに

本記事では、LIve2Dキャラクターの表示速度改善業務について紹介しました。

調査の結果、ボトルネックの特定と改善案の導出に成功し、motion3.jsonのパース処理がパフォーマンス低下の主な原因であることが判明しました。 しかし、すでに公式から同様の改善が行われていたことも後に分かり、パフォーマンス改善において公式のアップデートを定期的に確認することの重要性を強く認識する機会となりました。

加えて、JSON.parse()が大幅なパフォーマンス向上をもたらすことも実感できました。 今後は、公式のリリース差分を積極的にプロダクトに取り入れることで、無駄な作業を省きつつ、プロダクトの品質向上に繋げていきたいと考えています。

私たちのチームでは、このようなプロダクト改善業務や、新機能の開発、リプレイス案件の推進などに取り組んでいます。 ライブコミュニケーション開発部では開発メンバーを募集しています。 もしプロダクト改善業務や、ライブコミュニケーションサービスの開発に興味関心をお持ちいただいた方は、是非お気軽にご連絡ください。

dmm-corp.com