unity3d Extending the Editor Gizmos


Example

Gizmos are used for drawing shapes in the scene view. You can use these shapes to draw extra information about your GameObjects, for instance the frustum they have or the detection range.

Below are two examples on how to do this

Example One

This example uses the OnDrawGizmos and OnDrawGizmosSelected (magic) methods.

public class GizmoExample : MonoBehaviour {

    public float GetDetectionRadius() {
        return 12.5f;
    }

    public float GetFOV() {
        return 25f;
    }

    public float GetMaxRange() {
        return 6.5f;
    }

    public float GetMinRange() {
        return 0;
    }

    public float GetAspect() {
        return 2.5f;
    }

    public void OnDrawGizmos() {
        var gizmoMatrix = Gizmos.matrix;
        var gizmoColor = Gizmos.color;

        Gizmos.matrix = Matrix4x4.TRS( transform.position, transform.rotation, transform.lossyScale );
        Gizmos.color = Color.red;
        Gizmos.DrawFrustum( Vector3.zero, GetFOV(), GetMaxRange(), GetMinRange(), GetAspect() );

        Gizmos.matrix = gizmoMatrix;
        Gizmos.color = gizmoColor;
    }

    public void OnDrawGizmosSelected() {
        Handles.DrawWireDisc( transform.position, Vector3.up, GetDetectionRadius() );
    }
}

In this example we have two methods for drawing gizmos, one that draws when the object is active (OnDrawGizmos) and one for when the object is selected in the hierarchy (OnDrawGizmosSelected).

public void OnDrawGizmos() {
    var gizmoMatrix = Gizmos.matrix;
    var gizmoColor = Gizmos.color;

    Gizmos.matrix = Matrix4x4.TRS( transform.position, transform.rotation, transform.lossyScale );
    Gizmos.color = Color.red;
    Gizmos.DrawFrustum( Vector3.zero, GetFOV(), GetMaxRange(), GetMinRange(), GetAspect() );

    Gizmos.matrix = gizmoMatrix;
    Gizmos.color = gizmoColor;
}

First we save the gizmo matrix and color because we're going to change it and want to revert it back when we are done to not affect any other gizmo drawing.

Next we want to draw the frustum that our object has, however, we need to change the Gizmos' matrix so that it matches the position, rotation, and scale. We also set the Gizmos' color to red to emphasize the frustum. When this is done we can call Gizmos.DrawFrustum to draw the frustum in the scene view.

When we are done drawing what we want to draw, we reset the Gizmos' matrix and color.

public void OnDrawGizmosSelected() {
    Handles.DrawWireDisc( transform.position, Vector3.up, GetDetectionRadius() );
}

We also want to draw a detection range when we select our GameObject. This is done through the Handles class since the Gizmos class doesn't have any methods for discs.

Using this form of drawing gizmos results into the output shown below.

Example two

This example uses the DrawGizmo attribute.

public class GizmoDrawerExample {

    [DrawGizmo( GizmoType.Selected | GizmoType.NonSelected, typeof( GizmoExample ) )]
    public static void DrawGizmo( GizmoExample obj, GizmoType type ) {
        var gizmoMatrix = Gizmos.matrix;
        var gizmoColor = Gizmos.color;

        Gizmos.matrix = Matrix4x4.TRS( obj.transform.position, obj.transform.rotation, obj.transform.lossyScale );
        Gizmos.color = Color.red;
        Gizmos.DrawFrustum( Vector3.zero, obj.GetFOV(), obj.GetMaxRange(), obj.GetMinRange(), obj.GetAspect() );

        Gizmos.matrix = gizmoMatrix;
        Gizmos.color = gizmoColor;

        if ( ( type & GizmoType.Selected ) == GizmoType.Selected ) {
            Handles.DrawWireDisc( obj.transform.position, Vector3.up, obj.GetDetectionRadius() );
        }
    }
}

This way allows you to separate the gizmo calls from your script. Most of this uses the same code as the other example except for two things.

[DrawGizmo( GizmoType.Selected | GizmoType.NonSelected, typeof( GizmoExample ) )]
public static void DrawGizmo( GizmoExample obj, GizmoType type ) {

You need to use the DrawGizmo attribute which takes the enum GizmoType as the first parameter and a Type as the second parameter. The Type should be the type you want to use for drawing the gizmo.

The method for drawing the gizmo needs to be static, public or non-public, and can be named whatever you want. The first parameter is the type, which should match the type passed as the second parameter in the attribute, and the second parameter is the enum GizmoType which describes the current state of your object.

if ( ( type & GizmoType.Selected ) == GizmoType.Selected ) {
    Handles.DrawWireDisc( obj.transform.position, Vector3.up, obj.GetDetectionRadius() );
}

The other difference is that for checking what the GizmoType of the object is, you need to do an AND check on the parameter and the type you want.

Result

Not selected

example one not selected

Selected

example one selected