【Unity】【VRM】Scaleを変更するとSpringBoneが暴れる

はじめに

先日VRMモデルを使用した簡単なゲームをunityroomで公開したのですが、これを作成する際にハマったポイントの備忘録です。

神はサイコロをふる | フリーゲーム投稿サイト unityroom

環境

Unity6000.0.32f

VRM1.0

起きたこと

別記事(下記)で記載したようにサイコロのサイズをある程度大きくしないと物理演算が安定しないという問題がありました。

この問題を解決するためサイコロを10倍サイズにしたわけですが、そうするとVRMモデルも10倍にスケールアップしないとバランスが取れないので、VRMモデルをインポートするときに10倍にするように調整しました。

その調整を行った結果、髪の毛が下の動画のように何も力を加えていないのに動き続けるという現象が発生しました。

原因

Scaleを変更するだけで、この現象が発生することを確認しています。

なので、Scaleを変更することがVRMのSpringBoneの演算がおかしくなる原因と考えて良さそうです。

対応

この現象は再生中にScaleを変更した場合に発生しており、再生前に10倍にしてから再生しても発生しないことから、再生時にSpringBoneないし、VRMのインスタンスに何らかの初期化処理が走っていることが推測されました。

CludeCodeに調べさせたところScaleを変更した場合にはReconstructSpringBone()というメソッドをコールして、初期化してやる必要があることがわかりました。

Vrm10Instanceを引数として下記のようなメソッドを定義するのが良さそうです。

/// <summary>
/// MARK: ReinitializeSpringBoneAfterScale
/// スケール変更後にSpringBoneシステムを再初期化します
/// </summary>
/// <param name="vrmInstance">対象のVRMインスタンス</param>
public async UniTask ReinitializeSpringBoneAfterScale(Vrm10Instance vrmInstance)
{
    if (vrmInstance == null)
    {
        DebugLogger.LogWarning("VRMインスタンスがnullのため、SpringBone再初期化をスキップします。");
        return;
    }

    try
    {
        // 1フレーム待機してTransformの更新を確実にする
        await UniTask.NextFrame();

        // SpringBoneランタイムが存在するか確認
        if (vrmInstance.Runtime?.SpringBone == null)
        {
            DebugLogger.LogWarning("SpringBoneランタイムが初期化されていません。");
            return;
        }

        // SpringBoneシステムを再構築
        bool reconstructSuccess = vrmInstance.Runtime.SpringBone.ReconstructSpringBone();

        if (reconstructSuccess)
        {
            DebugLogger.Log("SpringBoneシステムの再構築が完了しました。");
        }
        else
        {
            DebugLogger.LogWarning("SpringBone再構築に失敗しました。代替方法を試行します。");

            // 代替方法: ランタイム全体を再作成
            vrmInstance.DisposeRuntime();
            await UniTask.NextFrame();

            // Runtime プロパティにアクセスすることで自動的に再作成される
            var newRuntime = vrmInstance.Runtime;
            DebugLogger.Log("SpringBoneランタイムを完全に再作成しました。");
        }
    }
    catch (System.Exception ex)
    {
        DebugLogger.LogError($"SpringBone再初期化中にエラーが発生しました: {ex.Message}");
    }
}

さいごに

ゲーム中にキャラクターのScaleを変えることはあまりない気もしますが、どなたかのお役に立てば幸いです。

最後までお読みいただきありがとうございます。

コメント

タイトルとURLをコピーしました