123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Rendering;
- using UnityEngine.SceneManagement;
- #if UNITY_EDITOR
- using UnityEditor;
- using UnityEditor.SceneManagement;
- #endif
- #if !UNITY_2019_1_OR_NEWER
- using System;
- public struct ScriptableRenderContext {}
- public static class RenderPipelineManager
- {
- public static event Action<ScriptableRenderContext, Camera> endCameraRendering;
- }
- #endif
- namespace Popcron
- {
- [ExecuteInEditMode]
- [AddComponentMenu("")]
- public class GizmosInstance : MonoBehaviour
- {
- private const int DefaultQueueSize = 4096;
- private static GizmosInstance instance;
- private static bool hotReloaded = true;
- private static Material defaultMaterial;
- private static Plane[] cameraPlanes = new Plane[6];
- private Material overrideMaterial;
- private int queueIndex = 0;
- private int lastFrame;
- private Element[] queue = new Element[DefaultQueueSize];
- /// <summary>
- /// The material being used to render
- /// </summary>
- public static Material Material
- {
- get
- {
- GizmosInstance inst = GetOrCreate();
- if (inst.overrideMaterial)
- {
- return inst.overrideMaterial;
- }
- return DefaultMaterial;
- }
- set
- {
- GizmosInstance inst = GetOrCreate();
- inst.overrideMaterial = value;
- }
- }
- /// <summary>
- /// The default line renderer material
- /// </summary>
- public static Material DefaultMaterial
- {
- get
- {
- if (!defaultMaterial)
- {
- // Unity has a built-in shader that is useful for drawing
- // simple colored things.
- Shader shader = Shader.Find("Hidden/Internal-Colored");
- defaultMaterial = new Material(shader)
- {
- hideFlags = HideFlags.HideAndDontSave
- };
- // Turn on alpha blending
- defaultMaterial.SetInt("_SrcBlend", (int)BlendMode.SrcAlpha);
- defaultMaterial.SetInt("_DstBlend", (int)BlendMode.OneMinusSrcAlpha);
- defaultMaterial.SetInt("_Cull", (int)CullMode.Off);
- defaultMaterial.SetInt("_ZWrite", 0);
- }
- return defaultMaterial;
- }
- }
- internal static GizmosInstance GetOrCreate()
- {
- if (hotReloaded || !instance)
- {
- bool markDirty = false;
- GizmosInstance[] gizmosInstances = FindObjectsOfType<GizmosInstance>();
- for (int i = 0; i < gizmosInstances.Length; i++)
- {
- instance = gizmosInstances[i];
- //destroy any extra gizmo instances
- if (i > 0)
- {
- if (Application.isPlaying)
- {
- Destroy(gizmosInstances[i]);
- }
- else
- {
- DestroyImmediate(gizmosInstances[i]);
- markDirty = true;
- }
- }
- }
- //none were found, create a new one
- if (!instance)
- {
- instance = new GameObject(typeof(GizmosInstance).FullName).AddComponent<GizmosInstance>();
- instance.gameObject.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
- markDirty = true;
- }
- #if UNITY_EDITOR
- //mark scene as dirty
- if (markDirty && !Application.isPlaying)
- {
- Scene scene = SceneManager.GetActiveScene();
- EditorSceneManager.MarkSceneDirty(scene);
- }
- #endif
- hotReloaded = false;
- }
- return instance;
- }
- private float CurrentTime
- {
- get
- {
- float time = 0f;
- if (Application.isPlaying)
- {
- time = Time.time;
- }
- else
- {
- #if UNITY_EDITOR
- time = (float)EditorApplication.timeSinceStartup;
- #endif
- }
- return time;
- }
- }
- /// <summary>
- /// Submits an array of points to draw into the queue.
- /// </summary>
- internal static void Submit(Vector3[] points, Color? color, bool dashed)
- {
- GizmosInstance inst = GetOrCreate();
- //if new frame, reset index
- if (inst.lastFrame != Time.frameCount)
- {
- inst.lastFrame = Time.frameCount;
- inst.queueIndex = 0;
- }
- //excedeed the length, so make it even bigger
- if (inst.queueIndex >= inst.queue.Length)
- {
- Element[] bigger = new Element[inst.queue.Length + DefaultQueueSize];
- for (int i = inst.queue.Length; i < bigger.Length; i++)
- {
- bigger[i] = new Element();
- }
- Array.Copy(inst.queue, 0, bigger, 0, inst.queue.Length);
- inst.queue = bigger;
- }
- inst.queue[inst.queueIndex].color = color ?? Color.white;
- inst.queue[inst.queueIndex].points = points;
- inst.queue[inst.queueIndex].dashed = dashed;
- inst.queueIndex++;
- }
- private void OnEnable()
- {
- //populate queue with empty elements
- queue = new Element[DefaultQueueSize];
- for (int i = 0; i < DefaultQueueSize; i++)
- {
- queue[i] = new Element();
- }
- if (GraphicsSettings.renderPipelineAsset == null)
- {
- Camera.onPostRender += OnRendered;
- }
- else
- {
- RenderPipelineManager.endCameraRendering += OnRendered;
- }
- }
- private void OnDisable()
- {
- if (GraphicsSettings.renderPipelineAsset == null)
- {
- Camera.onPostRender -= OnRendered;
- }
- else
- {
- RenderPipelineManager.endCameraRendering -= OnRendered;
- }
- }
- private void OnRendered(ScriptableRenderContext context, Camera camera) => OnRendered(camera);
- private bool ShouldRenderCamera(Camera camera)
- {
- if (!camera)
- {
- return false;
- }
- //allow the scene and main camera always
- bool isSceneCamera = false;
- #if UNITY_EDITOR
- SceneView sceneView = SceneView.currentDrawingSceneView;
- if (sceneView == null)
- {
- sceneView = SceneView.lastActiveSceneView;
- }
- if (sceneView != null && sceneView.camera == camera)
- {
- isSceneCamera = true;
- }
- #endif
- if (isSceneCamera || camera.CompareTag("MainCamera"))
- {
- return true;
- }
- //it passed through the filter
- if (Gizmos.CameraFilter?.Invoke(camera) == true)
- {
- return true;
- }
- return false;
- }
- private bool IsVisibleByCamera(Element points, Camera camera)
- {
- if (!camera)
- {
- return false;
- }
- //essentially check if at least 1 point is visible by the camera
- for (int i = 0; i < points.points.Length; i++)
- {
- Vector3 vp = camera.WorldToViewportPoint(points.points[i], camera.stereoActiveEye);
- if (vp.x >= 0 && vp.x <= 1 && vp.y >= 0 && vp.y <= 1)
- {
- return true;
- }
- }
- return false;
- }
- private void OnRendered(Camera camera)
- {
- //shouldnt be rendering
- if (!Gizmos.Enabled)
- {
- queueIndex = 0;
- }
- //check if this camera is ok to render with
- if (!ShouldRenderCamera(camera))
- {
- return;
- }
- Vector3 offset = Gizmos.Offset;
- Material.SetPass(Gizmos.Pass);
- GL.PushMatrix();
- GL.Begin(GL.LINES);
- bool alt = CurrentTime % 1 > 0.5f;
- float dashGap = Mathf.Clamp(Gizmos.DashGap, 0.01f, 32f);
- bool frustumCull = Gizmos.FrustumCulling;
- List<Vector3> points = new List<Vector3>();
- //draw le elements
- for (int e = 0; e < queueIndex; e++)
- {
- //just in case
- if (queue.Length <= e)
- {
- break;
- }
- Element element = queue[e];
- //dont render this thingy if its not inside the frustum
- if (frustumCull)
- {
- if (!IsVisibleByCamera(element, camera))
- {
- continue;
- }
- }
- points.Clear();
- if (element.dashed)
- {
- //subdivide
- for (int i = 0; i < element.points.Length - 1; i++)
- {
- Vector3 pointA = element.points[i];
- Vector3 pointB = element.points[i + 1];
- Vector3 direction = pointB - pointA;
- if (direction.sqrMagnitude > dashGap * dashGap * 2f)
- {
- float magnitude = direction.magnitude;
- int amount = Mathf.RoundToInt(magnitude / dashGap);
- direction /= magnitude;
- for (int p = 0; p < amount - 1; p++)
- {
- if (p % 2 == (alt ? 1 : 0))
- {
- float startLerp = p / (amount - 1f);
- float endLerp = (p + 1) / (amount - 1f);
- Vector3 start = Vector3.Lerp(pointA, pointB, startLerp);
- Vector3 end = Vector3.Lerp(pointA, pointB, endLerp);
- points.Add(start);
- points.Add(end);
- }
- }
- }
- else
- {
- points.Add(pointA);
- points.Add(pointB);
- }
- }
- }
- else
- {
- points.AddRange(element.points);
- }
- GL.Color(element.color);
- for (int i = 0; i < points.Count; i++)
- {
- GL.Vertex(points[i] + offset);
- }
- }
- GL.End();
- GL.PopMatrix();
- }
- }
- }
|