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