Skip to content

Instantly share code, notes, and snippets.

@Arakade
Created January 3, 2015 16:54
Show Gist options
  • Save Arakade/9dd844c2f9c10e97e3d0 to your computer and use it in GitHub Desktop.
Save Arakade/9dd844c2f9c10e97e3d0 to your computer and use it in GitHub Desktop.
Call from OnDrawGizmos() to draw text at Unity3D glocal position in Editor
static void drawString(string text, Vector3 worldPos, Color? colour = null) {
UnityEditor.Handles.BeginGUI();
if (colour.HasValue) GUI.color = colour.Value;
var view = UnityEditor.SceneView.currentDrawingSceneView;
Vector3 screenPos = view.camera.WorldToScreenPoint(worldPos);
Vector2 size = GUI.skin.label.CalcSize(new GUIContent(text));
GUI.Label(new Rect(screenPos.x - (size.x / 2), -screenPos.y + view.position.height + 4, size.x, size.y), text);
UnityEditor.Handles.EndGUI();
}
@mythstified
Copy link

Hey I used this code and it works great! Except, I was thinking of visualizing coordinates so I did the following:

void OnDrawGizmos()
{
    int xSize = 10, ySize = 10, zSize = 10;
    for (int z = 0; z < zSize; z++)
    {
        for (int y = 0; y < ySize; y++)
        {
            for (int x = 0; x < xSize; x++)
            {
                drawString(x + ", " + y + ", " + z, new Vector3(x, y, z), Color.black);
            }
        }
    }
}

Try this out.. Problem is it works nicely when you're in the proper spot, but if you keep diving into it, suddenly everything gets trippy and weird. What's happening? I suspect it's something to do with the WorldToScreenPoint section

Edit: I fixed it! Check it out:

static void drawString(string text, Vector3 worldPos, Color? colour = null)
{        
    UnityEditor.Handles.BeginGUI();
    if (colour.HasValue) GUI.color = colour.Value;
    var view = UnityEditor.SceneView.currentDrawingSceneView;
    Vector3 screenPos = view.camera.WorldToScreenPoint(worldPos);

    if (screenPos.y < 0 || screenPos.y > Screen.height || screenPos.x < 0 || screenPos.x > Screen.width || screenPos.z < 0)
    {
        UnityEditor.Handles.EndGUI();
        return;
    }

    Vector2 size = GUI.skin.label.CalcSize(new GUIContent(text));
    GUI.Label(new Rect(screenPos.x - (size.x / 2), -screenPos.y + view.position.height + 4, size.x, size.y), text);
    UnityEditor.Handles.EndGUI();
}

@rogeratplumbee
Copy link

I fixed the colour stuff. You need to restore the GUI colour after drawing.

static public void drawString(string text, Vector3 worldPos, Color? colour = null) {
            UnityEditor.Handles.BeginGUI();

            var restoreColor = GUI.color;

            if (colour.HasValue) GUI.color = colour.Value;
            var view = UnityEditor.SceneView.currentDrawingSceneView;
            Vector3 screenPos = view.camera.WorldToScreenPoint(worldPos);

            if (screenPos.y < 0 || screenPos.y > Screen.height || screenPos.x < 0 || screenPos.x > Screen.width || screenPos.z < 0)
            {
                GUI.color = restoreColor;
                UnityEditor.Handles.EndGUI();
                return;
            }

            Vector2 size = GUI.skin.label.CalcSize(new GUIContent(text));
            GUI.Label(new Rect(screenPos.x - (size.x / 2), -screenPos.y + view.position.height + 4, size.x, size.y), text);
            GUI.color = restoreColor;
            UnityEditor.Handles.EndGUI();
        }

@jspillers
Copy link

I see this is a few years old, but just wanted to say thank you for this very useful bit of code and that it is still working great in 2018.3.8f1!

@nukadelic
Copy link

You can use handles inside the gizmo draw function instead like so :

