0
0

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 3 years have passed since last update.

【Unity】UnpackされたモデルのTransformをプレハブで再現するEditor拡張

Last updated at Posted at 2022-05-06

例えばこんな岩のモデルがあったとして
RockModel.png

親GameObjectにColliderを付与して、それがそこそこ良い感じになるようにTransformの値をコネコネしたものをプレハブ化していたとします。
Rockプレハブ.png

その後暫くしてから仕様追加等でプレハブを編集したんだけど、「とあるシーンでは編集が効いていない」なんて不具合報告を受けて調査をしたところ…
モデルが直接シーンに置かれてる.png
プレハブUnpackしてモデルだけ直接シーンに置かれてる。。。

なんてこと、ありますよね。1

このようなものは同じ見た目になるようにプレハブで再現して修復する必要があるわけですが、プレハブ内のモデルのTransformに複雑な値が入っていると、手作業で復元するのは至難の業です。

ということで、復元してくれるエディタ拡張を作りました。

使い方

復元対象のプレハブを拡張機能から判別できるように、専用のフォルダに一旦移動します。
プレハブを専用フォルダに移動.png

Unpackされたモデルを右クリックしてメニューを選択すると
拡張機能のメニュー選択.png

同じ見た目となるようにルートGameObjectのPosition, Rotation, Scaleを調整したプレハブがヒエラルキーに生成されます。
再現完了.png

ソースコード

プレハブのルートGameObject直下の階層にモデルが配置されている前提の作りとなっています。
階層構造のあり方、復元対象のプレハブの指定方法等は利用場面に合わせて都度改変するのが良いと思います。

ソースコード
using UnityEditor;
using UnityEngine;

/// <summary>
/// UnpackしたGameObjectと同じPosition,Rotation,Scaleのものを再現したプレハブをヒエラルキーに配置する拡張機能
/// </summary>
/// <remarks>対象GameObjectを内包するプレハブをResources/<see cref="FolderName"/>フォルダに移動してから実行する必要があります。</remarks>
public static class UnpackedGameObjectRecreation
{
    private const string FolderName = "RecreationTarget";

    [MenuItem("GameObject/UnpackしたGameObjectをプレハブで再作成", false, 1)]
    public static void RecreateUnpackedGameObjectUsingPrefab()
    {
        var prefab = Resources.LoadAll<GameObject>(FolderName)[0];
        if (prefab == null)
        {
            Debug.LogError($"再現するプレハブをResources/{FolderName}フォルダに移動してから実行して下さい。");
            return;
        }

        foreach (var srcModel in Selection.transforms)
        {
            var createdRoot = (PrefabUtility.InstantiatePrefab(prefab) as GameObject).transform;
            var createdModel = createdRoot.GetChild(0);

            // 選択中のGameObjectと同じPosition, Rotation, Scaleとなるように、プレハブのルートGameObjectのTransformを変更
            var couldAdjust = AdjustScale(srcModel, createdModel);
            if (!couldAdjust)
            {
                UnityEngine.GameObject.DestroyImmediate(createdRoot.gameObject);
                continue;
            }

            AdjustRotation(srcModel, createdModel);
            AdjustPosition(srcModel, createdModel);
        }
    }

    private static bool AdjustScale(Transform src, Transform dest)
    {
        if (src.lossyScale == dest.lossyScale) return true;

        var tolerance = 0.0001f;
        var multiplier = src.lossyScale.x / dest.localScale.x;
        if (Mathf.Abs(multiplier - src.lossyScale.y / dest.localScale.y) > tolerance || Mathf.Abs(multiplier - src.lossyScale.z / dest.localScale.z) > tolerance)
        {
            Debug.LogError("選択したGameObjectとプレハブの子階層のGameObjectでScaleのXYZの比率が異なるため、再現できません。");
            return false;
        }

        dest.parent.localScale = Vector3.one * multiplier;
        return true;
    }

    private static void AdjustRotation(Transform src, Transform dest)
    {
        if (src.rotation == dest.rotation) return;

        dest.parent.rotation = src.rotation * Quaternion.Inverse(dest.localRotation);
    }

    private static void AdjustPosition(Transform src, Transform dest)
    {
        if (src.position == dest.position) return;

        dest.parent.position += src.position - dest.position;
    }
}

制限事項

複数選択対応

複数のGameObjectが選択されていたら全てのGameObjectをプレハブで再現するようになっています。

…が、Unityの不具合により、選択個数と同じ回数MenuItemの処理が呼び出されるので、同じGameObjectが選択個数分生成されてしまいます。(Unity2021.2.14にて確認)

<例>

  • 2個選択
    • → 2種類 x 2回処理 = 全部で4個生成される
  • 3個選択
    • → 3種類 x 3回処理 = 全部で9個生成される
      3x3個生成される.png

これ修正しないって表明されていますが、なんでそんな判断になったのか疑問…。

コンテキストメニューからではなく、メニューバーの[GameObject]内から選択して実行すれば意図通りの挙動となります。

Non-Uniform Scaling

UnityのTransformのマニュアルに記載のある通り、Non-Uniform Scaling(不均等スケーリング)と呼ばれる、ScaleのXYZ値が同一でないGameObjectの子オブジェクトは、親オブジェクトの軸でのみ拡縮可能となり、子オブジェクトの軸で拡縮させることができません。
このため、選択したGameObjectと、再現対象のプレハブの子階層のGameObjectでScaleのXYZ値の比率が同一でない場合は、親GameObjectのScaleのXYZを同一値で保ったまま再現することが不可能なので、エラーメッセージをコンソールに表示するようにしています。

Non-Uniform Scalingについては以下の記事にまとめました。

  1. 正確にはUnpackという操作をしなくてもこの状態を作り出すことはできます。
    実際はモデル部分のみをコピーして複製されてしまったというパターンの方が多いと思います。

0
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?