using UnityEngine; using UnityEditor; //Made by Dreadrith#3238 //Discord: https://discord.gg/ZsPfrGn //Github: https://github.com/Dreadrith/DreadScripts //Gumroad: https://gumroad.com/dreadrith //Ko-fi: https://ko-fi.com/dreadrith namespace DreadScripts.AutoBounds { public class AutoBounds { private const float boundsPercentIncrease = 25; //Sets bounds to auto-calculated dimensions starting from the target [MenuItem("DreadTools/Utility/AutoBounds/Auto")] private static void CalculateBounds() { //Get Selection GameObject go = Selection.activeGameObject; if (!go) return; //Check for animator and to use hips instead of target as root //Always using target as root may make the bounds follow improperly Animator ani = go.GetComponent(); bool isHuman = ani && ani.avatar && ani.isHuman; Transform rootBone = isHuman ? ani.GetBoneTransform(HumanBodyBones.Hips) ?? go.transform : go.transform; //Get child renderers including disabled var renderers = go.GetComponentsInChildren(true); //Get Max Extent by getting the biggest dimension //Avatars can rotate their armature around meaning this dimension can go in any direction, so reuse it for every dimension //Probably not the best logic or calculation but it usually works float maxExtent = 0; foreach (var r in renderers) { if (!r.sharedMesh) continue; Transform currentRootBone = r.rootBone ?? r.transform; var currentExtent = GetMaxAxis(rootBone.InverseTransformPoint(currentRootBone.position)) + GetMaxAxis(r.sharedMesh.bounds.size); if (maxExtent < currentExtent) maxExtent = currentExtent; } //If human, hips should stay the center //Otherwise, center the bounds vertically based on current dimensions Vector3 center = new Vector3(0, isHuman ? 0 : maxExtent / 2, 0); //Increase area by percentage for safe measure maxExtent *= 1 + boundsPercentIncrease / 100; Vector3 extents = new Vector3(maxExtent, maxExtent, maxExtent); //Set auto calculated bounds starting from target as root SetBounds(go.transform, rootBone, new Bounds(center, extents)); } //Sets sampled bounds from target starting from top most parent of target [MenuItem("DreadTools/Utility/AutoBounds/Sample")] private static void SampleBounds() { //Get Selection GameObject go = Selection.activeGameObject; if (!go) return; //Get renderer for sampling SkinnedMeshRenderer sampleRenderer = go.GetComponent(); if (!sampleRenderer) { Debug.LogWarning("No skinned mesh renderer on selected gameobject."); return; } //Set the samples bounds start from the top most parent SetBounds(go.transform.root, sampleRenderer.rootBone, sampleRenderer.bounds); } //Sets all children skinned mesh renderers of the root to the given bounds private static void SetBounds(Transform root, Transform rootbone, Bounds myBounds) { foreach (var r in root.GetComponentsInChildren(true)) { r.rootBone = rootbone; r.localBounds = myBounds; EditorUtility.SetDirty(r); } } private static float GetMaxAxis(Vector3 v) => Mathf.Max(v.x, v.y, v.z); } }