void OnDrawGizmos()
{
   #if UNITY_EDITOR
   UnityEditor.Handles.color = Color.white;
   UnityEditor.Handles.Label( pointA.position, "Point A" );
   #endif
}

it also has overloads for texture and style ( font size can be changed )

@qdx
Copy link

qdx commented Nov 22, 2020

@nukadelic works like a charm, thanks!

@andigamesandmusic
Copy link

andigamesandmusic commented Jan 27, 2022

Thanks all for the snippet and tweaks! Based on the GUI version above, I further improved by using GUIStyle to specify color and font size without having to use the color restore logic. I also added pixel-precise positioning with anchor support (e.g. Vector2.zero = center, Vector2.one = anchor to bottom-left corner, -Vector2.one = anchor to top-right corner, etc.). The fudge factor issue is fixed by using camera.pixelHeight instead of view.position.height.

static public void drawString(string text, Vector3 worldPosition, Color textColor, Vector2 anchor, float textSize = 15f)
{
#if UNITY_EDITOR
    var view = UnityEditor.SceneView.currentDrawingSceneView;
    if (!view)
        return;
    Vector3 screenPosition = view.camera.WorldToScreenPoint(worldPosition);
    if (screenPosition.y < 0 || screenPosition.y > view.camera.pixelHeight || screenPosition.x < 0 || screenPosition.x > view.camera.pixelWidth || screenPosition.z < 0)
        return;
    var pixelRatio = UnityEditor.HandleUtility.GUIPointToScreenPixelCoordinate(Vector2.right).x - UnityEditor.HandleUtility.GUIPointToScreenPixelCoordinate(Vector2.zero).x;
    UnityEditor.Handles.BeginGUI();
    var style = new GUIStyle(GUI.skin.label)
    {
        fontSize = (int)textSize,
        normal = new GUIStyleState() { textColor = textColor }
    };
    Vector2 size = style.CalcSize(new GUIContent(text)) * pixelRatio;
    var alignedPosition =
        ((Vector2)screenPosition +
        size * ((anchor + Vector2.left + Vector2.up) / 2f)) * (Vector2.right + Vector2.down) +
        Vector2.up * view.camera.pixelHeight;
    GUI.Label(new Rect(alignedPosition / pixelRatio, size / pixelRatio), text, style);
    UnityEditor.Handles.EndGUI();
#endif
}

@joaoh82
Copy link

joaoh82 commented Aug 30, 2022

@nukadelic great solution! Simple! Thanks!

@MartijnPW
Copy link

Thanks a lot, works great!

For those who wonder what this pixelRatio is about: it depends on the display UI scaling (e.g. 1.5 for the '150%' setting in windows)

Instead of computing it, you can actually just get it using
var pixelRatio = EditorGUIUtility.pixelsPerPoint;
(see https://docs.unity3d.com/ScriptReference/EditorGUIUtility-pixelsPerPoint.html)

@Kaegun
Copy link

Kaegun commented Jan 15, 2023

Very neat, exactly what I was looking for!

@BurakKaragol
Copy link

BurakKaragol commented Apr 14, 2023

I passed a color and it made the whole scene view that color. I just removed it, and it satisfied what I intended. Well done! Thanks

I solved the issue color issue and also fixed the scene zoom text slipping

public static void DrawString(string text, Vector3 worldPos, Color? colour = null)
{
UnityEditor.Handles.BeginGUI();
Color defaultColor = GUI.color;
if (colour.HasValue) GUI.color = colour.Value;
var view = UnityEditor.SceneView.currentDrawingSceneView;
Vector3 screenPos = view.camera.WorldToScreenPoint(worldPos);
Vector2 size = GUI.skin.label.CalcSize(new GUIContent(text));
GUI.Label(new Rect(screenPos.x - (size.x / 2), -screenPos.y + view.position.height - size.y * 2, size.x, size.y), text);
GUI.color = defaultColor;
UnityEditor.Handles.EndGUI();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment