How to get object bounds from children?

rigidbody object root have no collider and mesh
many children with box collider and mesh collider

I want to get the “physical size” of the object.

 Collider[] colliders = GetComponentsInChildren<Collider>();
            bounds = new Bounds(target.position, Vector3.one);
            foreach (Collider c in colliders)
            {               
                bounds.Encapsulate(c.bounds);
            }
            Debug.Log(bounds);

What you have should more or less work. Are you running into an issue with it?

First, just be aware that you can get some pretty screwy physics by having a bunch of child colliders. Sometimes it’s fine, but other times it can lead to some weird behavior.

As for bounds.Encapsulate, I’m not aware of an overload of Encapsulate that itself accepts a bounds, just the version that accepts points. Does your code actually compile? Or is that just kind of what you’re hoping will work?

I’d say you’d probably need to iterate over the effective corners of c.bounds, and call `bounds.Encapsulate’ on all of the pounds that make up the corners of the bounding box.

Edit: Nevermind, I guess Encapsulate(Bounds bounds) is a thing. :slight_smile:

1 Like

One more thing to add, Collider bounds are a decent approximation of an object’s size, but depending on what your exact requirements are, it might not be enough. Bounds are Axis-Aligned Bounding Boxes, which means they are boxes that sit perfectly square on the world axes. If your object is rotated off-axis there’s a good chance you won’t be able to get meaningful metrics about, for example, the “length” , “height” or “depth” of the object itself. This is because a larger axis-aligned box is needed to accomodate a rotated object, even though that box will be mostly empty space (thanks Pythagoras).

What’s the end goal here?

I am trying to make fly pathfinding.

When the target root have a collider, it works as shown in video. The fighter can pick destination
near target as shown in the pink line. (no terrain check yet)

However, when i use the encapsulate code, the destination will be very far away as shown in picture.

  Bounds bounds = new Bounds();
    public Transform Target
    {
        get { return target; }
        set
        {

            target = value;

           
           Collider[] colliders = GetComponentsInChildren<Collider>();
            bounds = new Bounds(target.position, Vector3.one);
            foreach (Collider c in colliders)
            {               
                bounds.Encapsulate(c.bounds);
            }
            Debug.Log(bounds);
            targetRadius = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z);
        
         //   bounds = target.GetComponent<Collider>().bounds;
          //  targetRadius = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z);

            stopDistanceSqrt = targetRadius + attackRange;
            returnDistanceSqrt = targetRadius + funnelRadius * 20;
           
            stopDistanceSqrt *= stopDistanceSqrt;
            returnDistanceSqrt *= returnDistanceSqrt;

            contactPoint = target.position;



               
 
        }
    }
    public bool ContactPoint
    {
        get { return contactPointDisable; }
        set { contactPointDisable = value; }
    }


    private void Awake()
    {
        rigidbody = GetComponent<Rigidbody>();
        Vector3 b = GetComponent<Collider>().bounds.size;
        funnelRadius = Mathf.Max(b.x, b.y, b.z);

        if (debug)
            Target = target;
    }

    private void FixedUpdate()
    {
        if (target != null)
            Move();
    }

    void Move()
    {
        // fly to target until distance
        // pick a non block direction to keep flying
        // return to target until a specific distance

        float distanceSqrt = (target.position - transform.position).sqrMagnitude;
   
        switch (mode)
        {
            case Mode.MoveToTarget:
                if (distanceSqrt > stopDistanceSqrt)
                {                   
                    if (contactPointDisable)
                        contactPoint = target.position;
                    else
                        contactPoint = PickContactPointOnTarget();
                    Rotate();
                    rigidbody.MovePosition(transform.position + transform.forward * speed * Time.fixedDeltaTime);
                }
                else
                    mode = Mode.MoveFromTarget;
                break;
            case Mode.MoveFromTarget:
                if (distanceSqrt < returnDistanceSqrt)
                {
                    rigidbody.MovePosition(transform.position + transform.forward * speed * Time.fixedDeltaTime);
                }
                else
                    mode = Mode.MoveToTarget;

                break;
        }
    }

    Vector3 PickContactPointOnTarget()
    {
        int DefaultLayer = 0;
        int TerrainLayer = 9;
        int LayerMask = 1 << DefaultLayer | 1 << TerrainLayer;

        // should not move directly to target position.
        // should move to a attack point near target
        Vector3 d = contactPoint - transform.position;
        RaycastHit hit;

        // check if the current contact point valid
       // if (!Physics.SphereCast(transform.position, funnelRadius, d, out hit, d.magnitude + targetRadius * 2))
         //   return contactPoint;

        d = target.position - transform.position;
        Vector3 fwdOriginal = d.normalized;
        Vector3 fwd = fwdOriginal;
        for (int i = 1; i <= 180; i+=5)
        {
            float distance = Mathf.Tan(i * Mathf.Deg2Rad) * d.magnitude;
            fwd = fwdOriginal;
            // only consider ray that is far enough from target
            if (distance >= targetRadius + contactDistance)
            {
                // Left, Right
                fwd = fwdOriginal;
                fwd = Quaternion.Euler(i, 0, 0) * fwd;                             
                if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
                    break;
                fwd = fwdOriginal;
                fwd = Quaternion.Euler(-i, 0, 0) * fwd;
                if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
                    break;
                // Up, Down
                fwd = fwdOriginal;
                fwd = Quaternion.Euler(0, i, 0) * fwd;
                if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
                    break;
                fwd = fwdOriginal;
                fwd = Quaternion.Euler(0, -i, 0) * fwd;
                if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
                    break;

                // Slope
                fwd = fwdOriginal;
                fwd = Quaternion.Euler(i, i, 0) * fwd;
                if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
                    break;
                fwd = fwdOriginal;
                fwd = Quaternion.Euler(-i,i, 0) * fwd;
                if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
                    break;
                fwd = fwdOriginal;
                fwd = Quaternion.Euler(i, -i, 0) * fwd;
                if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
                    break;
                fwd = fwdOriginal;
                fwd = Quaternion.Euler(-i, -i, 0) * fwd;
                if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
                    break;
            }
        }
        line.SetPosition(0, transform.position);
        line.SetPosition(1, transform.position + fwd * (d.magnitude));
        return transform.position + fwd * (d.magnitude);
    }


    void Rotate()
    {
        Vector3 d = contactPoint - transform.position;
        Quaternion rot = Quaternion.LookRotation(d, Vector3.up);
        rot = Quaternion.RotateTowards(transform.rotation, rot, Time.fixedDeltaTime * 50);
        rigidbody.MoveRotation(rot);

    }

     private void OnDrawGizmos()
     {
        Debug.DrawLine(bounds.center + bounds.extents, bounds.center, Color.red);
        Debug.DrawLine(target.position, contactPoint, Color.red);
        Debug.DrawLine(transform.position, contactPoint);
     }
}

I just add the terrain avoid part, it becomes something like this video.

It still use a collider on root.

I want to know how to get the “size” if the root don’t have collider.

I put the bounds result in a box collider for debug. The box is so big, I think I don’t understand how encapsulate work.

   Collider[] colliders = GetComponentsInChildren<Collider>();
            bounds = new Bounds(target.position, Vector3.one);
            foreach (Collider c in colliders)
            {               
                bounds.Encapsulate(c.bounds);
            }

            BoxCollider bc = target.GetComponent<BoxCollider>();

            bc.size = bounds.size;

6198268--680065--box.jpg

I just find the stupid bug.

Collider[ ] colliders = GetComponentsInChildren();

should be

Collider[ ] colliders = target.GetComponentsInChildren();