HierarchicalSphere.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using UnityEngine;
  2. namespace UnityEditor.Rendering
  3. {
  4. /// <summary>
  5. /// Provide a gizmo/handle representing a box where all face can be moved independently.
  6. /// Also add a contained sub gizmo/handle box if contained is used at creation.
  7. /// </summary>
  8. /// <example>
  9. /// <code>
  10. /// class MyComponentEditor : Editor
  11. /// {
  12. /// static HierarchicalSphere sphere;
  13. /// static HierarchicalSphere containedSphere;
  14. ///
  15. /// static MyComponentEditor()
  16. /// {
  17. /// Color[] handleColors = new Color[]
  18. /// {
  19. /// Color.red,
  20. /// Color.green,
  21. /// Color.Blue,
  22. /// new Color(0.5f, 0f, 0f, 1f),
  23. /// new Color(0f, 0.5f, 0f, 1f),
  24. /// new Color(0f, 0f, 0.5f, 1f)
  25. /// };
  26. /// sphere = new HierarchicalSphere(new Color(1f, 1f, 1f, 0.25));
  27. /// containedSphere = new HierarchicalSphere(new Color(1f, 0f, 1f, 0.25), container: sphere);
  28. /// }
  29. ///
  30. /// [DrawGizmo(GizmoType.Selected|GizmoType.Active)]
  31. /// void DrawGizmo(MyComponent comp, GizmoType gizmoType)
  32. /// {
  33. /// sphere.center = comp.transform.position;
  34. /// sphere.size = comp.transform.scale;
  35. /// sphere.DrawHull(gizmoType == GizmoType.Selected);
  36. ///
  37. /// containedSphere.center = comp.innerposition;
  38. /// containedSphere.size = comp.innerScale;
  39. /// containedSphere.DrawHull(gizmoType == GizmoType.Selected);
  40. /// }
  41. ///
  42. /// void OnSceneGUI()
  43. /// {
  44. /// EditorGUI.BeginChangeCheck();
  45. ///
  46. /// //container sphere must be also set for contained sphere for clamping
  47. /// sphere.center = comp.transform.position;
  48. /// sphere.size = comp.transform.scale;
  49. /// sphere.DrawHandle();
  50. ///
  51. /// containedSphere.center = comp.innerposition;
  52. /// containedSphere.size = comp.innerScale;
  53. /// containedSphere.DrawHandle();
  54. ///
  55. /// if(EditorGUI.EndChangeCheck())
  56. /// {
  57. /// comp.innerposition = containedSphere.center;
  58. /// comp.innersize = containedSphere.size;
  59. /// }
  60. /// }
  61. /// }
  62. /// </code>
  63. /// </example>
  64. public class HierarchicalSphere
  65. {
  66. const float k_HandleSizeCoef = 0.05f;
  67. static Material k_Material_Cache;
  68. static Material k_Material => (k_Material_Cache == null || k_Material_Cache.Equals(null) ? (k_Material_Cache = new Material(Shader.Find("Hidden/UnlitTransparentColored"))) : k_Material_Cache);
  69. static Mesh k_MeshSphere_Cache;
  70. static Mesh k_MeshSphere => k_MeshSphere_Cache == null || k_MeshSphere_Cache.Equals(null) ? (k_MeshSphere_Cache = Resources.GetBuiltinResource<Mesh>("New-Sphere.fbx")) : k_MeshSphere_Cache;
  71. Material m_Material;
  72. readonly HierarchicalSphere m_Parent;
  73. Color m_HandleColor;
  74. Color m_WireframeColor;
  75. Color m_WireframeColorBehind;
  76. Material material => m_Material == null || m_Material.Equals(null)
  77. ? (m_Material = new Material(k_Material))
  78. : m_Material;
  79. /// <summary>The position of the center of the box in Handle.matrix space.</summary>
  80. public Vector3 center { get; set; }
  81. /// <summary>The size of the box in Handle.matrix space.</summary>
  82. public float radius { get; set; }
  83. /// <summary>The baseColor used to fill hull. All other colors are deduced from it.</summary>
  84. public Color baseColor
  85. {
  86. get { return material.color; }
  87. set
  88. {
  89. value.a = 8f / 255;
  90. material.color = value;
  91. value.a = 1f;
  92. m_HandleColor = value;
  93. value.a = 0.7f;
  94. m_WireframeColor = value;
  95. value.a = 0.2f;
  96. m_WireframeColorBehind = value;
  97. }
  98. }
  99. /// <summary>Constructor. Used to setup colors and also the container if any.</summary>
  100. /// <param name="baseColor">The color of filling. All other colors are deduced from it.</param>
  101. /// <param name="parent">The HierarchicalSphere containing this sphere. If null, the sphere will not be limited in size.</param>
  102. public HierarchicalSphere(Color baseColor, HierarchicalSphere parent = null)
  103. {
  104. m_Parent = parent;
  105. m_Material = new Material(k_Material);
  106. this.baseColor = baseColor;
  107. }
  108. /// <summary>Draw the hull which means the boxes without the handles</summary>
  109. /// <param name="filled">If true, also draw the surface of the hull's sphere</param>
  110. public void DrawHull(bool filled)
  111. {
  112. Color wireframeColor = m_HandleColor;
  113. wireframeColor.a = 0.8f;
  114. using (new Handles.DrawingScope(m_WireframeColor, Matrix4x4.TRS((Vector3)Handles.matrix.GetColumn(3) + center, Quaternion.identity, Vector3.one)))
  115. {
  116. if (filled)
  117. {
  118. material.SetPass(0);
  119. Matrix4x4 drawMatrix = Matrix4x4.TRS((Vector3)Handles.matrix.GetColumn(3), Quaternion.identity, Vector3.one * radius * 2f);
  120. Graphics.DrawMeshNow(k_MeshSphere, drawMatrix);
  121. }
  122. var drawCenter = Vector3.zero;
  123. var viewPlaneNormal = Vector3.zero;
  124. var drawnRadius = radius;
  125. if (Camera.current.orthographic)
  126. viewPlaneNormal = Camera.current.transform.forward;
  127. else
  128. {
  129. viewPlaneNormal = (Vector3)Handles.matrix.GetColumn(3) - Camera.current.transform.position;
  130. var sqrDist = viewPlaneNormal.sqrMagnitude; // squared distance from camera to center
  131. var sqrRadius = radius * radius; // squared radius
  132. var sqrOffset = sqrRadius * sqrRadius / sqrDist; // squared distance from actual center to drawn disc center
  133. var insideAmount = sqrOffset / sqrRadius;
  134. // If we are not inside the sphere, calculate where to draw the periphery
  135. if (insideAmount < 1)
  136. {
  137. drawnRadius = Mathf.Sqrt(sqrRadius - sqrOffset); // the radius of the drawn disc
  138. drawCenter -= (sqrRadius / sqrDist) * viewPlaneNormal;
  139. }
  140. }
  141. Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
  142. Handles.DrawWireDisc(Vector3.zero, Vector3.up, radius);
  143. Handles.DrawWireDisc(drawCenter, viewPlaneNormal, drawnRadius);
  144. Handles.color = m_WireframeColorBehind;
  145. Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
  146. Handles.DrawWireDisc(Vector3.zero, Vector3.up, radius);
  147. Handles.DrawWireDisc(drawCenter, viewPlaneNormal, drawnRadius);
  148. Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  149. }
  150. }
  151. /// <summary>Draw the manipulable handles</summary>
  152. public void DrawHandle()
  153. {
  154. using (new Handles.DrawingScope(m_HandleColor))
  155. {
  156. radius = Handles.RadiusHandle(Quaternion.identity, center, radius, handlesOnly: true);
  157. if(m_Parent != null)
  158. radius = Mathf.Min(radius, m_Parent.radius - Vector3.Distance(center, m_Parent.center));
  159. }
  160. }
  161. }
  162. }