25 Sep 2015

Rendering custom GUI on Scene view

Piotr Korzuszek
By Piotr Korzuszek Unity Development Expert

If you’re using assets from the Asset Store then most probably you realized that some scripts introduce custom GUI elements inside the scene view. Custom GUI elements may be very helpful in many cases and they are also easy to implement! Today I’d like to show how to do this.

First, you need to know when custom GUI can be painted. It is done in Editor.OnSceneGUI() method. This means that you need to write a custom editor for any of your components. It should look like this:

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(MyComponent))]
public class MyComponentInspector : Editor {
    void OnSceneGUI() {
        // my scene GUI here
    }
}

This class inherits from Editor class thus let’s call it editor scriptPlease note that all editor scripts should be placed in special Editor directory. If you don’t have any, you can create it anywhere in your project. You can even have multiple Editor directories.

Handles

Handles can be the most useful GUI elements that can be painted on a scene. You will be able to use Unity standard handles like position handle, rotation handle, scale handle, and handle types that cannot be found anywhere else.

Let’s create handles fora  script that should draw a Bezier curve from point A to point B. All the drawing will be done in new editor script.

SceneGUIBezier.cs

using UnityEngine;

public class SceneGUIBezier : MonoBehaviour {
    public Vector3 PointA;
    public Vector3 PointB;
    public Vector3 TangentA;
    public Vector3 TangentB;
}

SceneGUIBezierInspector.cs (should be placed in Editor directory)

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(SceneGUIBezier))]
public class SceneGUIBezierInspector : Editor {
    void OnSceneGUI() {
        var script = (SceneGUIBezier) target;

        script.PointA = Handles.PositionHandle(script.PointA, Quaternion.identity);
        script.PointB = Handles.PositionHandle(script.PointB, Quaternion.identity);
        script.TangentA = Handles.PositionHandle(script.TangentA, Quaternion.identity);
        script.TangentB = Handles.PositionHandle(script.TangentB, Quaternion.identity);

        Handles.DrawBezier(script.PointA, script.PointB, script.TangentA, script.TangentB, Color.red, null, 5);
    }
}

And here’s how the Scene view will look like after this code is compiled and our script is selected:

handlez bezier curve

Tip: Editor script will not be included in your game. When the unity compiles the project it will intentionally ignore all the scripts inside the Editor directories. So don’t worry about additional or unoptimized code inside your editor scripts.

GUI Elements

You may be familiar with GUI and GUILayout functions. It’s a good method for quick and dirty GUI rendering (yet it is not recommended for production use). These and EditorGUI‘s methods are widely used when it comes to create custom inspector GUI, and it can be used to draw Scene GUI elements as well!

To show this, I will write a dummy script that displays Scene GUI to help to rotate object right and left. It will be dummy because all rotation logic is done in the editor script. It makes sense because this functionality will be useful only in the Unity editor and not in the game. Dummy script comes first:

SceneGUIRotate.cs

using UnityEngine;

public class SceneGUIRotate : MonoBehaviour {
}

SceneGUIRotateInspector.cs (should be placed in Editor directory)

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(SceneGUIRotate))]
public class SceneGUIRotateInspector : Editor {

    void OnSceneGUI() {
        Handles.BeginGUI();

        GUILayout.BeginArea(new Rect(20, 20, 150, 60));

        var rect = EditorGUILayout.BeginVertical();
        GUI.color = Color.yellow;
        GUI.Box(rect, GUIContent.none);

        GUI.color = Color.white;

        GUILayout.BeginHorizontal();
        GUILayout.FlexibleSpace();
        GUILayout.Label("Rotate");
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUI.backgroundColor = Color.red;

        if (GUILayout.Button("Left")) {
            RotateLeft();
        }

        if (GUILayout.Button("Right")) {
            RotateRight();
        }

        GUILayout.EndHorizontal();

        EditorGUILayout.EndVertical();


        GUILayout.EndArea();

        Handles.EndGUI();
    }

    void RotateLeft() {
        (target as Component).transform.Rotate(Vector3.down, 15);
    }

    void RotateRight() {
        (target as Component).transform.Rotate(Vector3.down, -15);
    }

}

Code like this will display GUI elements on our scene when object containing this component is selected. To present this, I’ve created a stretched cube:

scene gui rotate

Unitypackage file

Of course, you can download all the scripts mentioned above (along with the example scenes) as unitypackage file from here. Double-click to import it into your project.

Piotr Korzuszek
By Piotr Korzuszek Unity Development Expert
SIRBart

Call The Knights!

    Table of contents