Framing an Object, Bounds & Encapsulating

Hi All,

I have a selection system that is working fine, But I need to have the ability to zoom into the object I have clicked on, Similar to pressing ‘F’ Unity/Any other 3D package.

I have been looking into the bounds and can even get my camera to go to the objects bounds correctly, But I am not sure how to get it to frame it on screen, as it goes right into the middle of the objects bounds or to one of the edges depending on which mode I use.

Say I wanted to have it in the middle of the screen with a 10% screen gap around, I know I could do an offset but it wouldnt always be correct as some objects are significantly bigger than others.

I also have groups, And if I selected a group of objects I would want that to be framed with the same 10% margin around, Which I think I would use Encapsulating for.

If anyone can think of anything to point me in the right direction I would be incredibly grateful, Out of ideas at this point…

Cheers,
Russell

EDIT: Here are some simple scripts that will move the camera a set distance away from an object and look at it. Imagine an object rests at (0,0,0) and the camera is looking at from (3,3,3). These scripts will move the camera to be the same distance away on the x and z-axis while staying at height 3. This rough, doesn’t care about the height of the GO, and sets itself to a specific distance away. You can adjust this script for varying sized objects simply by testing out what you think looks good and storing that value in the offset variable on the object.

On your GameObject:

    float offset = 4.24264f
    void OnMouseOver()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Camera.main.GetComponent<FocusScript>().Focus(transform, offset);
        }
    }

On your main camera:

    public void Focus(Transform target, float offset)
    {
        Vector3 direction = transform.position - target.position;
        direction = offset * direction.normalized;

        Vector3 moveTo = target.position + direction;
        transform.position = new Vector3(moveTo.x, 3f, moveTo.z);

        transform.LookAt(target);
    }

I hope this works for you. If you need something a little more dynamic, you could use the height as a factor multiplied against a static offset. Like if the GO is 2 units tall you could move it 2 * offset away. And just look up the collider height to feed that value.

END EDIT

Well, first take a look at Transform.LookAt.

Then it gets hairy unless there is an API call for this that I can’t find (like your example from the unity editor). If you have a collider on the thing you’re trying to frame, you could look at it’s dimensions, then adjust the current viewport to the larger one respective to your current aspect ratio (plus your padding).

Maybe Camera.WorldToViewportPoint and Camera.ViewportToScreenPoint will come in handy.

Whatever math you use to figure out the new rectangle you’re looking at based on the collider you wanted to frame, do that again except figure it out based on the width of the group of objects you have selected. Find the leftmost and rightmost objects in the group after you’ve turned the camera to look at them, and use that as your bounds (plus your pladding). You can probably use Bounds.Encapsulate to accomplish this actually, then it’s a repeat of the simple version.

I realize there’s a lot of code you’re going to need for this, so hopefully someone else knows a more API based “FrameInView” method or something.

Thanks for the reply, Much appreciated.
I do have a collider on each of the objects, Which I my RayCast hits when each object is selected - So I can get all the bounds information from that and go up the hierarchy to encapsulate multiple objects. I’m just not sure how to then turn that information into something I can tell the camera to do…

I.E - Keep moving forwards until this object reaches some predefined boundary on the camera…

Currently having a look at this in the manual: Unity - Manual: The Size of the Frustum at a Given Distance from the Camera

Cheers,
Russell