Draw Gizmos from EditorWindow
Asked Answered
L

3

0

Hello,

I wrote an editor script for calculating Bounds of a scene. To prove, if the calculation was correct I would like to visualize the Bounds via a Gizmo. Unfortunately this is not possible, I am getting this error in Unity:

ArgumentException: Gizmo drawing functions can only be used in OnDrawGizmos and OnDrawGizmosSelected.

Any ideas how to make this work as easy as possible?

Here is my code:

public class AutoLightProbes : EditorWindow
{
    public static Bounds sceneBounds = new Bounds(Vector3.zero, Vector3.zero);
  
    [MenuItem("Tools/AutoLightProbes/CalculateLightProbes")]
    private static void CalculateLightProbes()
    {
        DefineSceneBounds();
        OnDrawGizmos();
    }
  
    // 1a) Find out the bounds of the scene
    public static void DefineSceneBounds()
    {
        foreach (Renderer renderer in FindObjectsOfType(typeof(Renderer)))
        { 
                sceneBounds.Encapsulate(renderer.bounds);
        }
        Debug.Log(sceneBounds);
    }
  
    // 1b) Draw Gizmo of the szeneBounds
    public static void OnDrawGizmos()
    {
        Gizmos.color = Color.magenta;
        Gizmos.DrawCube(sceneBounds.center, sceneBounds.size);
    }
}

Thank you
Huxi

Ladle answered 9/1 at 19:13 Comment(0)
L
0

Hello,

thank you very much for the ideas.
I found an easier way for me to make it. I just instantiate a cube:

BoundingBox = Resources.Load<GameObject>("BoundingBox");
var myBoundingBox = Instantiate(BoundingBox, sceneBounds.center, Quaternion.identity);
myBoundingBox.transform.localScale = sceneBounds.extents*2;

it’s just 3 lines of code, which I like :slight_smile:

Thank you for you’re help thought.

Huxi

Ladle answered 9/1 at 19:12 Comment(0)
P
0

There is a certain event structure involved when Unity calls OnDrawGizmos. That’s why you are only allowed to draw Gizmos in these special functions and these functions should only be called by unity.

To draw something for more then 1 frame there needs to be an object holding the data and drawing the data. You don’t have an object. Everything is static.

AutoLightProbes : EditorWindow

Inheriting from EditorWindow is pointless. You don’t open a window. You just execute a function when a menu item is clicked. Remove it and everything should be as before.

private static void CalculateLightProbes()

Is called once, when the user clicks the menu item. Even if you could draw with Gizmos, they would only appear for 1 frame. Thats useless. You need something that is called once every frame.

public static Bounds sceneBounds

This is where you store the result of your calculation. But it will be overwritten, every time the function is executed.

There is a way to do this. But it requires a higher level of understanding the subject matter.
I recommend steering away from editor coding for awhile. If you make it a monobehavior, you can even use Gizmos. Don’t let perfect be the enemy of good enough.

Prostitute answered 9/1 at 19:14 Comment(0)
D
0

EditorWindow OnDrawGizmos

using UnityEngine;
using UnityEngine.UIElements;
using UnityEngine.Rendering;
using UnityEditor;
  
public class AutoLightProbes : EditorWindow
{
  
	public void OnEnable ()
	{
		rootVisualElement.Add( new Label("Close window to stop drawing") );
		RenderPipelineManager.endFrameRendering += EndFrameRendering;
	}
	void OnDisable () => RenderPipelineManager.endFrameRendering -= EndFrameRendering;
  
	void EndFrameRendering ( ScriptableRenderContext context , Camera[] cameras )
		=> DrawBounds( CalculateSceneBounds() );
  
	static Bounds CalculateSceneBounds ()
	{
		Bounds bounds = default(Bounds);
		var renderers = FindObjectsOfType<Renderer>();
		int numRenderers = renderers.Length;
		if( numRenderers!=0 )
		{
			bounds = renderers[0].bounds;
			for( int i=1 ; i<numRenderers ; i++ )
				bounds.Encapsulate( renderers.bounds );
		}
		return bounds;
	}
	 
	static void DrawBounds ( Bounds bounds )
	{
		Vector3
			min = bounds.min ,
			max = bounds.max;
		Vector3
			b0 = min ,
			b1 = new Vector3( min.x , min.y , max.z ) ,
			b2 = new Vector3( max.x , min.y , max.z ) ,
			b3 = new Vector3( max.x , min.y , min.z ) ,
			t0 = new Vector3( min.x , max.y , min.z ) ,
			t1 = new Vector3( min.x , max.y , max.z ) ,
			t2 = max ,
			t3 = new Vector3( max.x , max.y , min.z );
		Color
			red   = new Color{ r=1 , a=0.1f } ,
			green = new Color{ g=1 , a=0.1f } ,
			blue  = new Color{ b=1 , a=0.1f };
		 
		Material material = AssetDatabase.GetBuiltinExtraResource<Material>("Sprites-Default.mat");
		material.SetPass(0);
		 
		GL.PushMatrix();
		GL.Begin( GL.QUADS );
		{
			Quad( b3 , b2 , b1 , b0 , green );// Y-
			Quad( b1 , t1 , t0 , b0 , red );// X-
			Quad( b0 , t0 , t3 , b3 , blue );// Z-
			Quad( b3 , t3 , t2 , b2 , red );// X+
			Quad( b2 , t2 , t1 , b1 , blue );// Z+
			Quad( t0 , t1 , t2 , t3 , green );// Y+
		}
		GL.End();
		GL.PopMatrix();
		 
		void Quad ( Vector3 v0 , Vector3 v1 , Vector3 v2 , Vector3 v3 , Color color )
		{
			GL.Color( color );
			GL.Vertex(v0); GL.Vertex(v1); GL.Vertex(v2); GL.Vertex(v3);
		}
	}
	 
	[MenuItem("Tools/Auto Light Probes/Calculate Light Probes")]
	static void CalculateLightProbes ()
	=> GetWindow<AutoLightProbes>().titleContent = new GUIContent("(= ФェФ=)");

}
Duel answered 9/1 at 19:19 Comment(0)
L
0

Hello,

thank you very much for the ideas.
I found an easier way for me to make it. I just instantiate a cube:

BoundingBox = Resources.Load<GameObject>("BoundingBox");
var myBoundingBox = Instantiate(BoundingBox, sceneBounds.center, Quaternion.identity);
myBoundingBox.transform.localScale = sceneBounds.extents*2;

it’s just 3 lines of code, which I like :slight_smile:

Thank you for you’re help thought.

Huxi

Ladle answered 9/1 at 19:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.