BlenderとUnityで作ったものをVR(Meta Quest/Oculus Link)で動かします

ブログの女の子を作る #40 キャラが見えない時はMagicaClothを止めてUnityの負荷を下げる【Unity】

 
前回の記事では、オブジェクトの頂点数を減らすことで、Unityの描画負荷を下げることができました。
 
だいぶん負荷が下がってきた気がしますが、その他にもないかと探してみると、気になるところを見つけました。Magica Clothの処理負荷です。
 
以前の記事で実装した「オクルージョンカリング」は動いているキャラクターにも有効なので、カメラ範囲外の時はキャラクターも非表示にしてくれるんですが、その状態でProfilerを確認してみると、Magica Clothの処理が動いているようでした。少しもったいないですね。
 
私の環境では、複数のキャラクターを同時に表示することが多いです。
キャラクターが見えない(=カメラの範囲外)」時に余分な負荷が無くなってくれると、キャラクターの配置によってはもっとたくさんのキャラクターを表示できるので、いろいろありがたい。
 
やや強引な方法ではありますが、実装してみました。
[2020/08/13追記]
Magica Clothの設定で「負荷を下げる設定(Distance Disable パラメータ)」が準備されていました。記事を追記しましたので、よろしければご覧くださいね。



★8/13追記「Distance Disable」パラメータをおすすめします!

この記事を書いてからMagica Clothさんのサイトを見ていると、「Distance Disable(距離による無効化)」という素晴らしいパラメータを見つけました。
 
本体と指定したオブジェクト(通常はカメラ)の距離に応じてシミュレーションを無効化/有効化します。
これはカメラから遠く離れた場合にシミュレーションをOFFにして処理負荷を下げたい場合に有効です。
このパラメータをオンにすると、この記事でやりたかったことが超簡単にできました。
 
最初から準備して下さっていたのですね。完全に見落としてましたよ。。。
ですので、Magica Clothの描画負荷を下げたい場合は、「Distance Disable」を使うことをおすすめします。
 
Magica Cloth以外のコンポーネント」ではこの記事の方法が使えるかも知れませんので、この記事はそのままにしておきます。
 
 
★以降の記事は「Distance Disable」を使っていない状態です。
 

(1) 描画負荷を確認する

プログラムをご紹介する前に、先に結果を載せておきます。
 
・負荷の差異が分かりやすいように、Terrainやビルなどはすべて非表示にしてます。
・キャラクター数は10体。
・待機状態のアニメーションを実行してます。
・Oculus Link接続はオン。Meta Questをつないだ状態です。
 

1. キャラクター表示あり、Magica Clothオン

最初の状態です。
 
Profilerで見てみると「Renderingの負荷」の上下が激しく変化してます。FPS値も頻繁に変わるので分かりにくいですが、60から90FPSくらい出てる感じでしょうか。
 

2. キャラクター表示なし、Magica Clothオン

カメラを移動して、キャラクターが見えないようにしました。
 
キャラクターは消えましたが、Profilerで確認してみると、Magica Cloth処理「Scripts(青い部分)」が残っているのが分かります。
FPSは70以上くらい。
 

3. キャラクター表示なし、Magica Clothオフ

プログラムを修正して、Magica Clothをオフにしました。
 
Scripts(青い部分)」が無くなりました!
これなら、画面に表示されているキャラクターの負荷だけで済むので安心ですね。
 
FPSの差異は分かりにくいですが、最低値が80以上に上がったようです。
 


(2) プログラムの修正内容(下準備から)

プログラムとしては、「キャラクターが見えない場合はMagica Clothをオフにする、見える場合はオンにする」だけですが、いろいろと下準備やメソッド追加が必要になりました。
一つ一つやっていきましょう。
 

Magica Clothのコンポーネント名を追加する

定数値を管理するクラス「Define.cs」に、Magica Clothのオブジェクト名を追加します。
 
