680 lines
27 KiB
C#
680 lines
27 KiB
C#
|
using System;
|
||
|
using UnityEditor.IMGUI.Controls;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Rendering;
|
||
|
|
||
|
namespace UnityEditor.Rendering
|
||
|
{
|
||
|
/// <summary>Utility class for drawing light Editor gizmos</summary>
|
||
|
public static class CoreLightEditorUtilities
|
||
|
{
|
||
|
[Flags]
|
||
|
enum HandleDirections
|
||
|
{
|
||
|
Left = 1 << 0,
|
||
|
Up = 1 << 1,
|
||
|
Right = 1 << 2,
|
||
|
Down = 1 << 3,
|
||
|
All = Left | Up | Right | Down
|
||
|
}
|
||
|
|
||
|
static readonly Vector3[] directionalLightHandlesRayPositions =
|
||
|
{
|
||
|
new Vector3(1, 0, 0),
|
||
|
new Vector3(-1, 0, 0),
|
||
|
new Vector3(0, 1, 0),
|
||
|
new Vector3(0, -1, 0),
|
||
|
new Vector3(1, 1, 0).normalized,
|
||
|
new Vector3(1, -1, 0).normalized,
|
||
|
new Vector3(-1, 1, 0).normalized,
|
||
|
new Vector3(-1, -1, 0).normalized
|
||
|
};
|
||
|
|
||
|
/// <summary>
|
||
|
/// Draw a gizmo for a directional light.
|
||
|
/// </summary>
|
||
|
/// <param name="light">The light that is used for this gizmo.</param>
|
||
|
public static void DrawDirectionalLightGizmo(Light light)
|
||
|
{
|
||
|
// Sets the color of the Gizmo.
|
||
|
Color outerColor = GetLightAboveObjectWireframeColor(light.color);
|
||
|
|
||
|
Vector3 lightPos = light.transform.position;
|
||
|
float lightSize;
|
||
|
using (new Handles.DrawingScope(Matrix4x4.identity)) //be sure no matrix affect the size computation
|
||
|
{
|
||
|
lightSize = HandleUtility.GetHandleSize(lightPos);
|
||
|
}
|
||
|
float radius = lightSize * 0.2f;
|
||
|
|
||
|
using (new Handles.DrawingScope(outerColor))
|
||
|
{
|
||
|
Handles.DrawWireDisc(Vector3.zero, Vector3.forward, radius);
|
||
|
foreach (Vector3 normalizedPos in directionalLightHandlesRayPositions)
|
||
|
{
|
||
|
Vector3 pos = normalizedPos * radius;
|
||
|
Handles.DrawLine(pos, pos + new Vector3(0, 0, lightSize));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Draw a gizmo for a point light.
|
||
|
/// </summary>
|
||
|
/// <param name="light">The light that is used for this gizmo.</param>
|
||
|
public static void DrawPointLightGizmo(Light light)
|
||
|
{
|
||
|
// Sets the color of the Gizmo.
|
||
|
Color outerColor = GetLightAboveObjectWireframeColor(light.color);
|
||
|
|
||
|
// Drawing the point light
|
||
|
DrawPointLight(light, outerColor);
|
||
|
|
||
|
// Draw the handles and labels
|
||
|
DrawPointHandlesAndLabels(light);
|
||
|
}
|
||
|
|
||
|
static void DrawPointLight(Light light, Color outerColor)
|
||
|
{
|
||
|
float range = light.range;
|
||
|
|
||
|
using (new Handles.DrawingScope(outerColor))
|
||
|
{
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
//range = Handles.RadiusHandle(Quaternion.identity, light.transform.position, range, false, true);
|
||
|
range = DoPointHandles(range);
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
Undo.RecordObject(light, "Adjust Point Light");
|
||
|
light.range = range;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DrawPointHandlesAndLabels(Light light)
|
||
|
{
|
||
|
// Getting the first control on point handle
|
||
|
var firstControl = GUIUtility.GetControlID(s_PointLightHandle.GetHashCode(), FocusType.Passive) - 6; // BoxBoundsHandle allocates 6 control IDs
|
||
|
if (Event.current.type != EventType.Repaint)
|
||
|
return;
|
||
|
// var firstControl = GUIUtility.GetControlID(k_RadiusHandleHash, FocusType.Passive) - 6;
|
||
|
// if (Event.current.type != EventType.Repaint)
|
||
|
// return;
|
||
|
|
||
|
// Adding label /////////////////////////////////////
|
||
|
Vector3 labelPosition = Vector3.zero;
|
||
|
|
||
|
if (GUIUtility.hotControl != 0)
|
||
|
{
|
||
|
switch (GUIUtility.hotControl - firstControl)
|
||
|
{
|
||
|
case 0:
|
||
|
labelPosition = Vector3.right * light.range;
|
||
|
break;
|
||
|
case 1:
|
||
|
labelPosition = Vector3.left * light.range;
|
||
|
break;
|
||
|
case 2:
|
||
|
labelPosition = Vector3.up * light.range;
|
||
|
break;
|
||
|
case 3:
|
||
|
labelPosition = Vector3.down * light.range;
|
||
|
break;
|
||
|
case 4:
|
||
|
labelPosition = Vector3.forward * light.range;
|
||
|
break;
|
||
|
case 5:
|
||
|
labelPosition = Vector3.back * light.range;
|
||
|
break;
|
||
|
default:
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
string labelText = FormattableString.Invariant($"Range: {light.range:0.00}");
|
||
|
DrawHandleLabel(labelPosition, labelText);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Draw a gizmo for an area/rectangle light.
|
||
|
/// </summary>
|
||
|
/// <param name="light">The light that is used for this gizmo.</param>
|
||
|
public static void DrawRectangleLightGizmo(Light light)
|
||
|
{
|
||
|
// Color to use for gizmo drawing
|
||
|
Color outerColor = GetLightAboveObjectWireframeColor(light.color);
|
||
|
|
||
|
// Drawing the gizmo
|
||
|
DrawRectangleLight(light, outerColor);
|
||
|
|
||
|
// Draw the handles and labels
|
||
|
DrawRectangleHandlesAndLabels(light);
|
||
|
}
|
||
|
|
||
|
static void DrawRectangleLight(Light light, Color outerColor)
|
||
|
{
|
||
|
Vector2 size = light.areaSize;
|
||
|
var range = light.range;
|
||
|
var innerColor = GetLightBehindObjectWireframeColor(light.color);
|
||
|
DrawZTestedLine(range, outerColor, innerColor);
|
||
|
|
||
|
using (new Handles.DrawingScope(outerColor))
|
||
|
{
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
size = DoRectHandles(size);
|
||
|
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
Undo.RecordObject(light, "Adjust Area Rectangle Light");
|
||
|
light.areaSize = size;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DrawRectangleHandlesAndLabels(Light light)
|
||
|
{
|
||
|
// Getting the first control on radius handle
|
||
|
var firstControl = GUIUtility.GetControlID(s_AreaLightHandle.GetHashCode(), FocusType.Passive) - 6; // BoxBoundsHandle allocates 6 control IDs
|
||
|
if (Event.current.type != EventType.Repaint)
|
||
|
return;
|
||
|
|
||
|
// Adding label /////////////////////////////////////
|
||
|
Vector3 labelPosition = Vector3.zero;
|
||
|
|
||
|
if (GUIUtility.hotControl != 0)
|
||
|
{
|
||
|
switch (GUIUtility.hotControl - firstControl)
|
||
|
{
|
||
|
case 0: // PositiveX
|
||
|
labelPosition = Vector3.right * (light.areaSize.x / 2);
|
||
|
break;
|
||
|
case 1: // NegativeX
|
||
|
labelPosition = Vector3.left * (light.areaSize.x / 2);
|
||
|
break;
|
||
|
case 2: // PositiveY
|
||
|
labelPosition = Vector3.up * (light.areaSize.y / 2);
|
||
|
break;
|
||
|
case 3: // NegativeY
|
||
|
labelPosition = Vector3.down * (light.areaSize.y / 2);
|
||
|
break;
|
||
|
default:
|
||
|
return;
|
||
|
}
|
||
|
string labelText = FormattableString.Invariant($"w:{light.areaSize.x:0.00} x h:{light.areaSize.y:0.00}");
|
||
|
DrawHandleLabel(labelPosition, labelText);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Draw a gizmo for a disc light.
|
||
|
/// </summary>
|
||
|
/// <param name="light">The light that is used for this gizmo.</param>
|
||
|
public static void DrawDiscLightGizmo(Light light)
|
||
|
{
|
||
|
// Color to use for gizmo drawing.
|
||
|
Color outerColor = GetLightAboveObjectWireframeColor(light.color);
|
||
|
|
||
|
// Drawing before objects
|
||
|
DrawDiscLight(light, outerColor);
|
||
|
|
||
|
// Draw handles
|
||
|
DrawDiscHandlesAndLabels(light);
|
||
|
}
|
||
|
|
||
|
static void DrawDiscLight(Light light, Color outerColor)
|
||
|
{
|
||
|
float radius = light.areaSize.x;
|
||
|
var range = light.range;
|
||
|
var innerColor = GetLightBehindObjectWireframeColor(light.color);
|
||
|
DrawZTestedLine(range, outerColor, innerColor);
|
||
|
|
||
|
using (new Handles.DrawingScope(outerColor))
|
||
|
{
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
radius = DoDiscHandles(radius);
|
||
|
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
Undo.RecordObject(light, "Adjust Area Disc Light");
|
||
|
light.areaSize = new Vector2(radius, light.areaSize.y);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DrawDiscHandlesAndLabels(Light light)
|
||
|
{
|
||
|
// Getting the first control on radius handle
|
||
|
var firstControl = GUIUtility.GetControlID(s_DiscLightHandle.GetHashCode(), FocusType.Passive) - 6; // BoxBoundsHandle allocates 6 control IDs
|
||
|
if (Event.current.type != EventType.Repaint)
|
||
|
return;
|
||
|
|
||
|
Vector3 labelPosition = Vector3.zero;
|
||
|
|
||
|
if (GUIUtility.hotControl != 0)
|
||
|
{
|
||
|
switch (GUIUtility.hotControl - firstControl)
|
||
|
{
|
||
|
case 0: // PositiveX
|
||
|
labelPosition = Vector3.right * light.areaSize.x;
|
||
|
break;
|
||
|
case 1: // NegativeX
|
||
|
labelPosition = Vector3.left * light.areaSize.x;
|
||
|
break;
|
||
|
case 2: // PositiveY
|
||
|
labelPosition = Vector3.up * light.areaSize.x;
|
||
|
break;
|
||
|
case 3: // NegativeY
|
||
|
labelPosition = Vector3.down * light.areaSize.x;
|
||
|
break;
|
||
|
default:
|
||
|
return;
|
||
|
}
|
||
|
string labelText = FormattableString.Invariant($"Radius: {light.areaSize.x:0.00}");
|
||
|
DrawHandleLabel(labelPosition, labelText);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DrawWithZTest(PrimitiveBoundsHandle primitiveHandle, float alpha = 0.2f)
|
||
|
{
|
||
|
primitiveHandle.center = Vector3.zero;
|
||
|
|
||
|
primitiveHandle.handleColor = Color.clear;
|
||
|
primitiveHandle.wireframeColor = Color.white;
|
||
|
Handles.zTest = CompareFunction.LessEqual;
|
||
|
primitiveHandle.DrawHandle();
|
||
|
|
||
|
primitiveHandle.wireframeColor = new Color(1f, 1f, 1f, alpha);
|
||
|
Handles.zTest = CompareFunction.Greater;
|
||
|
primitiveHandle.DrawHandle();
|
||
|
|
||
|
primitiveHandle.handleColor = Color.white;
|
||
|
primitiveHandle.wireframeColor = Color.clear;
|
||
|
Handles.zTest = CompareFunction.Always;
|
||
|
primitiveHandle.DrawHandle();
|
||
|
}
|
||
|
|
||
|
static void DrawZTestedLine(float range, Color outerColor, Color innerColor)
|
||
|
{
|
||
|
using (new Handles.DrawingScope(outerColor))
|
||
|
{
|
||
|
Handles.zTest = CompareFunction.LessEqual;
|
||
|
Handles.DrawLine(Vector3.zero, Vector3.forward * range);
|
||
|
}
|
||
|
using (new Handles.DrawingScope(innerColor))
|
||
|
{
|
||
|
Handles.zTest = CompareFunction.Greater;
|
||
|
Handles.DrawLine(Vector3.zero, Vector3.forward * range);
|
||
|
}
|
||
|
Handles.zTest = CompareFunction.Always;
|
||
|
}
|
||
|
|
||
|
static void DrawHandleLabel(Vector3 handlePosition, string labelText, float offsetFromHandle = 0.3f)
|
||
|
{
|
||
|
Vector3 labelPosition = Vector3.zero;
|
||
|
|
||
|
var style = new GUIStyle { normal = { background = Texture2D.whiteTexture } };
|
||
|
GUI.color = new Color(0.82f, 0.82f, 0.82f, 1);
|
||
|
|
||
|
labelPosition = handlePosition + Handles.inverseMatrix.MultiplyVector(Vector3.up) * HandleUtility.GetHandleSize(handlePosition) * offsetFromHandle;
|
||
|
Handles.Label(labelPosition, labelText, style);
|
||
|
}
|
||
|
|
||
|
static readonly BoxBoundsHandle s_AreaLightHandle =
|
||
|
new BoxBoundsHandle { axes = PrimitiveBoundsHandle.Axes.X | PrimitiveBoundsHandle.Axes.Y };
|
||
|
|
||
|
static Vector2 DoRectHandles(Vector2 size)
|
||
|
{
|
||
|
s_AreaLightHandle.center = Vector3.zero;
|
||
|
s_AreaLightHandle.size = size;
|
||
|
DrawWithZTest(s_AreaLightHandle);
|
||
|
|
||
|
return s_AreaLightHandle.size;
|
||
|
}
|
||
|
|
||
|
static readonly SphereBoundsHandle s_DiscLightHandle =
|
||
|
new SphereBoundsHandle { axes = PrimitiveBoundsHandle.Axes.X | PrimitiveBoundsHandle.Axes.Y };
|
||
|
static float DoDiscHandles(float radius)
|
||
|
{
|
||
|
s_DiscLightHandle.center = Vector3.zero;
|
||
|
s_DiscLightHandle.radius = radius;
|
||
|
DrawWithZTest(s_DiscLightHandle);
|
||
|
|
||
|
return s_DiscLightHandle.radius;
|
||
|
}
|
||
|
|
||
|
static readonly SphereBoundsHandle s_PointLightHandle =
|
||
|
new SphereBoundsHandle { axes = PrimitiveBoundsHandle.Axes.All };
|
||
|
|
||
|
static float DoPointHandles(float range)
|
||
|
{
|
||
|
s_PointLightHandle.radius = range;
|
||
|
DrawWithZTest(s_PointLightHandle);
|
||
|
|
||
|
return s_PointLightHandle.radius;
|
||
|
}
|
||
|
|
||
|
static bool drawInnerConeAngle = true;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Draw a gizmo for a spot light.
|
||
|
/// </summary>
|
||
|
/// <param name="light">The light that is used for this gizmo.</param>
|
||
|
public static void DrawSpotLightGizmo(Light light)
|
||
|
{
|
||
|
// Saving the default colors
|
||
|
var defColor = Handles.color;
|
||
|
var defZTest = Handles.zTest;
|
||
|
|
||
|
// Default Color for outer cone will be Yellow if nothing has been provided.
|
||
|
Color outerColor = GetLightAboveObjectWireframeColor(light.color);
|
||
|
|
||
|
// The default z-test outer color will be 20% opacity of the outer color
|
||
|
Color outerColorZTest = GetLightBehindObjectWireframeColor(outerColor);
|
||
|
|
||
|
// Default Color for inner cone will be Yellow-ish if nothing has been provided.
|
||
|
Color innerColor = GetLightInnerConeColor(light.color);
|
||
|
|
||
|
// The default z-test outer color will be 20% opacity of the inner color
|
||
|
Color innerColorZTest = GetLightBehindObjectWireframeColor(innerColor);
|
||
|
|
||
|
// Drawing before objects
|
||
|
Handles.zTest = CompareFunction.LessEqual;
|
||
|
DrawSpotlightWireframe(light, outerColor, innerColor);
|
||
|
|
||
|
// Drawing behind objects
|
||
|
Handles.zTest = CompareFunction.Greater;
|
||
|
DrawSpotlightWireframe(light, outerColorZTest, innerColorZTest);
|
||
|
|
||
|
// Resets the compare function to always
|
||
|
Handles.zTest = CompareFunction.Always;
|
||
|
|
||
|
// Draw handles
|
||
|
if (!Event.current.alt)
|
||
|
{
|
||
|
DrawHandlesAndLabels(light, outerColor);
|
||
|
}
|
||
|
|
||
|
// Resets the handle colors
|
||
|
Handles.color = defColor;
|
||
|
Handles.zTest = defZTest;
|
||
|
}
|
||
|
|
||
|
static void DrawHandlesAndLabels(Light light, Color color)
|
||
|
{
|
||
|
// Zero position vector3
|
||
|
Vector3 zeroPos = Vector3.zero;
|
||
|
|
||
|
// Variable for which direction to draw the handles
|
||
|
HandleDirections DrawHandleDirections;
|
||
|
|
||
|
// Draw the handles ///////////////////////////////
|
||
|
Handles.color = color;
|
||
|
|
||
|
// Draw Center Handle
|
||
|
float range = light.range;
|
||
|
var id = GUIUtility.GetControlID(FocusType.Passive);
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
range = SliderLineHandle(id, Vector3.zero, Vector3.forward, range, "Range: ");
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
Undo.RecordObjects(new[] { light }, "Undo range change.");
|
||
|
}
|
||
|
|
||
|
// Draw outer handles
|
||
|
DrawHandleDirections = HandleDirections.Down | HandleDirections.Up;
|
||
|
const string outerLabel = "Outer Angle: ";
|
||
|
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
float outerAngle = DrawConeHandles(zeroPos, light.spotAngle, range, DrawHandleDirections, outerLabel);
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
Undo.RecordObjects(new[] { light }, "Undo outer angle change.");
|
||
|
}
|
||
|
|
||
|
// Draw inner handles
|
||
|
float innerAngle = 0;
|
||
|
const string innerLabel = "Inner Angle: ";
|
||
|
if (light.innerSpotAngle > 0f && drawInnerConeAngle)
|
||
|
{
|
||
|
DrawHandleDirections = HandleDirections.Left | HandleDirections.Right;
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
innerAngle = DrawConeHandles(zeroPos, light.innerSpotAngle, range, DrawHandleDirections, innerLabel);
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
Undo.RecordObjects(new[] { light }, "Undo inner angle change.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Draw Near Plane Handle
|
||
|
float nearPlaneRange = light.shadowNearPlane;
|
||
|
if (light.shadows != LightShadows.None && light.lightmapBakeType != LightmapBakeType.Baked)
|
||
|
{
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
nearPlaneRange = SliderLineHandle(GUIUtility.GetControlID(FocusType.Passive), Vector3.zero, Vector3.forward, nearPlaneRange, "Near Plane: ");
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
Undo.RecordObjects(new[] { light }, "Undo shadow near plane change.");
|
||
|
nearPlaneRange = Mathf.Clamp(nearPlaneRange, 0.1f, light.range);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If changes has been made we update the corresponding property
|
||
|
if (GUI.changed)
|
||
|
{
|
||
|
light.spotAngle = outerAngle;
|
||
|
light.innerSpotAngle = innerAngle;
|
||
|
light.range = Math.Max(range, 0.01f);
|
||
|
light.shadowNearPlane = Mathf.Clamp(nearPlaneRange, 0.1f, light.range);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static Color GetLightInnerConeColor(Color wireframeColor)
|
||
|
{
|
||
|
Color color = wireframeColor;
|
||
|
color.a = 0.4f;
|
||
|
return RemapLightColor(CoreUtils.ConvertLinearToActiveColorSpace(color.linear));
|
||
|
}
|
||
|
|
||
|
static Color GetLightAboveObjectWireframeColor(Color wireframeColor)
|
||
|
{
|
||
|
Color color = wireframeColor;
|
||
|
color.a = 1f;
|
||
|
return RemapLightColor(CoreUtils.ConvertLinearToActiveColorSpace(color.linear));
|
||
|
}
|
||
|
|
||
|
static Color GetLightBehindObjectWireframeColor(Color wireframeColor)
|
||
|
{
|
||
|
Color color = wireframeColor;
|
||
|
color.a = 0.2f;
|
||
|
return RemapLightColor(CoreUtils.ConvertLinearToActiveColorSpace(color.linear));
|
||
|
}
|
||
|
|
||
|
static Color RemapLightColor(Color src)
|
||
|
{
|
||
|
Color color = src;
|
||
|
float max = Mathf.Max(Mathf.Max(color.r, color.g), color.b);
|
||
|
if (max > 0f)
|
||
|
{
|
||
|
float mult = 1f / max;
|
||
|
color.r *= mult;
|
||
|
color.g *= mult;
|
||
|
color.b *= mult;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
color = Color.white;
|
||
|
}
|
||
|
|
||
|
return color;
|
||
|
}
|
||
|
|
||
|
static void DrawSpotlightWireframe(Light spotlight, Color outerColor, Color innerColor)
|
||
|
{
|
||
|
// Variable for which direction to draw the handles
|
||
|
HandleDirections DrawHandleDirections;
|
||
|
|
||
|
float outerAngle = spotlight.spotAngle;
|
||
|
float innerAngle = spotlight.innerSpotAngle;
|
||
|
float range = spotlight.range;
|
||
|
|
||
|
var outerDiscRadius = range * Mathf.Sin(outerAngle * Mathf.Deg2Rad * 0.5f);
|
||
|
var outerDiscDistance = Mathf.Cos(Mathf.Deg2Rad * outerAngle * 0.5f) * range;
|
||
|
var vectorLineUp = Vector3.Normalize(Vector3.forward * outerDiscDistance + Vector3.up * outerDiscRadius);
|
||
|
var vectorLineLeft = Vector3.Normalize(Vector3.forward * outerDiscDistance + Vector3.left * outerDiscRadius);
|
||
|
|
||
|
// Need to check if we need to draw inner angle
|
||
|
// Need to disable this for now until we get all the inner angle baking working.
|
||
|
if (innerAngle > 0f && drawInnerConeAngle)
|
||
|
{
|
||
|
DrawHandleDirections = HandleDirections.Up | HandleDirections.Down;
|
||
|
var innerDiscRadius = range * Mathf.Sin(innerAngle * Mathf.Deg2Rad * 0.5f);
|
||
|
var innerDiscDistance = Mathf.Cos(Mathf.Deg2Rad * innerAngle * 0.5f) * range;
|
||
|
|
||
|
// Drawing the inner Cone and also z-testing it to draw another color if behind
|
||
|
Handles.color = innerColor;
|
||
|
DrawConeWireframe(innerDiscRadius, innerDiscDistance, DrawHandleDirections);
|
||
|
}
|
||
|
|
||
|
// Draw range line
|
||
|
Handles.color = innerColor;
|
||
|
var rangeCenter = Vector3.forward * range;
|
||
|
Handles.DrawLine(Vector3.zero, rangeCenter);
|
||
|
|
||
|
// Drawing the outer Cone and also z-testing it to draw another color if behind
|
||
|
Handles.color = outerColor;
|
||
|
|
||
|
DrawHandleDirections = HandleDirections.Left | HandleDirections.Right;
|
||
|
DrawConeWireframe(outerDiscRadius, outerDiscDistance, DrawHandleDirections);
|
||
|
|
||
|
// Bottom arcs, making a nice rounded shape
|
||
|
Handles.DrawWireArc(Vector3.zero, Vector3.right, vectorLineUp, outerAngle, range);
|
||
|
Handles.DrawWireArc(Vector3.zero, Vector3.up, vectorLineLeft, outerAngle, range);
|
||
|
|
||
|
// If we are using shadows we draw the near plane for shadows
|
||
|
if (spotlight.shadows != LightShadows.None && spotlight.lightmapBakeType != LightmapBakeType.Baked)
|
||
|
{
|
||
|
DrawShadowNearPlane(spotlight, innerColor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DrawShadowNearPlane(Light spotlight, Color color)
|
||
|
{
|
||
|
Color previousColor = Handles.color;
|
||
|
Handles.color = color;
|
||
|
|
||
|
var shadowDiscRadius = Mathf.Tan(spotlight.spotAngle * Mathf.Deg2Rad * 0.5f) * spotlight.shadowNearPlane;
|
||
|
var shadowDiscDistance = spotlight.shadowNearPlane;
|
||
|
Handles.DrawWireDisc(Vector3.forward * shadowDiscDistance, Vector3.forward, shadowDiscRadius);
|
||
|
Handles.DrawLine(Vector3.forward * shadowDiscDistance, (Vector3.right * shadowDiscRadius) + (Vector3.forward * shadowDiscDistance));
|
||
|
Handles.DrawLine(Vector3.forward * shadowDiscDistance, (-Vector3.right * shadowDiscRadius) + (Vector3.forward * shadowDiscDistance));
|
||
|
|
||
|
Handles.color = previousColor;
|
||
|
}
|
||
|
|
||
|
static void DrawConeWireframe(float radius, float height, HandleDirections handleDirections)
|
||
|
{
|
||
|
var rangeCenter = Vector3.forward * height;
|
||
|
if (handleDirections.HasFlag(HandleDirections.Up))
|
||
|
{
|
||
|
var rangeUp = rangeCenter + Vector3.up * radius;
|
||
|
Handles.DrawLine(Vector3.zero, rangeUp);
|
||
|
}
|
||
|
|
||
|
if (handleDirections.HasFlag(HandleDirections.Down))
|
||
|
{
|
||
|
var rangeDown = rangeCenter - Vector3.up * radius;
|
||
|
Handles.DrawLine(Vector3.zero, rangeDown);
|
||
|
}
|
||
|
|
||
|
if (handleDirections.HasFlag(HandleDirections.Right))
|
||
|
{
|
||
|
var rangeRight = rangeCenter + Vector3.right * radius;
|
||
|
Handles.DrawLine(Vector3.zero, rangeRight);
|
||
|
}
|
||
|
|
||
|
if (handleDirections.HasFlag(HandleDirections.Left))
|
||
|
{
|
||
|
var rangeLeft = rangeCenter - Vector3.right * radius;
|
||
|
Handles.DrawLine(Vector3.zero, rangeLeft);
|
||
|
}
|
||
|
|
||
|
//Draw Circle
|
||
|
Handles.DrawWireDisc(rangeCenter, Vector3.forward, radius);
|
||
|
}
|
||
|
|
||
|
static float DrawConeHandles(Vector3 position, float angle, float range, HandleDirections handleDirections, string controlName)
|
||
|
{
|
||
|
if (handleDirections.HasFlag(HandleDirections.Left))
|
||
|
{
|
||
|
angle = SizeSliderSpotAngle(position, Vector3.forward, -Vector3.right, range, angle, controlName);
|
||
|
}
|
||
|
if (handleDirections.HasFlag(HandleDirections.Up))
|
||
|
{
|
||
|
angle = SizeSliderSpotAngle(position, Vector3.forward, Vector3.up, range, angle, controlName);
|
||
|
}
|
||
|
if (handleDirections.HasFlag(HandleDirections.Right))
|
||
|
{
|
||
|
angle = SizeSliderSpotAngle(position, Vector3.forward, Vector3.right, range, angle, controlName);
|
||
|
}
|
||
|
if (handleDirections.HasFlag(HandleDirections.Down))
|
||
|
{
|
||
|
angle = SizeSliderSpotAngle(position, Vector3.forward, -Vector3.up, range, angle, controlName);
|
||
|
}
|
||
|
return angle;
|
||
|
}
|
||
|
|
||
|
static float SliderLineHandle(int id, Vector3 position, Vector3 direction, float value, string labelText = "")
|
||
|
{
|
||
|
Vector3 pos = position + direction * value;
|
||
|
float sizeHandle = HandleUtility.GetHandleSize(pos);
|
||
|
bool temp = GUI.changed;
|
||
|
GUI.changed = false;
|
||
|
pos = Handles.Slider(id, pos, direction, sizeHandle * 0.03f, Handles.DotHandleCap, 0f);
|
||
|
if (GUI.changed)
|
||
|
{
|
||
|
value = Vector3.Dot(pos - position, direction);
|
||
|
}
|
||
|
GUI.changed |= temp;
|
||
|
|
||
|
if (GUIUtility.hotControl == id && !String.IsNullOrEmpty(labelText))
|
||
|
{
|
||
|
labelText += FormattableString.Invariant($"{value:0.00}");
|
||
|
DrawHandleLabel(pos, labelText);
|
||
|
}
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
static float SizeSliderSpotAngle(Vector3 position, Vector3 forward, Vector3 axis, float range, float spotAngle, string controlName)
|
||
|
{
|
||
|
if (Math.Abs(spotAngle) <= 0.05f)
|
||
|
return spotAngle;
|
||
|
var angledForward = Quaternion.AngleAxis(Mathf.Max(spotAngle, 0.05f) * 0.5f, axis) * forward;
|
||
|
var centerToLeftOnSphere = (angledForward * range + position) - (position + forward * range);
|
||
|
bool temp = GUI.changed;
|
||
|
GUI.changed = false;
|
||
|
var handlePosition = position + forward * range;
|
||
|
var id = GUIUtility.GetControlID(FocusType.Passive);
|
||
|
var newMagnitude = Mathf.Max(0f, SliderLineHandle(id, handlePosition, centerToLeftOnSphere.normalized, centerToLeftOnSphere.magnitude));
|
||
|
if (GUI.changed)
|
||
|
{
|
||
|
centerToLeftOnSphere = centerToLeftOnSphere.normalized * newMagnitude;
|
||
|
angledForward = (centerToLeftOnSphere + (position + forward * range) - position).normalized;
|
||
|
spotAngle = Mathf.Clamp(Mathf.Acos(Vector3.Dot(forward, angledForward)) * Mathf.Rad2Deg * 2, 0f, 179f);
|
||
|
if (spotAngle <= 0.05f || float.IsNaN(spotAngle))
|
||
|
spotAngle = 0f;
|
||
|
}
|
||
|
GUI.changed |= temp;
|
||
|
|
||
|
if (GUIUtility.hotControl == id)
|
||
|
{
|
||
|
var pos = handlePosition + centerToLeftOnSphere.normalized * newMagnitude;
|
||
|
string labelText = FormattableString.Invariant($"{controlName} {spotAngle:0.00}");
|
||
|
DrawHandleLabel(pos, labelText);
|
||
|
}
|
||
|
|
||
|
return spotAngle;
|
||
|
}
|
||
|
}
|
||
|
}
|