6 using System.Collections.Generic;
37 [Tooltip(
"The target object")]
44 [Tooltip(
"The transform used to scale the bounding box (will be auto-generated)")]
46 protected Transform scaleTransform = null;
51 [Header(
"Flattening & Padding")]
52 [Tooltip(
"Flattening behavior setting.")]
63 return flattenPreference;
67 flattenPreference = value;
74 [Tooltip(
"The relative % size of an axis must meet before being auto-flattened")]
76 protected float flattenAxisThreshold = 0.025f;
81 [Tooltip(
"The relative % size of a flattened axis")]
83 protected float flattenedAxisThickness = 0.01f;
88 [Tooltip(
"How much to pad the scale of the box to fit around objects (as % of largest dimension)")]
90 protected float scalePadding = 0.05f;
95 [Tooltip(
"How much to pad the scale of the box on an axis that's flattened")]
97 protected float flattenedScalePadding = 0f;
102 [Header(
"Bounds Calculation")]
103 [Tooltip(
"Method used to calculate the bounds of the object.")]
110 [Tooltip(
"Any renderers on this layer will be ignored when calculating object bounds")]
112 protected LayerMask ignoreLayers = (1 << 2);
114 protected Vector3 targetBoundsWorldCenter = Vector3.zero;
116 protected Vector3 targetBoundsLocalScale = Vector3.zero;
118 protected Bounds localTargetBounds =
new Bounds();
120 protected List<Vector3> boundsPoints =
new List<Vector3>();
124 protected bool isVisible =
true;
139 get {
return boundsCalculationMethod; }
140 set { boundsCalculationMethod = value; }
146 public virtual GameObject Target
161 if (!isActiveAndEnabled)
170 RefreshTargetBounds();
178 public Vector3 TargetBoundsCenter
182 return targetBoundsWorldCenter;
190 public Vector3 TargetBoundsScale
194 return scaleTransform.localScale;
201 public Vector3 TargetBoundsLocalScale
205 return targetBoundsLocalScale;
213 public bool IsVisible
221 if (rendererForVisibility == null)
223 Transform scale = transform.GetChild(0);
224 Transform rig = scale.GetChild(0);
225 GameObject rigobject = rig.gameObject;
226 rendererForVisibility = rigobject.gameObject.GetComponent<Renderer>();
229 rendererForVisibility.enabled = value;
241 return flattenedAxis;
245 if (flattenedAxis != value)
247 flattenedAxis = value;
248 if (OnFlattenedAxisChange != null)
250 OnFlattenedAxisChange();
261 protected virtual void OnDrawGizmos()
264 if (!Application.isPlaying)
268 RefreshTargetBounds();
269 UpdateScaleTransform();
274 foreach (Vector3 point
in boundsPoints)
276 Gizmos.DrawSphere(target.transform.TransformPoint(point), 0.01f);
288 RefreshTargetBounds();
289 UpdateScaleTransform();
304 if (scaleTransform == null)
306 scaleTransform = transform;
309 if (scaleTransform == null)
311 scaleTransform =
new GameObject(
"Scale").transform;
314 scaleTransform.parent = transform;
326 targetBoundsWorldCenter = Vector3.zero;
327 targetBoundsLocalScale = Vector3.one;
332 boundsPoints.Clear();
334 switch (boundsCalculationMethod)
338 GetRenderBoundsPoints(target, boundsPoints, ignoreLayers);
342 GetColliderBoundsPoints(target, boundsPoints, ignoreLayers);
346 GetMeshFilterBoundsPoints(target, boundsPoints, ignoreLayers);
350 if (boundsPoints.Count > 0)
354 for (
int i = 0; i < boundsPoints.Count; i++)
356 boundsPoints[i] = target.transform.InverseTransformPoint(boundsPoints[i]);
360 localTargetBounds.center = boundsPoints[0];
361 localTargetBounds.size = Vector3.zero;
362 foreach (Vector3 point
in boundsPoints)
364 localTargetBounds.Encapsulate(point);
369 targetBoundsWorldCenter = target.transform.TransformPoint(localTargetBounds.center);
372 targetBoundsLocalScale = localTargetBounds.size;
373 targetBoundsLocalScale.Scale(target.transform.localScale);
376 UpdateFlattenedAxis();
385 float maxAxisThickness = Mathf.Max(Mathf.Max(targetBoundsLocalScale.x, targetBoundsLocalScale.y), targetBoundsLocalScale.z);
388 switch (flattenPreference)
396 if (Mathf.Abs(targetBoundsLocalScale.z / maxAxisThickness) < flattenAxisThreshold)
399 targetBoundsLocalScale.z = flattenedAxisThickness * maxAxisThickness;
401 else if (Mathf.Abs(targetBoundsLocalScale.y / maxAxisThickness) < flattenAxisThreshold)
404 targetBoundsLocalScale.y = flattenedAxisThickness * maxAxisThickness;
406 else if (Mathf.Abs(targetBoundsLocalScale.x / maxAxisThickness) < flattenAxisThreshold)
409 targetBoundsLocalScale.x = flattenedAxisThickness * maxAxisThickness;
415 targetBoundsLocalScale.x = flattenedAxisThickness * maxAxisThickness;
420 targetBoundsLocalScale.y = flattenedAxisThickness * maxAxisThickness;
425 targetBoundsLocalScale.z = flattenedAxisThickness * maxAxisThickness;
429 FlattenedAxis = newFlattenedAxis;
443 transform.position = targetBoundsWorldCenter;
444 Vector3 scale = targetBoundsLocalScale;
448 float largestDimension = Mathf.Max(Mathf.Max(
453 switch (flattenedAxis)
457 scale.x += (largestDimension * scalePadding);
458 scale.y += (largestDimension * scalePadding);
459 scale.z += (largestDimension * scalePadding);
463 scale.x += (largestDimension * flattenedScalePadding);
464 scale.y += (largestDimension * scalePadding);
465 scale.z += (largestDimension * scalePadding);
469 scale.x += (largestDimension * scalePadding);
470 scale.y += (largestDimension * flattenedScalePadding);
471 scale.z += (largestDimension * scalePadding);
475 scale.x += (largestDimension * scalePadding);
476 scale.y += (largestDimension * scalePadding);
477 scale.z += (largestDimension * flattenedScalePadding);
480 scaleTransform.localScale = scale;
481 Vector3 rotation = target.transform.eulerAngles;
482 transform.eulerAngles = rotation;
486 #region static utility functions 487 public static void GetColliderBoundsPoints(GameObject target, List<Vector3> boundsPoints, LayerMask ignoreLayers)
495 Collider[] colliders = target.GetComponentsInChildren<Collider>();
496 for (
int i = 0; i < colliders.Length; i++)
498 if (ignoreLayers == (1 << colliders[i].gameObject.layer | ignoreLayers))
503 switch (colliders[i].GetType().Name)
505 case "SphereCollider":
506 SphereCollider sc = colliders[i] as SphereCollider;
507 Bounds sphereBounds =
new Bounds(sc.center, Vector3.one * sc.radius * 2);
508 sphereBounds.GetFacePositions(sc.transform, ref corners);
509 boundsPoints.AddRange(corners);
513 BoxCollider bc = colliders[i] as BoxCollider;
514 Bounds boxBounds =
new Bounds(bc.center, bc.size);
515 boxBounds.GetCornerPositions(bc.transform, ref corners);
516 boundsPoints.AddRange(corners);
520 MeshCollider mc = colliders[i] as MeshCollider;
521 Bounds meshBounds = mc.sharedMesh.bounds;
522 meshBounds.GetCornerPositions(mc.transform, ref corners);
523 boundsPoints.AddRange(corners);
526 case "CapsuleCollider":
527 CapsuleCollider cc = colliders[i] as CapsuleCollider;
528 Bounds capsuleBounds =
new Bounds(cc.center, Vector3.zero);
529 switch (cc.direction)
532 capsuleBounds.size =
new Vector3(cc.height, cc.radius * 2, cc.radius * 2);
536 capsuleBounds.size =
new Vector3(cc.radius * 2, cc.height, cc.radius * 2);
540 capsuleBounds.size =
new Vector3(cc.radius * 2, cc.radius * 2, cc.height);
543 capsuleBounds.GetFacePositions(cc.transform, ref corners);
544 boundsPoints.AddRange(corners);
561 Renderer[] renderers = target.GetComponentsInChildren<Renderer>();
562 for (
int i = 0; i < renderers.Length; ++i)
564 var rendererObj = renderers[i];
565 if (ignoreLayers == (1 << rendererObj.gameObject.layer | ignoreLayers))
570 rendererObj.bounds.GetCornerPositionsFromRendererBounds(ref corners);
571 boundsPoints.AddRange(corners);
577 Bounds bounds =
new Bounds();
578 Renderer[] renderers = target.GetComponentsInChildren<Renderer>();
579 for (
int i = 0; i < renderers.Length; ++i)
581 var rendererObj = renderers[i];
582 bounds.ExpandToContain(rendererObj.bounds);
596 MeshFilter[] meshFilters = target.GetComponentsInChildren<MeshFilter>();
597 for (
int i = 0; i < meshFilters.Length; i++)
599 var meshFilterObj = meshFilters[i];
600 if (ignoreLayers == (1 << meshFilterObj.gameObject.layer | ignoreLayers))
605 Bounds meshBounds = meshFilterObj.sharedMesh.bounds;
606 meshBounds.GetCornerPositions(meshFilterObj.transform, ref corners);
607 boundsPoints.AddRange(corners);
609 RectTransform[] rectTransforms = target.GetComponentsInChildren<RectTransform>();
610 for (
int i = 0; i < rectTransforms.Length; i++)
612 rectTransforms[i].GetWorldCorners(rectTransformCorners);
613 boundsPoints.AddRange(rectTransformCorners);
619 LayerMask mask =
new LayerMask();
621 GameObject clone = GameObject.Instantiate(target);
622 clone.transform.localRotation = Quaternion.identity;
623 clone.transform.position = Vector3.zero;
624 clone.transform.localScale = Vector3.one;
626 Vector3 centroid = target.transform.position;
627 GameObject.Destroy(clone);
629 #if UNITY_2017_1_OR_NEWER 630 for (
int i = 0; i < boundsPoints.Count; ++i)
632 boundsPoints[i] = target.transform.localToWorldMatrix.MultiplyPoint(boundsPoints[i]);
634 #endif // UNITY_2017_1_OR_NEWER 637 private static Vector3[] corners = null;
638 private static Vector3[] rectTransformCorners =
new Vector3[4];