[Define.cs]
// Magica Clothのコンポーネント名
public static readonly string MVD_SK = "Magica Virtual Deformer (スカート)";
public static readonly string MMC_SK = "Magica Mesh Cloth (スカート)";
public static readonly string MVD_SK_C1 = "Magica Virtual Deformer (スカートC1)";
public static readonly string MMC_SK_C1 = "Magica Mesh Cloth (スカートC1)";
public static readonly string MVD_SK_C2 = "Magica Virtual Deformer (スカートC2)";
public static readonly string MMC_SK_C2 = "Magica Mesh Cloth (スカートC2)";
public static readonly string MVD_SK_C3 = "Magica Virtual Deformer (スカートC3)";
public static readonly string MMC_SK_C3 = "Magica Mesh Cloth (スカートC3)";
public static readonly string MVD_SK_L = "Magica Virtual Deformer (スカートL)";
public static readonly string MMC_SK_L = "Magica Mesh Cloth (スカートL)";
public static readonly string MVD_WP_S = "Magica Virtual Deformer (ワンピース下)";
public static readonly string MMC_WP_S = "Magica Mesh Cloth (ワンピース下)";

public static readonly string MBC_TT = "Magica Bone Cloth (ツインテール)";
public static readonly string MVD_KAMI = "Magica Virtual Deformer (髪の毛)";
public static readonly string MMC_KAMI = "Magica Mesh Cloth (髪の毛)";
public static readonly string MVD_YURE = "Magica Virtual Deformer (揺れもの)";
public static readonly string MMC_YURE = "Magica Mesh Cloth (揺れもの)";
 
ツインテールや髪の毛などですね。
これまでは「常にオン(有効状態)」だったので必要ありませんでしたが、今回はこのコンポーネントもオフにしますので、追加で定義しておきます。
 

コンポーネント名を配列にまとめる

プログラム内で扱いやすいように、コンポーネント名のセットを配列にまとめておきます。
 
[Define.cs]
// Magica Clothのコンポーネント設定
// 全ての服
public static readonly string[] MCC_ALL_HUKU = new string[]{
    Define.HUKU_SK,
    Define.HUKU_SK_C1,
    Define.HUKU_SK_C2,
    Define.HUKU_SK_C3,
    Define.HUKU_SK_L,
    Define.HUKU_YS,
    Define.HUKU_YS2,
    Define.HUKU_RB,
    Define.HUKU_RB2,
    Define.HUKU_WP_U,
    Define.HUKU_WP_S,
    Define.HUKU_RB3,
    Define.HUKU_WP_RB,
    Define.HUKU_KT,
    Define.HUKU_KT_B,
    Define.HUKU_KTS,
    Define.HUKU_KTS_B
};

// Magica Clothコンポーネント(全て)
public static readonly string[] MCC_ALL_MCC = new string[]{
    Define.MVD_SK,
    Define.MMC_SK,
    Define.MVD_SK_C1,
    Define.MMC_SK_C1,
    Define.MVD_SK_C2,
    Define.MMC_SK_C2,
    Define.MVD_SK_C3,
    Define.MMC_SK_C3,
    Define.MVD_SK_L,
    Define.MMC_SK_L,
    Define.MVD_WP_S,
    Define.MMC_WP_S
};

// Magica Clothコンポーネント(カメラ範囲外の場合に無効化)
public static readonly string[] MCC_USED_WHEN_CAMERA_OUT = new string[]{
    Define.MBC_TT,
    Define.MVD_KAMI,
    Define.MMC_KAMI,
    Define.MVD_YURE,
    Define.MMC_YURE
};

// キャラ設定1(吊りスカート)
public static readonly string[] MCC_CHARA1 = new string[]{
    Define.HUKU_SK,
    Define.HUKU_YS,
    Define.HUKU_RB,
    Define.HUKU_KT,
    Define.HUKU_KTS,
    Define.MVD_SK,
    Define.MMC_SK
};

