0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Unity(C#)】Lightmap設定関連の一括変更Editor拡張

Last updated at Posted at 2019-10-19

BakeされるStaticなオブジェクト

StaticBake.PNG

画像の箇所にチェックを入れると、
GenerateLighting(Bake)した際に、光源からの情報をオブジェクトに焼き付けることができます。

Unity触りたての頃は、何のために使うのか?という疑問がありましたが、
今となっては使わないことはありません。

簡単に言うとRealTimeで光を反映させると処理が重くなってしまうからです。

なので、オブジェクトが大量にあったり、光源が大量にあったりするシーンにおいては、
StaticなオブジェクトにBakeして、あらかじめ光の情報を焼き付けておくというのは重要となってきます。

一括変更したい項目

StaticなオブジェクトにBakeする際に、オブジェクト毎に設定が必要となる場合があります。
Staticにチェックを入れるとMeshRendererの項目にBake時の設定項目が増えます。
StaticBake.gif

今回はこの増えた設定項目を変更するScriptを書きます。

具体的には、ScaleInLightmapLightmapParametersStitchSeamsです。
他にも項目は増えますが、個人的によく変更する上記3つを一括変更することにします。

コード

一旦全部載せて、後程細かくメモ残します。

# if UNITY_EDITOR
using UnityEngine;
using UnityEditor;

public class LightmapSettingsEdit : EditorWindow
{
    static EditorWindow window;
    float slider;
    Object source;
    bool isOn;
  
    [MenuItem("MyTools/LightmapSettingsEdit")]
    static void ShowWindow()
    {
        window = EditorWindow.GetWindow(typeof(LightmapSettingsEdit));
        window.position = new Rect(Screen.width /2, Screen.height / 2, 300, 400);
    }

    void OnGUI()
    {
        GUILayout.Space(25);

        //ここでScale In Lightmapの値を設定
        slider = EditorGUILayout.Slider("Scale In Lightmap", slider, 0, 20);

        GUILayout.Space(10);

        //====================
        //Scale In Lightmap一括変更ボタン
        //====================
        if (GUILayout.Button("Change all Scale In Lightmap"))
        {
            GameObject selectionObj = Selection.activeGameObject;

            if(selectionObj == null)
            {
                Debug.LogError("オブジェクトを選択してください");
                return;
            }

            ChangeScaleInLightmap(selectionObj);
        }

        GUILayout.Space(50);

        //ここでLightmapParametersを選択
        source = EditorGUILayout.ObjectField(source, typeof(LightmapParameters), true);

        GUILayout.Space(10);

        //====================
        //LightmapParameters一括変更ボタン
        //====================
        if (GUILayout.Button("Change all LightmapParameters"))
        {
            GameObject selectionObj = Selection.activeGameObject;

            if (source == null)
            {
                Debug.LogError("LightmapParametersを選択してください");
                return;
            }

            if (selectionObj == null)
            {
                Debug.LogError("オブジェクトを選択してください");
                return;
            }

            ChangeLightmapParameters(selectionObj);
        }

        GUILayout.Space(50);

        //ここでStitch Seamsを選択
        isOn =  EditorGUILayout.Toggle("Stitch Seams", isOn);

        GUILayout.Space(10);

        //====================
        //Stitch Seams一括変更ボタン
        //====================
        if (GUILayout.Button("Change all Stitch Seams"))
        {
            GameObject selectionObj = Selection.activeGameObject;

            if (selectionObj == null)
            {
                Debug.LogError("オブジェクトを選択してください");
                return;
            }

            ChangeStitchSeams(selectionObj);
        }

        GUILayout.Space(50);

        //====================
        //一括変更ボタン
        //====================
        if (GUILayout.Button("All Apply"))
        {
            GameObject selectionObj = Selection.activeGameObject;

            if (source == null)
            {
                Debug.LogError("LightmapParametersを選択してください");
                return;
            }

            if (selectionObj == null)
            {
                Debug.LogError("オブジェクトを選択してください");
                return;
            }

            //全部いっぺんにするだけ
            ChangeScaleInLightmap(selectionObj);
            ChangeLightmapParameters(selectionObj);
            ChangeStitchSeams(selectionObj);
        }
    }

    void ChangeScaleInLightmap(GameObject obj)
    {
        foreach (Transform child in obj.GetComponentsInChildren<Transform>(true))
        {
            MeshRenderer mr = child.GetComponent<MeshRenderer>();
            if(mr != null)
            {
                SerializedObject so = new SerializedObject(mr);
                so.FindProperty("m_ScaleInLightmap").floatValue = slider;
                so.ApplyModifiedProperties();

                Debug.Log("ScaleInLightmapを一括変更完了!");
            }         
        }
    }

    void ChangeLightmapParameters(GameObject obj)
    {
        foreach (Transform child in obj.GetComponentsInChildren<Transform>(true))
        {
            MeshRenderer mr = child.GetComponent<MeshRenderer>();
            if(mr != null)
            {
                SerializedObject so = new SerializedObject(mr);
               
                SerializedProperty sp = so.FindProperty("m_LightmapParameters");
                if (sp != null)
                {
                    sp.objectReferenceValue = source;
                    so.ApplyModifiedProperties();
                    Debug.Log("LightmapParametersを一括変更完了!");
                }
            }         
        }
    }

    void ChangeStitchSeams(GameObject obj)
    {
        foreach (Transform child in obj.GetComponentsInChildren<Transform>(true))
        {
            MeshRenderer mr = child.GetComponent<MeshRenderer>();
            if (mr != null)
            {
                SerializedObject so = new SerializedObject(mr);
                so.FindProperty("m_StitchLightmapSeams").boolValue = isOn;
                so.ApplyModifiedProperties();

                Debug.Log("ScaleInLightmapを一括変更完了!");
            }
        }
    }
}
# endif

実際にできたEditorWindowがこれです。
Hierarchyで選択したオブジェクト含む、子階層を全て一括で変更します。

LightmapSettings.PNG

FindProperty

今回編集するプロパティがPublicでは無い為(?)、
MeshRenderer.LightmapParametersのようにしてプロパティにアクセスすることはできません。

下記コードのように一度SerializedObjectのコンストラクタに渡して変換してから
FindPropertyを利用します。

    MeshRenderer mr = child.GetComponent<MeshRenderer>();         
    SerializedObject so = new SerializedObject(mr);               
    SerializedProperty sp = so.FindProperty("m_LightmapParameters");
    sp.objectReferenceValue = 適用したいLightmapParameters;
    so.ApplyModifiedProperties();

ただ、このm_LightmapParametersの見つけ方がやっかいでした。
私が行った方法としては、SceneをExplorerからテキストエディタで開きます。

SceneTex.PNG

MeshRendererの箇所に該当するプロパティを見つけました。
少しめんどうですね。他のやり方あれば教えてください。

テキストエディタでSceneを開いた際の注意点

moving.png

テキストエディタでSceneを開いた状態でSceneを変更、Saveすると画像のようなエラーウィンドウが出ます。
何回かに一回、編集データが吹き飛んだので気を付ける必要がありそうです。

FindPropertyするもう一つの理由

実はこのFindPropertyをSerializedObject経由で行う理由はもう1つありまして、
それはUndoが可能になるという点です。Ctrl+ZCtrl+Yで元に戻せますよってことです。

例えばEditor拡張で下記のように重力をOffにした場合、Undoできません。

     rb = child.GetComponent<Rigidbody>();
     rb.useGravity = false;

下記のように変更することでUndoが可能となります。

     rb = child.GetComponent<Rigidbody>();
     SerializedObject so_rb = new SerializedObject(rb);
     so_rb.FindProperty("m_UseGravity").boolValue = false;
     so_rb.ApplyModifiedProperties();

EditorGUILayout.ObjectField

これはInspectorでオブジェクトをアタッチできるアレです。

任意のObjectの種類を指定してあげれば
public GameObject hogehogeとした時と同様の表示が行えます。

Object source;
source = EditorGUILayout.ObjectField(source, typeof(LightmapParameters), true);

2番目の引数(typeofの箇所)で型を指定します。3番目の引数のbool値はScene上のオブジェクトを参照するかどうかの設定です。

GetComponent<T>(true)

GetComponent時の引数にtrueを渡すと、
非アクティブなオブジェクトからも取得が可能になります。

グループごとの設定も可能

選択したオブジェクトと、子のオブジェクトを一括で変更できるので、
Hierarchy上でグループ化したオブジェクト毎にLightmapParametersを設定するなどもできます。

GameObjectに設定されたタグに応じて設定できる。。。といった拡張なども便利かもしれません。

引き続き便利そうなのを思いついたら更新します。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?