本日はUnityの小ネタ枠です。
Unityでゲームオブジェクトのメッシュ形状に合わせてBoundsを設定する方法です。
Bounds.Encapsulate
Bounds.EncapsulateはBoundsを拡張して別のBoundsを内包する最小限のBoundsを生成するメソッドです。
本メソッドを利用することで複数のBoundsを組み合わせて1つのBoundsを作成できます。
docs.unity3d.com
サンプルスクリプト
以下の指定されたオブジェクトが持つMeshRendererのBoundsを取得して見た目と同じ大きさのBoxColliderを生成するサンプルスクリプトを作成しました。
子オブジェクトの回転やスケールを考慮して全てのBoundsをBounds.Encapsulateで結合します。
・CalculateBoundsTest.cs
using UnityEngine; public class CalculateBoundsTest : MonoBehaviour { [SerializeField] private GameObject targetObject; [ContextMenu("Calculate Bounds")] void CalculateBounds() { // 子を含む全Rendererを取得 var renderers = targetObject.GetComponentsInChildren<Renderer>(true); // 対象Rendererが存在しない場合は終了 if (renderers.Length == 0) { return; } // ローカル空間での結合Boundsを構築 var parentTransform = targetObject.transform; Bounds combinedLocalBounds = default; bool initialized = false; foreach (var renderer in renderers) { EncapsulateInLocalSpace(renderer.bounds, parentTransform, ref combinedLocalBounds, ref initialized); } // 対象のオブジェクトに同じサイズのBoxColliderを追加 var boxCollider = targetObject.GetComponent<BoxCollider>(); if (boxCollider == null) { boxCollider = targetObject.AddComponent<BoxCollider>(); } boxCollider.center = combinedLocalBounds.center; boxCollider.size = combinedLocalBounds.size; } private void EncapsulateInLocalSpace(Bounds worldBounds, Transform parentTransform, ref Bounds localBounds, ref bool initialized) { // ワールド座標のBoundsを構成するパラメータを取得 Vector3 extents = worldBounds.extents; Vector3 center = worldBounds.center; // バウンディングボックスの8頂点をローカル座標に変換しEncapsulate for (int ix = -1; ix <= 1; ix += 2) { for (int iy = -1; iy <= 1; iy += 2) { for (int iz = -1; iz <= 1; iz += 2) { Vector3 cornerWorld = center + Vector3.Scale(extents, new Vector3(ix, iy, iz)); Vector3 cornerLocal = parentTransform.InverseTransformPoint(cornerWorld); if (!initialized) { localBounds = new Bounds(cornerLocal, Vector3.zero); initialized = true; } else { localBounds.Encapsulate(cornerLocal); } } } } } }
サンプルスクリプトをアタッチした以下のサンプルシーンを作成しました。
計算対象のルートオブジェクトをTargetObjectに指定します。

コンテキストメニューからCalculateBoundsTestを実行します。

以下の通り、子オブジェクトを含んだ見た目と同じ大きさのBoxColliderが設定されました。
