forked from BilalY/Rasagar
823 lines
42 KiB
C#
823 lines
42 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Rendering.HighDefinition;
|
|
using UnityEngine.Rendering;
|
|
using System;
|
|
|
|
namespace UnityEditor.Rendering.HighDefinition
|
|
{
|
|
partial class HDLightUI
|
|
{
|
|
#region HDRPOnlyPreviouslyInCoreThatNeedRewrite
|
|
// All this region was in CoreLightEditorUtilities
|
|
// We must change the light gizmo to matches Universal ones
|
|
// This was public API but we do not want it public as it need to be rewritten
|
|
|
|
static Color GetLightHandleColor(Color wireframeColor)
|
|
{
|
|
Color color = wireframeColor;
|
|
color.a = Mathf.Clamp01(color.a * 2);
|
|
return (QualitySettings.activeColorSpace == ColorSpace.Linear) ? color.linear : color;
|
|
}
|
|
|
|
//copy of CoreLightEditorUtilities
|
|
static Color GetLightBehindObjectWireframeColor(Color wireframeColor)
|
|
{
|
|
Color color = wireframeColor;
|
|
color.a = 0.2f;
|
|
return RemapLightColor(UnityEngine.Rendering.CoreUtils.ConvertLinearToActiveColorSpace(color.linear));
|
|
}
|
|
|
|
//copy of CoreLightEditorUtilities
|
|
|
|
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;
|
|
}
|
|
|
|
//copy of CoreLightEditorUtilities
|
|
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 + HandleUtility.GetHandleSize(handlePosition) * offsetFromHandle * Handles.inverseMatrix.MultiplyVector(Vector3.up);
|
|
Handles.Label(labelPosition, labelText, style);
|
|
}
|
|
|
|
//copy of CoreLightEditorUtilities
|
|
static float SliderLineHandle(Vector3 position, Vector3 direction, float value)
|
|
{
|
|
return SliderLineHandle(GUIUtility.GetControlID(FocusType.Passive), position, direction, value, "");
|
|
}
|
|
|
|
//copy of CoreLightEditorUtilities
|
|
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;
|
|
}
|
|
|
|
//copy of CoreLightEditorUtilities
|
|
static Vector2 SliderPlaneHandle(Vector3 origin, Vector3 axis1, Vector3 axis2, Vector2 position)
|
|
{
|
|
Vector3 pos = origin + position.x * axis1 + position.y * axis2;
|
|
float sizeHandle = HandleUtility.GetHandleSize(pos);
|
|
bool temp = GUI.changed;
|
|
GUI.changed = false;
|
|
pos = Handles.Slider2D(pos, Vector3.forward, axis1, axis2, sizeHandle * 0.03f, Handles.DotHandleCap, 0f);
|
|
if (GUI.changed)
|
|
{
|
|
position = new Vector2(Vector3.Dot(pos, axis1), Vector3.Dot(pos, axis2));
|
|
}
|
|
GUI.changed |= temp;
|
|
return position;
|
|
}
|
|
|
|
//copy of CoreLightEditorUtilities
|
|
static float SizeSliderSpotAngle(Vector3 position, Vector3 forward, Vector3 axis, float range, float spotAngle, string controlName)
|
|
{
|
|
if (Mathf.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;
|
|
}
|
|
|
|
//TODO: decompose arguments (or tuples) + put back to CoreLightEditorUtilities
|
|
static Vector3 DrawSpotlightHandle(Vector3 outerAngleInnerAngleRange)
|
|
{
|
|
float outerAngle = outerAngleInnerAngleRange.x;
|
|
float innerAngle = outerAngleInnerAngleRange.y;
|
|
float range = outerAngleInnerAngleRange.z;
|
|
|
|
if (innerAngle > 0f)
|
|
{
|
|
innerAngle = SizeSliderSpotAngle(Vector3.zero, Vector3.forward, Vector3.right, range, innerAngle, String.Empty);
|
|
innerAngle = SizeSliderSpotAngle(Vector3.zero, Vector3.forward, Vector3.left, range, innerAngle, String.Empty);
|
|
innerAngle = SizeSliderSpotAngle(Vector3.zero, Vector3.forward, Vector3.up, range, innerAngle, String.Empty);
|
|
innerAngle = SizeSliderSpotAngle(Vector3.zero, Vector3.forward, Vector3.down, range, innerAngle, String.Empty);
|
|
}
|
|
|
|
outerAngle = SizeSliderSpotAngle(Vector3.zero, Vector3.forward, Vector3.right, range, outerAngle, String.Empty);
|
|
outerAngle = SizeSliderSpotAngle(Vector3.zero, Vector3.forward, Vector3.left, range, outerAngle, String.Empty);
|
|
outerAngle = SizeSliderSpotAngle(Vector3.zero, Vector3.forward, Vector3.up, range, outerAngle, String.Empty);
|
|
outerAngle = SizeSliderSpotAngle(Vector3.zero, Vector3.forward, Vector3.down, range, outerAngle, String.Empty);
|
|
|
|
range = SliderLineHandle(Vector3.zero, Vector3.forward, range);
|
|
|
|
return new Vector3(outerAngle, innerAngle, range);
|
|
}
|
|
|
|
//TODO: decompose arguments (or tuples) + put back to CoreLightEditorUtilities
|
|
static void DrawSpotlightWireframe(Vector3 outerAngleInnerAngleRange, float shadowPlaneDistance = -1f)
|
|
{
|
|
float outerAngle = outerAngleInnerAngleRange.x;
|
|
float innerAngle = outerAngleInnerAngleRange.y;
|
|
float range = outerAngleInnerAngleRange.z;
|
|
|
|
|
|
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);
|
|
|
|
if (innerAngle > 0f)
|
|
{
|
|
var innerDiscRadius = range * Mathf.Sin(innerAngle * Mathf.Deg2Rad * 0.5f);
|
|
var innerDiscDistance = Mathf.Cos(Mathf.Deg2Rad * innerAngle * 0.5f) * range;
|
|
DrawConeWireframe(innerDiscRadius, innerDiscDistance);
|
|
}
|
|
DrawConeWireframe(outerDiscRadius, outerDiscDistance);
|
|
Handles.DrawWireArc(Vector3.zero, Vector3.right, vectorLineUp, outerAngle, range);
|
|
Handles.DrawWireArc(Vector3.zero, Vector3.up, vectorLineLeft, outerAngle, range);
|
|
|
|
if (shadowPlaneDistance > 0)
|
|
{
|
|
var shadowDiscRadius = shadowPlaneDistance * Mathf.Tan(outerAngle * Mathf.Deg2Rad * 0.5f);
|
|
Handles.DrawWireDisc(Vector3.forward * shadowPlaneDistance, Vector3.forward, shadowDiscRadius);
|
|
}
|
|
}
|
|
|
|
static void DrawConeWireframe(float radius, float height)
|
|
{
|
|
var rangeCenter = Vector3.forward * height;
|
|
var rangeUp = rangeCenter + Vector3.up * radius;
|
|
var rangeDown = rangeCenter - Vector3.up * radius;
|
|
var rangeRight = rangeCenter + Vector3.right * radius;
|
|
var rangeLeft = rangeCenter - Vector3.right * radius;
|
|
|
|
//Draw Lines
|
|
Handles.DrawLine(Vector3.zero, rangeUp);
|
|
Handles.DrawLine(Vector3.zero, rangeDown);
|
|
Handles.DrawLine(Vector3.zero, rangeRight);
|
|
Handles.DrawLine(Vector3.zero, rangeLeft);
|
|
|
|
Handles.DrawWireDisc(Vector3.forward * height, Vector3.forward, radius);
|
|
}
|
|
|
|
//TODO: decompose arguments (or tuples) + put back to CoreLightEditorUtilities
|
|
static void DrawAreaLightWireframe(Vector2 rectangleSize)
|
|
{
|
|
Handles.DrawWireCube(Vector3.zero, rectangleSize);
|
|
}
|
|
|
|
//TODO: decompose arguments (or tuples) + put back to CoreLightEditorUtilities
|
|
static Vector2 DrawAreaLightHandle(Vector2 rectangleSize, bool withYAxis)
|
|
{
|
|
float halfWidth = rectangleSize.x * 0.5f;
|
|
float halfHeight = rectangleSize.y * 0.5f;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
halfWidth = SliderLineHandle(Vector3.zero, Vector3.right, halfWidth);
|
|
halfWidth = SliderLineHandle(Vector3.zero, Vector3.left, halfWidth);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
halfWidth = Mathf.Max(0f, halfWidth);
|
|
}
|
|
|
|
if (withYAxis)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
halfHeight = SliderLineHandle(Vector3.zero, Vector3.up, halfHeight);
|
|
halfHeight = SliderLineHandle(Vector3.zero, Vector3.down, halfHeight);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
halfHeight = Mathf.Max(0f, halfHeight);
|
|
}
|
|
}
|
|
|
|
return new Vector2(halfWidth * 2f, halfHeight * 2f);
|
|
}
|
|
|
|
//copy of CoreLightEditorUtilities
|
|
static Vector3[] GetFrustrumProjectedRectAngles(float distance, float aspect, float tanFOV)
|
|
{
|
|
Vector3 sizeX;
|
|
Vector3 sizeY;
|
|
float minXYTruncSize = distance * tanFOV;
|
|
if (aspect >= 1.0f)
|
|
{
|
|
sizeX = new Vector3(minXYTruncSize * aspect, 0, 0);
|
|
sizeY = new Vector3(0, minXYTruncSize, 0);
|
|
}
|
|
else
|
|
{
|
|
sizeX = new Vector3(minXYTruncSize, 0, 0);
|
|
sizeY = new Vector3(0, minXYTruncSize / aspect, 0);
|
|
}
|
|
Vector3 center = new Vector3(0, 0, distance);
|
|
Vector3[] angles =
|
|
{
|
|
center + sizeX + sizeY,
|
|
center - sizeX + sizeY,
|
|
center - sizeX - sizeY,
|
|
center + sizeX - sizeY
|
|
};
|
|
|
|
return angles;
|
|
}
|
|
|
|
//TODO: decompose arguments (or tuples) + put back to CoreLightEditorUtilities
|
|
// Same as Gizmo.DrawFrustum except that when aspect is below one, fov represent fovX instead of fovY
|
|
// Use to match our light frustum pyramid behavior
|
|
static void DrawSpherePortionWireframe(Vector4 aspectFovMaxRangeMinRange, float distanceTruncPlane = 0f, bool drawApex = true)
|
|
{
|
|
float aspect = aspectFovMaxRangeMinRange.x;
|
|
float fov = aspectFovMaxRangeMinRange.y;
|
|
float maxRange = aspectFovMaxRangeMinRange.z;
|
|
float minRange = aspectFovMaxRangeMinRange.w;
|
|
float tanfov = Mathf.Tan(Mathf.Deg2Rad * fov * 0.5f);
|
|
|
|
var startAngles = new Vector3[4];
|
|
if (minRange > 0f)
|
|
{
|
|
startAngles = GetFrustrumProjectedRectAngles(minRange, aspect, tanfov);
|
|
Handles.DrawLine(startAngles[0], startAngles[1]);
|
|
Handles.DrawLine(startAngles[1], startAngles[2]);
|
|
Handles.DrawLine(startAngles[2], startAngles[3]);
|
|
Handles.DrawLine(startAngles[3], startAngles[0]);
|
|
}
|
|
|
|
var endAngles = GetSphericalProjectedRectAngles(maxRange, aspect, tanfov);
|
|
|
|
if (distanceTruncPlane > 0f)
|
|
{
|
|
var truncAngles = GetFrustrumProjectedRectAngles(distanceTruncPlane, aspect, tanfov);
|
|
Handles.DrawLine(truncAngles[0], truncAngles[1]);
|
|
Handles.DrawLine(truncAngles[1], truncAngles[2]);
|
|
Handles.DrawLine(truncAngles[2], truncAngles[3]);
|
|
Handles.DrawLine(truncAngles[3], truncAngles[0]);
|
|
|
|
if (!drawApex)
|
|
{
|
|
Handles.DrawLine(truncAngles[0], endAngles[0]);
|
|
Handles.DrawLine(truncAngles[1], endAngles[1]);
|
|
Handles.DrawLine(truncAngles[2], endAngles[2]);
|
|
Handles.DrawLine(truncAngles[3], endAngles[3]);
|
|
}
|
|
}
|
|
|
|
var planProjectedCrossNormal0 = new Vector3(endAngles[0].y, -endAngles[0].x, 0).normalized;
|
|
var planProjectedCrossNormal1 = new Vector3(endAngles[1].y, -endAngles[1].x, 0).normalized;
|
|
Vector3[] faceNormals = new[]
|
|
{
|
|
Vector3.right - Vector3.Dot((endAngles[3] + endAngles[0]).normalized, Vector3.right) * (endAngles[3] + endAngles[0]).normalized,
|
|
Vector3.up - Vector3.Dot((endAngles[0] + endAngles[1]).normalized, Vector3.up) * (endAngles[0] + endAngles[1]).normalized,
|
|
Vector3.left - Vector3.Dot((endAngles[1] + endAngles[2]).normalized, Vector3.left) * (endAngles[1] + endAngles[2]).normalized,
|
|
Vector3.down - Vector3.Dot((endAngles[2] + endAngles[3]).normalized, Vector3.down) * (endAngles[2] + endAngles[3]).normalized,
|
|
//cross
|
|
planProjectedCrossNormal0 - Vector3.Dot((endAngles[1] + endAngles[3]).normalized, planProjectedCrossNormal0) * (endAngles[1] + endAngles[3]).normalized,
|
|
planProjectedCrossNormal1 - Vector3.Dot((endAngles[0] + endAngles[2]).normalized, planProjectedCrossNormal1) * (endAngles[0] + endAngles[2]).normalized,
|
|
};
|
|
|
|
float[] faceAngles = new[]
|
|
{
|
|
Vector3.Angle(endAngles[3], endAngles[0]),
|
|
Vector3.Angle(endAngles[0], endAngles[1]),
|
|
Vector3.Angle(endAngles[1], endAngles[2]),
|
|
Vector3.Angle(endAngles[2], endAngles[3]),
|
|
Vector3.Angle(endAngles[1], endAngles[3]),
|
|
Vector3.Angle(endAngles[0], endAngles[2]),
|
|
};
|
|
|
|
Handles.DrawWireArc(Vector3.zero, faceNormals[0], endAngles[0], faceAngles[0], maxRange);
|
|
Handles.DrawWireArc(Vector3.zero, faceNormals[1], endAngles[1], faceAngles[1], maxRange);
|
|
Handles.DrawWireArc(Vector3.zero, faceNormals[2], endAngles[2], faceAngles[2], maxRange);
|
|
Handles.DrawWireArc(Vector3.zero, faceNormals[3], endAngles[3], faceAngles[3], maxRange);
|
|
Handles.DrawWireArc(Vector3.zero, faceNormals[4], endAngles[0], faceAngles[4], maxRange);
|
|
Handles.DrawWireArc(Vector3.zero, faceNormals[5], endAngles[1], faceAngles[5], maxRange);
|
|
|
|
if (drawApex)
|
|
{
|
|
Handles.DrawLine(startAngles[0], endAngles[0]);
|
|
Handles.DrawLine(startAngles[1], endAngles[1]);
|
|
Handles.DrawLine(startAngles[2], endAngles[2]);
|
|
Handles.DrawLine(startAngles[3], endAngles[3]);
|
|
}
|
|
}
|
|
|
|
static Vector3[] GetSphericalProjectedRectAngles(float distance, float aspect, float tanFOV)
|
|
{
|
|
var angles = GetFrustrumProjectedRectAngles(distance, aspect, tanFOV);
|
|
for (int index = 0; index < 4; ++index)
|
|
angles[index] = angles[index].normalized * distance;
|
|
return angles;
|
|
}
|
|
|
|
//TODO: decompose arguments (or tuples) + put back to CoreLightEditorUtilities
|
|
static Vector4 DrawSpherePortionHandle(Vector4 aspectFovMaxRangeMinRange, bool useNearPlane, float minAspect = 0.05f, float maxAspect = 20f, float minFov = 1f)
|
|
{
|
|
float aspect = aspectFovMaxRangeMinRange.x;
|
|
float fov = aspectFovMaxRangeMinRange.y;
|
|
float maxRange = aspectFovMaxRangeMinRange.z;
|
|
float minRange = aspectFovMaxRangeMinRange.w;
|
|
float tanfov = Mathf.Tan(Mathf.Deg2Rad * fov * 0.5f);
|
|
|
|
var endAngles = GetSphericalProjectedRectAngles(maxRange, aspect, tanfov);
|
|
|
|
if (useNearPlane)
|
|
{
|
|
minRange = SliderLineHandle(Vector3.zero, Vector3.forward, minRange);
|
|
}
|
|
|
|
maxRange = SliderLineHandle(Vector3.zero, Vector3.forward, maxRange);
|
|
|
|
float distanceRight = HandleUtility.DistanceToLine(endAngles[0], endAngles[3]);
|
|
float distanceLeft = HandleUtility.DistanceToLine(endAngles[1], endAngles[2]);
|
|
float distanceUp = HandleUtility.DistanceToLine(endAngles[0], endAngles[1]);
|
|
float distanceDown = HandleUtility.DistanceToLine(endAngles[2], endAngles[3]);
|
|
|
|
int pointIndex = 0;
|
|
if (distanceRight < distanceLeft)
|
|
{
|
|
if (distanceUp < distanceDown)
|
|
pointIndex = 0;
|
|
else
|
|
pointIndex = 3;
|
|
}
|
|
else
|
|
{
|
|
if (distanceUp < distanceDown)
|
|
pointIndex = 1;
|
|
else
|
|
pointIndex = 2;
|
|
}
|
|
|
|
Vector2 send = endAngles[pointIndex];
|
|
Vector3 farEnd = new Vector3(0, 0, endAngles[0].z);
|
|
EditorGUI.BeginChangeCheck();
|
|
Vector2 received = SliderPlaneHandle(farEnd, Vector3.right, Vector3.up, send);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
bool fixedFov = Event.current.control && !Event.current.shift;
|
|
bool fixedAspect = Event.current.shift && !Event.current.control;
|
|
|
|
//work on positive quadrant
|
|
int xSign = send.x < 0f ? -1 : 1;
|
|
int ySign = send.y < 0f ? -1 : 1;
|
|
Vector2 corrected = new Vector2(received.x * xSign, received.y * ySign);
|
|
|
|
//fixed aspect correction
|
|
if (fixedAspect)
|
|
{
|
|
corrected.x = corrected.y * aspect;
|
|
}
|
|
|
|
//remove aspect deadzone
|
|
if (corrected.x > maxAspect * corrected.y)
|
|
{
|
|
corrected.y = corrected.x * minAspect;
|
|
}
|
|
if (corrected.x < minAspect * corrected.y)
|
|
{
|
|
corrected.x = corrected.y / maxAspect;
|
|
}
|
|
|
|
//remove fov deadzone
|
|
float deadThresholdFoV = Mathf.Tan(Mathf.Deg2Rad * minFov * 0.5f) * maxRange;
|
|
corrected.x = Mathf.Max(corrected.x, deadThresholdFoV);
|
|
corrected.y = Mathf.Max(corrected.y, deadThresholdFoV, Mathf.Epsilon * 100); //prevent any division by zero
|
|
|
|
if (!fixedAspect)
|
|
{
|
|
aspect = corrected.x / corrected.y;
|
|
}
|
|
float min = Mathf.Min(corrected.x, corrected.y);
|
|
if (!fixedFov && maxRange > Mathf.Epsilon * 100)
|
|
{
|
|
fov = Mathf.Atan(min / maxRange) * 2f * Mathf.Rad2Deg;
|
|
}
|
|
}
|
|
|
|
return new Vector4(aspect, fov, maxRange, minRange);
|
|
}
|
|
|
|
//TODO: decompose arguments (or tuples) + put back to CoreLightEditorUtilities
|
|
static void DrawOrthoFrustumWireframe(Vector4 widthHeightMaxRangeMinRange, float distanceTruncPlane = 0f)
|
|
{
|
|
float halfWidth = widthHeightMaxRangeMinRange.x * 0.5f;
|
|
float halfHeight = widthHeightMaxRangeMinRange.y * 0.5f;
|
|
float maxRange = widthHeightMaxRangeMinRange.z;
|
|
float minRange = widthHeightMaxRangeMinRange.w;
|
|
|
|
Vector3 sizeX = new Vector3(halfWidth, 0, 0);
|
|
Vector3 sizeY = new Vector3(0, halfHeight, 0);
|
|
Vector3 nearEnd = new Vector3(0, 0, minRange);
|
|
Vector3 farEnd = new Vector3(0, 0, maxRange);
|
|
|
|
Vector3 s1 = nearEnd + sizeX + sizeY;
|
|
Vector3 s2 = nearEnd - sizeX + sizeY;
|
|
Vector3 s3 = nearEnd - sizeX - sizeY;
|
|
Vector3 s4 = nearEnd + sizeX - sizeY;
|
|
|
|
Vector3 e1 = farEnd + sizeX + sizeY;
|
|
Vector3 e2 = farEnd - sizeX + sizeY;
|
|
Vector3 e3 = farEnd - sizeX - sizeY;
|
|
Vector3 e4 = farEnd + sizeX - sizeY;
|
|
|
|
Handles.DrawLine(s1, s2);
|
|
Handles.DrawLine(s2, s3);
|
|
Handles.DrawLine(s3, s4);
|
|
Handles.DrawLine(s4, s1);
|
|
|
|
Handles.DrawLine(e1, e2);
|
|
Handles.DrawLine(e2, e3);
|
|
Handles.DrawLine(e3, e4);
|
|
Handles.DrawLine(e4, e1);
|
|
|
|
Handles.DrawLine(s1, e1);
|
|
Handles.DrawLine(s2, e2);
|
|
Handles.DrawLine(s3, e3);
|
|
Handles.DrawLine(s4, e4);
|
|
|
|
if (distanceTruncPlane > 0f)
|
|
{
|
|
Vector3 truncPoint = new Vector3(0, 0, distanceTruncPlane);
|
|
Vector3 t1 = truncPoint + sizeX + sizeY;
|
|
Vector3 t2 = truncPoint - sizeX + sizeY;
|
|
Vector3 t3 = truncPoint - sizeX - sizeY;
|
|
Vector3 t4 = truncPoint + sizeX - sizeY;
|
|
|
|
Handles.DrawLine(t1, t2);
|
|
Handles.DrawLine(t2, t3);
|
|
Handles.DrawLine(t3, t4);
|
|
Handles.DrawLine(t4, t1);
|
|
}
|
|
}
|
|
|
|
//TODO: decompose arguments (or tuples) + put back to CoreLightEditorUtilities
|
|
static Vector4 DrawOrthoFrustumHandle(Vector4 widthHeightMaxRangeMinRange, bool useNearHandle)
|
|
{
|
|
float halfWidth = widthHeightMaxRangeMinRange.x * 0.5f;
|
|
float halfHeight = widthHeightMaxRangeMinRange.y * 0.5f;
|
|
float maxRange = widthHeightMaxRangeMinRange.z;
|
|
float minRange = widthHeightMaxRangeMinRange.w;
|
|
Vector3 farEnd = new Vector3(0, 0, maxRange);
|
|
|
|
if (useNearHandle)
|
|
{
|
|
minRange = SliderLineHandle(Vector3.zero, Vector3.forward, minRange);
|
|
}
|
|
|
|
maxRange = SliderLineHandle(Vector3.zero, Vector3.forward, maxRange);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
halfWidth = SliderLineHandle(farEnd, Vector3.right, halfWidth);
|
|
halfWidth = SliderLineHandle(farEnd, Vector3.left, halfWidth);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
halfWidth = Mathf.Max(0f, halfWidth);
|
|
}
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
halfHeight = SliderLineHandle(farEnd, Vector3.up, halfHeight);
|
|
halfHeight = SliderLineHandle(farEnd, Vector3.down, halfHeight);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
halfHeight = Mathf.Max(0f, halfHeight);
|
|
}
|
|
|
|
return new Vector4(halfWidth * 2f, halfHeight * 2f, maxRange, minRange);
|
|
}
|
|
|
|
#endregion
|
|
|
|
public static void DrawHandles(HDAdditionalLightData additionalData, Editor owner)
|
|
{
|
|
Light light = additionalData.legacyLight;
|
|
|
|
Color wireframeColorAbove = (owner as HDLightEditor).legacyLightColor;
|
|
Color handleColorAbove = GetLightHandleColor(wireframeColorAbove);
|
|
Color wireframeColorBehind = GetLightBehindObjectWireframeColor(wireframeColorAbove);
|
|
Color handleColorBehind = GetLightHandleColor(wireframeColorBehind);
|
|
|
|
switch (light.type)
|
|
{
|
|
case LightType.Directional:
|
|
case LightType.Point:
|
|
//use legacy handles for those cases:
|
|
//See HDLightEditor
|
|
break;
|
|
case LightType.Spot:
|
|
{
|
|
float shadowNearPlane = Mathf.Max(additionalData.shadowNearPlane, HDShadowUtils.k_MinShadowNearPlane);
|
|
shadowNearPlane = light.shadows != LightShadows.None ? shadowNearPlane : 0.0f;
|
|
using (new Handles.DrawingScope(Matrix4x4.TRS(light.transform.position, light.transform.rotation, Vector3.one)))
|
|
{
|
|
Vector3 outterAngleInnerAngleRange = new Vector3(light.spotAngle, light.spotAngle * additionalData.innerSpotPercent01, light.range);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.color = wireframeColorBehind;
|
|
DrawSpotlightWireframe(outterAngleInnerAngleRange, shadowNearPlane);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.color = wireframeColorAbove;
|
|
DrawSpotlightWireframe(outterAngleInnerAngleRange, shadowNearPlane);
|
|
EditorGUI.BeginChangeCheck();
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.color = handleColorBehind;
|
|
outterAngleInnerAngleRange = DrawSpotlightHandle(outterAngleInnerAngleRange);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.color = handleColorAbove;
|
|
outterAngleInnerAngleRange = DrawSpotlightHandle(outterAngleInnerAngleRange);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Undo.RecordObjects(new UnityEngine.Object[] { light, additionalData }, "Adjust Cone Spot Light");
|
|
outterAngleInnerAngleRange.x = Mathf.Min(179.0f, Mathf.Max(1.0f, outterAngleInnerAngleRange.x));
|
|
additionalData.innerSpotPercent = 100f * outterAngleInnerAngleRange.y / outterAngleInnerAngleRange.x;
|
|
// If light unit is currently displayed in lumen and 'reflector' is on, recalculate candela so lumen value remains constant
|
|
if (light.spotAngle != outterAngleInnerAngleRange.x && light.enableSpotReflector && light.lightUnit == LightUnit.Lumen)
|
|
{
|
|
float oldLumen = LightUnitUtils.ConvertIntensity(light, light.intensity, LightUnit.Candela, LightUnit.Lumen);
|
|
float newSolidAngle = LightUnitUtils.GetSolidAngleFromSpotLight(Mathf.Max(1.0f, outterAngleInnerAngleRange.x));
|
|
light.intensity = LightUnitUtils.LumenToCandela(oldLumen, newSolidAngle);
|
|
}
|
|
light.spotAngle = outterAngleInnerAngleRange.x;
|
|
light.range = outterAngleInnerAngleRange.z;
|
|
}
|
|
|
|
// Handles.color reseted at end of scope
|
|
}
|
|
}
|
|
break;
|
|
case LightType.Pyramid:
|
|
{
|
|
float shadowNearPlane = Mathf.Max(additionalData.shadowNearPlane, HDShadowUtils.k_MinShadowNearPlane);
|
|
shadowNearPlane = light.shadows != LightShadows.None ? shadowNearPlane : 0.0f;
|
|
using (new Handles.DrawingScope(Matrix4x4.TRS(light.transform.position, light.transform.rotation, Vector3.one)))
|
|
{
|
|
Vector4 aspectFovMaxRangeMinRange = new Vector4(additionalData.aspectRatio, light.spotAngle, light.range);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.color = wireframeColorBehind;
|
|
DrawSpherePortionWireframe(aspectFovMaxRangeMinRange, shadowNearPlane);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.color = wireframeColorAbove;
|
|
DrawSpherePortionWireframe(aspectFovMaxRangeMinRange, shadowNearPlane);
|
|
EditorGUI.BeginChangeCheck();
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.color = handleColorBehind;
|
|
aspectFovMaxRangeMinRange = DrawSpherePortionHandle(aspectFovMaxRangeMinRange, false);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.color = handleColorAbove;
|
|
aspectFovMaxRangeMinRange = DrawSpherePortionHandle(aspectFovMaxRangeMinRange, false);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Undo.RecordObjects(new UnityEngine.Object[] { light, additionalData }, "Adjust Pyramid Spot Light");
|
|
|
|
if ((light.spotAngle != aspectFovMaxRangeMinRange.y || additionalData.aspectRatio != aspectFovMaxRangeMinRange.x)
|
|
&& light.enableSpotReflector && light.lightUnit == LightUnit.Lumen)
|
|
{
|
|
float oldLumen = LightUnitUtils.ConvertIntensity(light, light.intensity, LightUnit.Candela, LightUnit.Lumen);
|
|
float newSolidAngle = LightUnitUtils.GetSolidAngleFromPyramidLight(aspectFovMaxRangeMinRange.y, aspectFovMaxRangeMinRange.x);
|
|
light.intensity = LightUnitUtils.LumenToCandela(oldLumen, newSolidAngle);
|
|
}
|
|
additionalData.aspectRatio = aspectFovMaxRangeMinRange.x;
|
|
light.spotAngle = aspectFovMaxRangeMinRange.y;
|
|
light.range = aspectFovMaxRangeMinRange.z;
|
|
}
|
|
|
|
// Handles.color reseted at end of scope
|
|
}
|
|
}
|
|
break;
|
|
case LightType.Box:
|
|
{
|
|
float shadowNearPlane = Mathf.Max(additionalData.shadowNearPlane, 0);
|
|
shadowNearPlane = light.shadows != LightShadows.None ? shadowNearPlane : 0.0f;
|
|
using (new Handles.DrawingScope(Matrix4x4.TRS(light.transform.position, light.transform.rotation, Vector3.one)))
|
|
{
|
|
Vector4 widthHeightMaxRangeMinRange = new Vector4(additionalData.shapeWidth, additionalData.shapeHeight, light.range);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.color = wireframeColorBehind;
|
|
DrawOrthoFrustumWireframe(widthHeightMaxRangeMinRange, shadowNearPlane);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.color = wireframeColorAbove;
|
|
DrawOrthoFrustumWireframe(widthHeightMaxRangeMinRange, shadowNearPlane);
|
|
EditorGUI.BeginChangeCheck();
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.color = handleColorBehind;
|
|
widthHeightMaxRangeMinRange = DrawOrthoFrustumHandle(widthHeightMaxRangeMinRange, false);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.color = handleColorAbove;
|
|
widthHeightMaxRangeMinRange = DrawOrthoFrustumHandle(widthHeightMaxRangeMinRange, false);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Undo.RecordObjects(new UnityEngine.Object[] { light, additionalData }, "Adjust Box Spot Light");
|
|
additionalData.shapeWidth = widthHeightMaxRangeMinRange.x;
|
|
additionalData.shapeHeight = widthHeightMaxRangeMinRange.y;
|
|
light.range = widthHeightMaxRangeMinRange.z;
|
|
}
|
|
|
|
// Handles.color reset at end of scope
|
|
}
|
|
}
|
|
break;
|
|
case LightType.Rectangle:
|
|
case LightType.Tube:
|
|
{
|
|
bool withYAxis = light.type == LightType.Rectangle;
|
|
using (new Handles.DrawingScope(Matrix4x4.TRS(light.transform.position, light.transform.rotation, Vector3.one)))
|
|
{
|
|
Vector2 widthHeight = new Vector4(additionalData.shapeWidth, withYAxis ? additionalData.shapeHeight : 0f);
|
|
float range = light.range;
|
|
float aspect = additionalData.shapeWidth / additionalData.shapeHeight;
|
|
float angle = additionalData.areaLightShadowCone;
|
|
float offset = -Mathf.Min(additionalData.shapeWidth, additionalData.shapeHeight) * 0.5f / Mathf.Tan(angle * 0.5f * Mathf.Deg2Rad);
|
|
Vector4 aspectFovMaxRangeMinRange = new Vector4(aspect, angle, range - offset);
|
|
Matrix4x4 shadowFrustumMatrix = Matrix4x4.TRS(light.transform.position + light.transform.forward * offset, light.transform.rotation, Vector3.one);
|
|
float nearPlane = additionalData.shadowNearPlane - offset;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.color = wireframeColorBehind;
|
|
DrawAreaLightWireframe(widthHeight);
|
|
if (light.shadows != LightShadows.None)
|
|
{
|
|
using (new Handles.DrawingScope(shadowFrustumMatrix))
|
|
DrawSpherePortionWireframe(aspectFovMaxRangeMinRange, nearPlane, drawApex: false);
|
|
range = SliderLineHandle(Vector3.zero, Vector3.forward, range);
|
|
}
|
|
else
|
|
{
|
|
range = Handles.RadiusHandle(Quaternion.identity, Vector3.zero, range);
|
|
}
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.color = wireframeColorAbove;
|
|
DrawAreaLightWireframe(widthHeight);
|
|
if (light.shadows != LightShadows.None)
|
|
{
|
|
using (new Handles.DrawingScope(shadowFrustumMatrix))
|
|
DrawSpherePortionWireframe(aspectFovMaxRangeMinRange, nearPlane, drawApex: false);
|
|
range = SliderLineHandle(Vector3.zero, Vector3.forward, range);
|
|
}
|
|
else
|
|
{
|
|
range = Handles.RadiusHandle(Quaternion.identity, Vector3.zero, range);
|
|
}
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
Handles.color = handleColorBehind;
|
|
widthHeight = DrawAreaLightHandle(widthHeight, withYAxis);
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
Handles.color = handleColorAbove;
|
|
widthHeight = DrawAreaLightHandle(widthHeight, withYAxis);
|
|
widthHeight = Vector2.Max(Vector2.one * HDAdditionalLightData.k_MinLightSize, widthHeight);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Undo.RecordObjects(new UnityEngine.Object[] { light, additionalData }, withYAxis ? "Adjust Area Rectangle Light" : "Adjust Area Tube Light");
|
|
float oldWidth = additionalData.shapeWidth;
|
|
float oldHeight = additionalData.shapeHeight;
|
|
if (withYAxis)
|
|
{
|
|
if (light.lightUnit == LightUnit.Lumen)
|
|
{
|
|
float oldArea = LightUnitUtils.GetAreaFromRectangleLight(oldWidth, oldHeight);
|
|
float oldLumen = LightUnitUtils.NitsToLumen(light.intensity, oldArea);
|
|
|
|
float newArea = LightUnitUtils.GetAreaFromRectangleLight(widthHeight);
|
|
light.intensity = LightUnitUtils.LumenToNits(oldLumen, newArea);
|
|
}
|
|
additionalData.shapeHeight = widthHeight.y;
|
|
}
|
|
else if (light.lightUnit == LightUnit.Lumen)
|
|
{
|
|
float oldArea = LightUnitUtils.GetAreaFromTubeLight(oldWidth);
|
|
float oldLumen = LightUnitUtils.NitsToLumen(light.intensity, oldArea);
|
|
|
|
float newArea = LightUnitUtils.GetAreaFromTubeLight(widthHeight.x);
|
|
light.intensity = LightUnitUtils.LumenToNits(oldLumen, newArea);
|
|
}
|
|
additionalData.shapeWidth = widthHeight.x;
|
|
light.range = range;
|
|
}
|
|
|
|
// Handles.color reset at end of scope
|
|
}
|
|
}
|
|
break;
|
|
case LightType.Disc:
|
|
//use legacy handles for this case
|
|
break;
|
|
}
|
|
}
|
|
|
|
[DrawGizmo(GizmoType.Selected)]
|
|
static void DrawGizmoForHDAdditionalLightData(HDAdditionalLightData src, GizmoType gizmoType)
|
|
{
|
|
if (!(UnityEngine.Rendering.GraphicsSettings.currentRenderPipeline is HDRenderPipelineAsset))
|
|
return;
|
|
|
|
if (src.legacyLight.type != LightType.Directional)
|
|
{
|
|
// Trace a ray down to better locate the light location
|
|
Ray ray = new Ray(src.gameObject.transform.position, Vector3.down);
|
|
RaycastHit hit;
|
|
if (Physics.Raycast(ray, out hit))
|
|
{
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
|
|
using (new Handles.DrawingScope(Color.green))
|
|
{
|
|
Handles.DrawLine(src.gameObject.transform.position, hit.point);
|
|
Handles.DrawWireDisc(hit.point, hit.normal, 0.5f);
|
|
}
|
|
|
|
Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
|
|
using (new Handles.DrawingScope(Color.red))
|
|
{
|
|
Handles.DrawLine(src.gameObject.transform.position, hit.point);
|
|
Handles.DrawWireDisc(hit.point, hit.normal, 0.5f);
|
|
}
|
|
}
|
|
|
|
if ((ShaderConfig.s_BarnDoor == 1) && (src.legacyLight.type.IsArea() && src.barnDoorAngle < 89.0f))
|
|
{
|
|
// Convert the angle to randians
|
|
float angle = src.barnDoorAngle * Mathf.PI / 180.0f;
|
|
|
|
// Compute the depth of the pyramid
|
|
float depth = src.barnDoorLength * Mathf.Cos(angle);
|
|
|
|
// Evaluate the half dimensions of the rectangular area light
|
|
float halfWidth = src.shapeWidth * 0.5f;
|
|
float halfHeight = src.shapeHeight * 0.5f;
|
|
|
|
// Evaluate the dimensions of the extended area light
|
|
float extendedWidth = Mathf.Tan(angle) * depth + halfWidth;
|
|
float extendedHeight = Mathf.Tan(angle) * depth + halfHeight;
|
|
|
|
// Compute all the points of the pyramid
|
|
Vector3 pos00 = src.transform.position + halfWidth * src.transform.right + halfHeight * src.transform.up;
|
|
Vector3 pos10 = src.transform.position - halfWidth * src.transform.right + halfHeight * src.transform.up;
|
|
Vector3 pos20 = src.transform.position - halfWidth * src.transform.right - halfHeight * src.transform.up;
|
|
Vector3 pos30 = src.transform.position + halfWidth * src.transform.right - halfHeight * src.transform.up;
|
|
Vector3 pos01 = src.transform.position + src.transform.forward * depth + src.transform.right * extendedWidth + src.transform.up * extendedHeight;
|
|
Vector3 pos11 = src.transform.position + src.transform.forward * depth - src.transform.right * extendedWidth + src.transform.up * extendedHeight;
|
|
Vector3 pos21 = src.transform.position + src.transform.forward * depth - src.transform.right * extendedWidth - src.transform.up * extendedHeight;
|
|
Vector3 pos31 = src.transform.position + src.transform.forward * depth + src.transform.right * extendedWidth - src.transform.up * extendedHeight;
|
|
|
|
// Draw the pyramid
|
|
Debug.DrawLine(pos00, pos01, Color.yellow);
|
|
Debug.DrawLine(pos10, pos11, Color.yellow);
|
|
Debug.DrawLine(pos20, pos21, Color.yellow);
|
|
Debug.DrawLine(pos30, pos31, Color.yellow);
|
|
Debug.DrawLine(pos01, pos11, Color.yellow);
|
|
Debug.DrawLine(pos11, pos21, Color.yellow);
|
|
Debug.DrawLine(pos21, pos31, Color.yellow);
|
|
Debug.DrawLine(pos31, pos01, Color.yellow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|