Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Drawing Unity gizmos in builds

A topic by Phill created Nov 15, 2017 Views: 17,179 Replies: 3
Viewing posts 1 to 3
(2 edits) (+5)

In the Unity game engine, theres a useful thing that can help you debug your games, this is the Gizmo toggle.

First, an intro to how gizmos are drawn. Every MonoBehaviour has a magic OnDrawGizmos and OnDrawGIzmosSelected methods. The engine listens for these and executes them when a camera finishes drawing, this includes the hidden scene camera and any other camera. These methods are still compiled into the builds, which means that any code in it, will stay there, but will never be called.

Its a really nice feature when debugging in the editor, however they arent visible in builds. Which is why i made this thread, to explain how you can implement the GL class in unity to display the same gizmos, in builds.

Now to the GL class. This class provides a handy method that can emulate the OpenGL implementation of glVertex3(x, y, z). This method is used to specify a vertex of a shape, and pairing this with GL.Begin() and GL.End() methods tells OpenGL if its a new shape, or a continuous one. So how do you draw a line, in screen space? Well, you have to perform your GL code inside the OnPostRender code, which has to be attached to a camera.

using System.Collections.Generics;
using UnityEngine;
public class GizmoManager : MonoBehaviour
{
    public Material material;
    void OnPostRender()
    {
        material.SetPass(0); //optional, i have mine set to "Sprites-Default"
        //OnPostRender method
        GL.Begin(GL.LINES);
        GL.Color(Color.yellow);
        GL.Vertex(Vector2(0, 0));
        GL.Vertex(Vector2(100, 100));
        GL.End();
    }
}

Ok, you have a diagonal line drawing now, but the Gizmos class still exists, can I override it or hide it? Yes.

One way, is to create a new class called Gizmos, and create your own gizmo methods inside it. This can be placed in the same GizmoManager class file. The only caveat with this is that you have to implement all of the old methods yourself.

public class Gizmos
{
    public static void DrawLine(Vector3 a, Vector3 b, Color color)
    {
        //DrawLine method
    }
}

If you compile this, and try to call Gizmos.DrawLine(), it will default to your implementation of this class. If you want to specify the Gizmos you've been using before you have to explicitly specify the namespace it belongs to.

//DrawLine method
UnityEngine.Gizmos.color = color;
UnityEngine.Gizmos.DrawLine(a, b);

In fact, if you place this line in your own DrawLine implementation, you will be able to draw lines again. So moving on now, how do you call the OnPostRender class from the old one, so that your DrawLine methods draws a line?

A way to do this, is to add the two vectors two a list of lines in the GizmoManager class, and then in the OnPostRender method, for loop through this method and draw all of the lines. Then clear this list after for loop through all of the lines. Why? Because OnDrawGizmos runs before OnPostRender, so theoretically, every line asked to be draw, will be drawn.

So what do we do know to our code? We add a new structure type:

public struct GizmoLine
{
    public Vector3 a;
    public Vector3 b;
    public Color color;
    public GizmoLine(Vector3 a, Vector3 b, Color color)
    {
        this.a = a;
        this.b = b;
        this.color = color;
    }
}

Now that this is declared, you can create a list of this type in your GizmoManager, and now that you have a list, add to it when you call DrawLine in your Gizmos class.

NOTE: Make this list static, so you can access it from the Gizmos class.

//DrawLine method
GizmoManager.lines.Add(new GizmoLine(a, b, color));

Then in your OnPostRender method

//OnPostRender method
GL.Begin(GL.LINES);
for(int i = 0; i < lines.Count; i++)
{
    GL.Color(lines[i].color);
    GL.Vertex(lines[i].a);
    GL.Vertex(lines[i].b);
}
GL.End();
lines.Clear();

Now if you play your game, your Gizmos.DrawLine method should add a GL Line to the list, and have the OnPostRenderer will loop through all lines, and draw this line. Which means its visible in builds. However, the lines are still not visible when the gizmo toggled is turned off. This because the OnDrawGizmos method, only runs if the gizmo toggle is on. So the solution here is to call the Gizmos.DrawLine() method from the OnRenderObject() method on your game objects.

NOTE: The OnPostRender method doesnt run every frame in the editor, which means your gizmos wont be drawn when in edit mode, a workaround for this is to execute the real UnityEngine.Gizmos.DrawLine() method if the Application.isPlaying property is false.

You might also notice that the lines arent visible through other objects, you can fix this by setting the material to a shader that ignores the ztest.


For those in a "rush", heres the full .cs file, just drag and drop onto your Camera and you're good to go.

And here is an example of my 2D game Paintime


(+1)

Cool solution!

(2 edits) (+6)

I know I shouldn't be necroing this shit, but I wrote a neat little package that wraps all of this. GitHub repo.

If you're using 2018.3.x you can add the following to your manifest.json file in Packages folder:

"com.popcron.gizmos": "https://github.com/popcron/gizmos.git"

After that's installed, you can just call Gizmos.Line(a, b) and so on, and it will draw your gizmos for both the editor and builds. Let me know what you guys think of this, I'd be happy to listen to suggestions and feedback on its usability.

I currently use these gizmos in all of my personal games, so that I could hit F3 while I'm playing my game to test out hitboxes and bounds and such stuff.

Thank You Phill!

This is exactly what I was searching for, being able to see debug gizmos in builds is really helpful.