【Unity】PLATEAU SDK ToolkitsのLOD1自動テクスチャ生成機能を一括で実行する方法

今回は、[PLATEAU SDK Toolkits for Unity](https://github.com/Project-PLATEAU/PLATEAU-SDK-Toolkits-for-Unity)の[Rendering Toolkit](https://github.com/Project-PLATEAU/PLATEAU-SDK-Toolkits-for-Unity/blob/main/rendering_toolkit.md) にある自動テクスチャ生成機能を使いやすくするためのツールを作ったので、その内容について紹介したいと考えています。

:::note warn
今回の記事の内容は、PLATEAU SDK Toolkits for UnityのPLATEAU Utilitiesによって公式対応されました。
:::

# まえおき
PLATEAUの都市モデルは、建物の再現度を __LOD（Level of Detail）で表現__ します。
LOD0が最低レベルで、数字が増えていくごとに再現度も高くなります。

例として、実際にPLATEAU SDK for Unityを利用して配置したモデルを紹介します。

| __次の画像の左半分がLOD2モデルで、右半分がLOD1モデル__ |
|:--------:|
![スクリーンショット 2023-12-02 23.19.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3609913/efd57efc-397b-214e-ca17-ea745387afbf.png)

右側のLOD1のモデルはデフォルトのテクスチャ（とても小さな窓が規則的に並んでいる）が割り当てられただけで、航空写真のある __LOD2のモデルとうまく馴染んでいません__ 。

3Dモデル化されているPLATEAUの建物データのほとんどはこのLOD1なので、広い範囲を映像作品やゲームなどで使用するには、もう少し他の __オブジェクトと調和させる必要がありそう__ です。
東京都の23区は全て対応していて、一部は非常に解像度が高くなっているだけに惜しいです。

そこで、PLATEAU SDK for Unityのアドオンの一つである、[Rendering Toolkit](https://github.com/Project-PLATEAU/PLATEAU-SDK-Toolkits-for-Unity/blob/main/rendering_toolkit.md) の自動テクスチャ生成機能を使うと、デフォルトのLOD1モデルと比べて違和感のないテクスチャを自動で生成できます。

実際にRendering Toolkitの自動テクスチャ生成機能を実行した結果、この様になりました。

| __LOD1モデルに自動テクスチャを生成した結果__ |
|:--------:|
![スクリーンショット 2023-12-02 23.19.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3609913/1735cfeb-2fc7-f11e-d45f-7d5dd6577993.png)

およそ実用的なレベルでテクスチャが貼れていて、 __LOD2のモデルとも併用できそう__ ですね。

しかし、このままシーンに存在する全てのLOD1オブジェクトに自動テクスチャを生成しようとすると、 __一筋縄ではいかない__ ことがわかります。

ツールの機能として、HierarchyでLOD1のオブジェクトを複数選択することで自動テクスチャを選択したものに対して一括で生成することができます。
ただ、シーンにインポートされる地物データの階層の都合上、配置したLOD1オブジェクトの全てを一度に一括選択し、 __その全てにテクスチャを生成することはできません。__

実際にPLATEAUの地物データを配置すると、以下の画像の様にLOD1オブジェクトが別の親の元にもあり、複数選択することに多くの手間がかかってしまいます。

| __LOD1の親オブジェクトが複数に配置されている__ |
|:--------:|
![スクリーンショット 2023-12-02 23.20.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3609913/d0ca744b-0c6c-0f9e-a401-86296f198160.png)

（Rendering Toolkitに付属するモデル修正機能を使用すると、一応LOD1オブジェクトを絞り込めます。ただ、非アクティブなオブジェクトも選択されてしまうので、検索欄から一括で選択しテクスチャを変更するには名前かコンポーネントを変更する必要がありそうです）

この問題の解決法の一つとして、LOD1オブジェクトの名称をスクリプトから検出し __一度名称変更する__ ことによって、LOD1オブジェクトをHierarchyの __検索バーから一括選択__ し、 __テクスチャの同時自動生成ができる__ ツールを作成しました。
以降はこのツールについて紹介したいと思います。

軽量化や最適化、ツールの導入については扱わないので、その部分に関しては他の記事を参考にしていただけたら幸いです。
# 環境構築（SDKとToolkits）

SDKやToolkitsの環境構築に関しては、[PLATEAU公式のGitHub](https://github.com/Project-PLATEAU/PLATEAU-SDK-Toolkits-for-Unity)が参考になるかと思います。
最新の情報を踏まえた公式のドキュメントなので、この場で説明するよりも信頼できるでしょう。

:::note warn
以降はRendering Toolkitが導入できている前提で話を進めていきます。
:::
# ツールの実装

これ以降は、LOD1オブジェクトの自動テクスチャ生成を使用できる状態を前提とします。

:::note alert
SDKからモデルをインポートする時に、モデル結合の項目を「地域単位」に設定してください。
それ以外を選択してしまうと、原因不明のバグにより、テクスチャを自動生成する時にUnityがフリーズします。
:::
（名前の検索意外で一括変更をしたい場合は、名前ではなくコンポーネントを追加か変更するといいかもしれません）

ChangeNamesForAllLODObjects.csというスクリプトを作り、以下のコードを書きました。

```C#:ChangeNamesForAllLODObjects.cs
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System.Text.RegularExpressions;

public class ChangeNamesForLOD1Objects : EditorWindow
{
    [MenuItem("PLATEAU/Rename LOD")]
    static void LOD_ChangeName()
    {
        bool foundLODObjects = false;
        Transform[] allTransforms = GameObject.FindObjectsByType<Transform>(FindObjectsSortMode.None);

        foreach(var transform in allTransforms)
        {
            Transform grandparent = transform.parent?.parent;

            if (grandparent != null && Regex.IsMatch(grandparent.name, "(bldg|brid)") && transform.parent.name.StartsWith("LOD") && !transform.name.Contains("LOD") && IsNumeric(transform.parent.name.Substring(3)))
            {
                foundLODObjects = true;
                ChangeName(transform.gameObject, int.Parse(transform.parent.name.Substring(3)));
            }
        }

        if (!foundLODObjects)
        {
            Debug.LogWarning("There are no LOD objects");
        }

        return;
    }
    
    static private bool IsNumeric(string str)
    {
        return int.TryParse(str, out _);
    }
    
    static private void ChangeName(GameObject obj, int LOD)
    {
        string newName = $"{obj.name}_LOD{LOD}";
        obj.name = newName;
        Debug.Log($"{obj.name} was renamed.", obj);

        return;
    }
}
#endif

```

このC#スクリプトを書いて保存することにより、メニューバーのPLATEAUに __Rename LODという項目が確認できる__ と思います。
これで準備は完了です。

| __メニューバーのPLATEAUにRename LODが作られる__ |
|:--------:|
![スクリーンショット 2023-12-02 23.22.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3609913/d9ac3d7b-b91e-ed78-6202-b85e7f2886b0.png)

# 実行
そのままRename LODを押下すると、現在アクティブで親にLOD{n}（nは0以上の整数）という名称のオブジェクトを持つオブジェクトの名前に_LOD{n}（nは親オブジェクトのもの）が追加されているはずです。（親がbridかbldgのオブジェクトのみ）
つまり、__親のLODに合わせて子の名前が変更される__ ということです。

| __LODに合わせて名前が変更されている__ |
|:--------:|
![スクリーンショット 2023-12-03 0.06.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3609913/6dcb6112-4ee6-66ed-9640-96275f1ca306.png)

これが確認できたら、Hierarchyの検索バーに"_LOD1"と入力してみてください。
そうすると、LOD1のオブジェクトのみがHierarchyに表示されるはずです。
これを複数選択をすることによって、 __LOD1オブジェクトに自動テクスチャを一括で生成できるようになります。__

| __LOD1オブジェクトのみが表示される__ |
|:--------:|
![スクリーンショット 2023-12-02 23.51.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3609913/d00bdccd-a868-4a2c-6638-16fa40f66e16.png)

# まとめ
今回は、PLATEAU SDK Toolkitsに内包される自動テクスチャ生成をより便利に使うためのコードを書きました。
少しでも作業の効率化に役立てば幸いです。