//キャラ設定2(チェック柄の青色スカート)
public static readonly string[] MCC_CHARA2 = new string[]{
    Define.HUKU_SK_C1,
    Define.HUKU_YS,
    Define.HUKU_RB2,
    Define.HUKU_KT_B,
    Define.HUKU_KTS_B,
    Define.MVD_SK_C1,
    Define.MMC_SK_C1
};
 
128行目から142行目で「Magica Clothコンポーネント(全て)」、
144行目から151行目で「Magica Clothコンポーネント(カメラ範囲外の場合に無効化)」、
153行目から162行目で「キャラ設定1(吊りスカート)」などを設定してます。
 
基本的には、この単位でMagica Clothをオン/オフします。
 

Utilityクラスにメソッドを移動した

オブジェクトのactive設定を変える「SetObjectメソッド」は良く使いますので、Utilityクラスを新たに作成して、そこにメソッドを移動しました。
 
[Utility.cs]
using System.Collections;
using UnityEngine;

namespace Amaotolog
{
    /// <summary>
    /// ユーティリティクラス
    /// </summary>
    public static class Utility
    {
        // オブジェクトのactive設定
        public static void SetObject(Transform obj, bool isActive, params string[] names)
        {
            for (int i = 0; i < names.Length; i++)
            {
                obj.Find(names[i]).gameObject.SetActive(isActive);
            }
        }

 
場所が変わっただけで、中身は同じですよ。
 
これで下準備は完了です。
 

(3) キャラ生成時にコンポーネント名を保存しておく

キャラクター毎にコンポーネント名を保存しておくと、Magica Clothをオン/オフする処理が楽になります。
 
キャラクターを生成する「InitCharaメソッド」を修正します。
 
[InitCharacter.cs]
// キャラ設定の初期化
void InitChara(Transform chara, string charaName, string[] mccChara)
{
    // 名前
    chara.name = charaName;

    // 自撮りカメラ設定
    //SetObject(chara, false, Define.CAMERA);

    // 服設定
    Utility.SetObject(chara, false, Define.MCC_ALL_HUKU);

    // パンツ設定
    int index = lotPantsList[Random.Range(0, lotPantsList.Count)];
    chara.Find(Define.HUKU_PANTS).gameObject.GetComponent<Renderer>().sharedMaterial = pantsMaterials[index];
    Material parbnMate = chara.Find(Define.HUKU_PANTS).gameObject.GetComponent<Renderer>().materials[1];

    // Pリボン設定
    switch (index)
    {
        case 2: parbnMate.color = Color.blue; break;
        case 3: parbnMate.color = Color.black; break;
    }

    // Magica Clothの全コンポーネントをオフ
    Utility.SetObject(chara, false, Define.MCC_ALL_MCC);

    // キャラ毎のMagica Clothコンポーネントをオン
    Utility.SetObject(chara, true, mccChara);

    // 設定するMagica Clothコンポーネント名リストを格納
    chara.GetComponent<AgentMotion>().mccChara = mccChara;
}

// キャラ設定1
private Transform SetChara1()
{
    Transform chara = Instantiate(baseChara);
    InitChara(chara, "chara1", Define.MCC_CHARA1);
    return chara;
}

// キャラ設定2
private Transform SetChara2()
{
    Transform chara = Instantiate(baseChara);
    InitChara(chara, "chara2", Define.MCC_CHARA2);
    return chara;
}
 
123行目のInitCharaメソッドでキャラクターを生成する際、引数に「そのキャラクターが使うMagica Clothコンポーネント名の配列(Define.MCC_CHARA1」を渡しています。
 
InitCharaメソッド内では、113行目で「Magica Clothコンポーネントをオン」にしつつ、116行目で「コンポーネント名の配列」を保存しています。これでいつでも再利用できますね。
 
これで下準備が完了しました!
 


(4) キャラが見えない時はMagica Clothをオフにする

今回のメイン処理を実装していきましょう。
 

見える/見えないは「レンダラー」で判定する

キャラクターが見える/見えないの判定は、「体」オブジェクトのレンダラーを使います。
 
別の判定方法として「オクルージョンカリングの表示結果を使う(CullingGroup)」もありましたが、若干ややこしそうでしたのでレンダラーを使ってます。
 
[AgentMotion.cs]
[SerializeField]
private Renderer targetRenderer;            // チェック対象のレンダラー
private bool objectEnabledFlg = false;      // オブジェクト有効フラグ
public string[] mccChara;                   // キャラに設定したMagica Clothコンポーネント
39,40行目で targetRenderer を定義することで、キャラクターの「Inspector -> AgentMotion (Script)」に Target Renderer 欄が増えます。
 
ここに「体」オブジェクトをD&Dすると、体のレンダラー「体 (Skinned Mesh Renderer)」を設定できます。
これで、プログラム内で「体オブジェクトのレンダラー」にアクセスしやすくなります。
 

判定用メソッドをUpdate内で呼ぶ

キャラクターの表示判定は毎フレーム実行する必要がありますので、Updateメソッド内に「判定用メソッドを呼ぶ」処理を追加します。
 
[AgentMotion.cs]
private void Update()
{
    // カメラ範囲内外でオブジェクト有無を変更
    IsVisibleCharaOnOff();

    // 目的地に近づいた場合
    if (!agent.pathPending && agent.remainingDistance < 0.5f)
    {
        // モーション実行と次の目的地を設定
        SetMotionAndNextDest();
    }

 
63行目の「IsVisibleCharaOnOffメソッド」が判定用メソッドですね。
 

キャラが見える/見えないで、Magica Clothをオン/オフする

IsVisibleCharaOnOffメソッド」を実装していきます。
 
[AgentMotion.cs]
// カメラ範囲内外でキャラの有無を変更
private void IsVisibleCharaOnOff()
{
    // カメラ範囲内で、オブジェクトが無効の場合
    if (targetRenderer.isVisible && !objectEnabledFlg)
    {
        // オブジェクトを有効にする
        Utility.SetObject(transform, true, mccChara);
        Utility.SetObject(transform, true, Define.MCC_USED_WHEN_CAMERA_OUT);
        objectEnabledFlg = true;
    }

    // カメラ範囲外で、オブジェクトが有効の場合
    if (!targetRenderer.isVisible && objectEnabledFlg)
    {
        // オブジェクトを無効にする
        Utility.SetObject(transform, false, mccChara);
        Utility.SetObject(transform, false, Define.MCC_USED_WHEN_CAMERA_OUT);
        objectEnabledFlg = false;
    }
}
 
127行目から134行目では、「キャラクターが見えない(カメラ範囲外)」場合、そのキャラクターが使っている「Magica Clothのコンポーネントのすべて」をオフ(無効)にしています。
条件文に objectEnabledFlg変数 を追加することで、キャラクターが見えなくなった時に一回だけオフ処理を実行するよう制御してます。
 
118行目から125行目は、先ほどの逆の処理ですね。「キャラクターが見える(カメラ範囲内)」の場合、Magica Clothをオンにしてます。
 

まとめ 

キャラクターが見えない時は、Magica Clothを止めてUnityの負荷を下げることができました。
 
負荷を下げる方法はいろいろあるものですね。
また良い最適化の方法が見つかれば、試してみたいと思います。
 
スポンサーリンク

コメント

  • トラックバックは利用できません。

  • コメント (0)

  1. この記事へのコメントはありません。

ブログの女の子を作る #39 オブジェクトの頂点数を減らしてUnityの負荷を下げる【Unity】

ブログの女の子を作る #41 スカートの一部を固定化する【Unity】


最近のコメント

だーしゅ
IT関係のお仕事してます。
3Dモデルの女の子は「ブログノ・スージー」。VRは楽しいですね。

[当ブログについて]