F for Frame Selected - why does it zoom out so much?

Nice work! I’ve had a moment to try some things myself.

It looks like line 17 may serve us better as:

if (EditorWindow.mouseOverWindow != SceneView.lastActiveSceneView || SceneView.lastActiveSceneView == null) {

Note the Editor.mouseOverWindow, which adds some functionality that was missing: if focus is in the hierarchy window, but the mouse is hovering over the scene, pressing “F” should focus the object in the scene.

Also, after re-reading karl_jones’s post above, I noticed that encapsulation of children only happens when Tools.pivotMode == PivotMode.Center. I think that has been a major source of confusion for me as the ignorant user I am, as sometimes focus works nicely while other times it’s zoomed way out for seemingly no reason.

To that end, after playing around with different ideas, I think the built-in Frame works fairly well in pivotMode==PivotMode.Pivot (minus the zooming-out for lights and ParticleSystems), and I’m not a fan of child encapsulation at all. I’ve also found I enjoy having a “maxExtent” value, whereby even large objects have a limit to how far away the camera will be from them. (I also like zooming-in 30% closer than Unity’s default, so I added that as “zoomFactor = 0.7f”.)

Anyway, here’s how it’s looking:

using UnityEditor;
using UnityEngine;

public class FocusReplacer {
    static float defaultExtent = 1f; // if no renderer or collider is found, zoom to an object of this size
    static float maxExtent = 20f; // controls the maximum "zoom-out" when focusing large objects
    static float zoomFactor = 0.7f; // zoom-in more than Unity would by default (1f)

    [MenuItem("Edit/Focus Selected &f")]
    static void Focus() {
        if (Selection.activeObject == null)
            return;

        //Detect object is in project, so just ping
        if (AssetDatabase.Contains(Selection.activeObject)) {
            EditorGUIUtility.PingObject(Selection.activeInstanceID);
            return;
        }

        //Detect hierarchy window is focused, so just ping
        if (EditorWindow.mouseOverWindow != SceneView.lastActiveSceneView || SceneView.lastActiveSceneView == null) {
            EditorGUIUtility.PingObject(Selection.activeInstanceID);
            return;
        }

        Bounds bounds;
        Bounds allBounds = new Bounds();
        foreach (GameObject obj in Selection.gameObjects) {
            Renderer renderer = obj.GetComponentInChildren<Renderer>();
            Collider collider = obj.GetComponentInChildren<Collider>();
            if (renderer && !(renderer is ParticleSystemRenderer)) {
                bounds = renderer.bounds;
            } else if (collider) {
                bounds = collider.bounds;
            } else {
                bounds = new Bounds(obj.transform.position, Vector3.one * defaultExtent);
            }
            if (allBounds.extents == Vector3.zero)
                allBounds = bounds;
            else
                allBounds.Encapsulate(bounds);
        }

        allBounds.extents *= zoomFactor;
        if (allBounds.extents.magnitude > maxExtent)
            allBounds.extents = allBounds.extents.normalized * maxExtent;
        SceneView.lastActiveSceneView.Frame(allBounds, false);
    }
}

5300517–532338–FocusReplacer.cs (1.97 KB)

2 Likes