Skip to content

Instantly share code, notes, and snippets.

@bugshake
Created September 28, 2018 12:27
Show Gist options
  • Save bugshake/9adbb023494b7b886c78d1f82e67df65 to your computer and use it in GitHub Desktop.
Save bugshake/9adbb023494b7b886c78d1f82e67df65 to your computer and use it in GitHub Desktop.
Depth sorted Gizmos in the Unity Editor
using System;
using System.Collections.Generic;
using UnityEngine;
public static class SortedGizmos
{
static List<ICommand> commands = new List<ICommand>(1000);
public static Color color { get; set; }
public static void BatchCommit()
{
#if UNITY_EDITOR
Camera cam = null;
var sv = UnityEditor.SceneView.currentDrawingSceneView;
if (sv != null && sv.camera != null)
{
cam = sv.camera;
}
else
{
cam = Camera.main;
}
if (cam != null)
{
var mat = cam.worldToCameraMatrix;
for (int i = 0; i < commands.Count; ++i)
{
commands[i].Transform(mat);
}
// sort by z
var a = commands.ToArray();
Array.Sort<ICommand>(a, compareCommands);
// draw
for (int i = 0; i < a.Length; ++i)
{
a[i].Draw();
}
}
#endif
commands.Clear();
}
public static void DrawSphere(Vector3 center, float radius)
{
commands.Add(new DrawSolidSphereCommand
{
color = color,
position = center,
radius = radius
});
}
public static void DrawWireSphere(Vector3 center, float radius)
{
commands.Add(new DrawWireSphereCommand
{
color = color,
position = center,
radius = radius
});
}
public static void DrawCube(Vector3 center, Vector3 size)
{
commands.Add(new DrawSolidCubeCommand
{
color = color,
position = center,
size = size
});
}
public static void DrawWireCube(Vector3 center, Vector3 size)
{
commands.Add(new DrawWireCubeCommand
{
color = color,
position = center,
size = size
});
}
static int compareCommands(ICommand a, ICommand b)
{
float diff = a.SortValue - b.SortValue;
if (diff < 0f) return -1;
else if (diff > 0f) return 1;
else return 0;
}
interface ICommand
{
void Transform(Matrix4x4 worldToCamera);
void Draw();
float SortValue { get; }
}
struct DrawSolidSphereCommand : ICommand
{
public Color color;
public Vector3 position;
public float radius;
private Vector3 transformedPosition;
public void Transform(Matrix4x4 mat)
{
transformedPosition = mat.MultiplyPoint(position);
}
public void Draw()
{
Gizmos.color = color;
Gizmos.DrawSphere(position, radius);
}
public float SortValue { get { return transformedPosition.z; } }
}
struct DrawWireSphereCommand : ICommand
{
public Color color;
public Vector3 position;
public float radius;
private Vector3 transformedPosition;
public void Transform(Matrix4x4 mat)
{
transformedPosition = mat.MultiplyPoint(position);
}
public void Draw()
{
Gizmos.color = color;
Gizmos.DrawWireSphere(position, radius);
}
public float SortValue { get { return transformedPosition.z; } }
}
struct DrawSolidCubeCommand : ICommand
{
public Color color;
public Vector3 position;
public Vector3 size;
private Vector3 transformedPosition;
public void Transform(Matrix4x4 mat)
{
transformedPosition = mat.MultiplyPoint(position);
}
public void Draw()
{
Gizmos.color = color;
Gizmos.DrawCube(position, size);
}
public float SortValue { get { return transformedPosition.z; } }
}
struct DrawWireCubeCommand : ICommand
{
public Color color;
public Vector3 position;
public Vector3 size;
private Vector3 transformedPosition;
public void Transform(Matrix4x4 mat)
{
transformedPosition = mat.MultiplyPoint(position);
}
public void Draw()
{
Gizmos.color = color;
Gizmos.DrawWireCube(position, size);
}
public float SortValue { get { return transformedPosition.z; } }
}
struct DrawSolidMeshCommand : ICommand
{
public Color color;
public Vector3 position;
public Vector3 scale;
public Quaternion rotation;
public Mesh mesh;
private Vector3 transformedPosition;
public void Transform(Matrix4x4 mat)
{
transformedPosition = mat.MultiplyPoint(position);
}
public void Draw()
{
Gizmos.color = color;
Gizmos.DrawMesh(mesh, position, rotation, scale);
}
public float SortValue { get { return transformedPosition.z; } }
}
struct DrawWireMeshCommand : ICommand
{
public Color color;
public Vector3 position;
public Vector3 scale;
public Quaternion rotation;
public Mesh mesh;
private Vector3 transformedPosition;
public void Transform(Matrix4x4 mat)
{
transformedPosition = mat.MultiplyPoint(position);
}
public void Draw()
{
Gizmos.color = color;
Gizmos.DrawWireMesh(mesh, position, rotation, scale);
}
public float SortValue { get { return transformedPosition.z; } }
}
}
@szethh
Copy link

szethh commented Aug 10, 2020

How does this work? Does it need to be in an Editor folder?

@bugshake
Copy link
Author

It can be anywhere in your project.

To use it you can call the various draw functions like SortedGizmos.DrawSphere from various scripts at various times. (All this does is add a struct to a list)

Then, once per frame, from within a DrawGizmos body you call SortedGizmos.BatchCommit, for example:

void OnDrawGizmos()
{
    SortedGizmos.DrawSphere( Vector3.zero, 1.5f );
    SortedGizmos.DrawSphere( Vector3.right, 1.5f );
    SortedGizmos.BatchCommit();
}

This will draw the gizmos with proper depth sorting and clear the list.

Note that this code will not be optimized out when you build your project.

@szethh
Copy link

szethh commented Aug 10, 2020

I tried drawing some gizmos and then placing a regular sprite in the scene, but the gizmos are always rendered on top on the sprite.
Doesn't matter how much I change the Z-position of the sprite, it is always drawn under the gizmos.

With regular (3D) cubes this doesn't happen.

Why could that be?

@szethh
Copy link

szethh commented Aug 10, 2020

Sprite (left) and cube (right)
image

Both are placed on top of the gizmos, but only the cube is rendered correctly.
image2

@bugshake
Copy link
Author

Ah, this script cannot help you there.

Gizmos completely ignore the depthbuffer. My script will sort them, so the gizmos themselves look normally in 3D (allthough will not intersect).

If you want gizmo's and normal scene to intersect using the depth buffer, you need to use open GL direct mode drawing in the render method, see https://docs.unity3d.com/ScriptReference/GL.html

@Eagle-E
Copy link

Eagle-E commented Mar 7, 2023

Nice!

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