1. 程式人生 > >【包圍盒計算】計算某個物件所有子物件的包圍盒

【包圍盒計算】計算某個物件所有子物件的包圍盒

版權所有。轉載請註明出處: IT_yanghui

     在遊戲開發中,很多時候不需要知道物件下的子物件是什麼,只想給該物件外部加一個物理碰撞或者Collider,或者在開發中需要動態獲取該物件新增Collider,然而給每一個子物件分別加,明顯不現實,浪費時間且影響幀率。

     此時我們需要計算該物件所有子物件的包圍盒。其實很簡單的計算方法,授之於漁。

     計算包圍盒,需要拿到該物件下所有Renderer,即Renderer[]。通過Renderer去計算包圍盒Bounds以及中心點center :

所有Renderer的bounds通過計算得出一個整體(外部)bounds,所有Renderer的中心點center計算得出整體的中心點,有中心點和包圍盒,就OK了。

     修改一下,可以新增到Unity-Component下,給策劃使用,更加方便。

     程式碼如下:看懂了再複製貼上。

static public class BoundsCalculate
    {
        /// <summary>
        /// 獲取模型包圍盒
        /// </summary>
        public static Bounds BOUNDS(this Transform model)
        {
            Vector3 oldPos = model.position;
            model.position = Vector3.zero;
            Bounds resultBounds = new Bounds(model.CENTER(), Vector3.zero);
            CalculateBounds(model, ref resultBounds);
            model.position = oldPos;
            Vector3 scalueValue = ScaleValue(model);
            resultBounds.size = new Vector3(resultBounds.size.x / scalueValue.x, resultBounds.size.y / scalueValue.y, resultBounds.size.z / scalueValue.z);
            return resultBounds;
        }

        /// <summary>
        /// 獲取模型包圍盒的中心點
        /// </summary>
        public static Vector3 CENTER(this Transform model)
        {
            Vector3 result = Vector3.zero;
            int counter = 0;
            CalculateCenter(model, ref result, ref counter);
            if (counter == 0) return result;
            return result / counter;
        }
        
        /// <summary>
        /// 給模型包圍盒新增Collider
        /// </summary>
        public static Bounds AddBoundsCollider(this Transform model)
        {
            Bounds bounds = model.BOUNDS();
            BoxCollider collider = model.gameObject.AddComponent<BoxCollider>();
            collider.center = bounds.center;
            collider.size = bounds.size;
            return bounds;
        }

        /// <summary>
        /// 計算模型包圍盒
        /// </summary>
        private static void CalculateBounds(Transform model, ref Bounds bounds)
        {
            Renderer[] renders = model.GetComponentsInChildren<Renderer>();
            foreach (Renderer child in renders)
            {
                bounds.Encapsulate(child.bounds);
            }
        }
        
        /// <summary>
        /// 計算模型中心點
        /// </summary>
        private static void CalculateCenter(Transform model, ref Vector3 result, ref int counter)
        {
            Renderer[] renders = model.GetComponentsInChildren<Renderer>();
            foreach (Renderer child in renders)
            {
                result += child.bounds.center;
                counter++;
            }
        }

        /// <summary>
        /// 獲取模型Scale值
        /// </summary>
        private static Vector3 ScaleValue(Transform model)
        {
            Vector3 result = model.localScale;
            return CalculateScale(model, ref result);
        }
        
        /// <summary>
        /// 計算模型Scale值
        /// </summary>
        private static Vector3 CalculateScale(Transform model, ref Vector3 value)
        {
            if (model.parent)
            {
                Vector3 scale = model.parent.localScale;
                value = new Vector3(value.x * scale.x, value.y * scale.y, value.z * scale.z);
                CalculateScale(model.parent, ref value);
            }
            return value;
        }
        
    }