您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
749 行
37 KiB
749 行
37 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditor.EditorTools;
|
|
using UnityEditor.Experimental.Rendering.Universal.Path2D;
|
|
using UnityEngine;
|
|
using UnityEngine.Experimental.Rendering.Universal;
|
|
using UnityEngine.Rendering.Universal;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace UnityEditor.Experimental.Rendering.Universal
|
|
{
|
|
[CustomEditor(typeof(Light2D))]
|
|
[CanEditMultipleObjects]
|
|
internal class Light2DEditor : PathComponentEditor<ScriptablePath>
|
|
{
|
|
[EditorTool("Edit Freeform Shape", typeof(Light2D))]
|
|
class FreeformShapeTool : PathEditorTool<ScriptablePath>
|
|
{
|
|
const string k_ShapePath = "m_ShapePath";
|
|
|
|
public override bool IsAvailable()
|
|
{
|
|
var light = target as Light2D;
|
|
|
|
if (light == null)
|
|
return false;
|
|
else
|
|
return base.IsAvailable() && light.lightType == Light2D.LightType.Freeform;
|
|
}
|
|
|
|
protected override IShape GetShape(Object target)
|
|
{
|
|
return (target as Light2D).shapePath.ToPolygon(false);
|
|
}
|
|
|
|
protected override void SetShape(ScriptablePath shapeEditor, SerializedObject serializedObject)
|
|
{
|
|
serializedObject.Update();
|
|
|
|
var pointsProperty = serializedObject.FindProperty(k_ShapePath);
|
|
pointsProperty.arraySize = shapeEditor.pointCount;
|
|
|
|
for (var i = 0; i < shapeEditor.pointCount; ++i)
|
|
pointsProperty.GetArrayElementAtIndex(i).vector3Value = shapeEditor.GetPoint(i).position;
|
|
|
|
// This is untracked right now...
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
}
|
|
|
|
private static class Styles
|
|
{
|
|
public static Texture lightCapTopRight = Resources.Load<Texture>("LightCapTopRight");
|
|
public static Texture lightCapTopLeft = Resources.Load<Texture>("LightCapTopLeft");
|
|
public static Texture lightCapBottomLeft = Resources.Load<Texture>("LightCapBottomLeft");
|
|
public static Texture lightCapBottomRight = Resources.Load<Texture>("LightCapBottomRight");
|
|
public static Texture lightCapUp = Resources.Load<Texture>("LightCapUp");
|
|
public static Texture lightCapDown = Resources.Load<Texture>("LightCapDown");
|
|
public static Texture parametricLightIcon = Resources.Load("InspectorIcons/ParametricLight") as Texture;
|
|
public static Texture freeformLightIcon = Resources.Load("InspectorIcons/FreeformLight") as Texture;
|
|
public static Texture spriteLightIcon = Resources.Load("InspectorIcons/SpriteLight") as Texture;
|
|
public static Texture pointLightIcon = Resources.Load("InspectorIcons/PointLight") as Texture;
|
|
public static Texture globalLightIcon = Resources.Load("InspectorIcons/GlobalLight") as Texture;
|
|
public static Texture[] lightIcons = new Texture[] { parametricLightIcon, freeformLightIcon, spriteLightIcon, pointLightIcon, globalLightIcon };
|
|
|
|
public static GUIContent generalLightType = EditorGUIUtility.TrTextContent("Light Type", "Specify the light type");
|
|
public static GUIContent generalFalloffSize = EditorGUIUtility.TrTextContent("Falloff", "Specify the falloff of the light");
|
|
public static GUIContent generalFalloffIntensity = EditorGUIUtility.TrTextContent("Falloff Intensity", "Adjusts the falloff curve");
|
|
public static GUIContent generalLightColor = EditorGUIUtility.TrTextContent("Color", "Specify the light color");
|
|
public static GUIContent generalLightIntensity = EditorGUIUtility.TrTextContent("Intensity", "Specify the light color's intensity");
|
|
public static GUIContent generalUseNormalMap = EditorGUIUtility.TrTextContent("Use Normal Map", "Specify whether the light considers normal maps");
|
|
public static GUIContent generalVolumeOpacity = EditorGUIUtility.TrTextContent("Volume Opacity", "Specify the light's volumetric light volume opacity");
|
|
public static GUIContent generalBlendStyle = EditorGUIUtility.TrTextContent("Blend Style", "Specify the blend style");
|
|
public static GUIContent generalLightOverlapMode = EditorGUIUtility.TrTextContent("Alpha Blend on Overlap", "Use alpha blending instead of additive blending when this light overlaps others");
|
|
public static GUIContent generalLightOrder = EditorGUIUtility.TrTextContent("Light Order", "The relative order in which lights of the same blend style get rendered.");
|
|
|
|
public static GUIContent pointLightQuality = EditorGUIUtility.TrTextContent("Quality", "Use accurate if there are noticeable visual issues");
|
|
public static GUIContent pointLightInnerAngle = EditorGUIUtility.TrTextContent("Inner Angle", "Specify the inner angle of the light");
|
|
public static GUIContent pointLightOuterAngle = EditorGUIUtility.TrTextContent("Outer Angle", "Specify the outer angle of the light");
|
|
public static GUIContent pointLightInnerRadius = EditorGUIUtility.TrTextContent("Inner Radius", "Specify the inner radius of the light");
|
|
public static GUIContent pointLightOuterRadius = EditorGUIUtility.TrTextContent("Outer Radius", "Specify the outer radius of the light");
|
|
public static GUIContent pointLightZDistance = EditorGUIUtility.TrTextContent("Distance", "Specify the Z Distance of the light");
|
|
public static GUIContent pointLightCookie = EditorGUIUtility.TrTextContent("Cookie", "Specify a sprite as the cookie for the light");
|
|
|
|
public static GUIContent shapeLightNoLightDefined = EditorGUIUtility.TrTextContentWithIcon("No valid Shape Light type is defined.", MessageType.Error);
|
|
public static GUIContent shapeLightSprite = EditorGUIUtility.TrTextContent("Sprite", "Specify the sprite");
|
|
public static GUIContent shapeLightParametricRadius = EditorGUIUtility.TrTextContent("Radius", "Adjust the size of the object");
|
|
public static GUIContent shapeLightParametricSides = EditorGUIUtility.TrTextContent("Sides", "Adjust the shapes number of sides");
|
|
public static GUIContent shapeLightFalloffOffset = EditorGUIUtility.TrTextContent("Falloff Offset", "Specify the shape's falloff offset");
|
|
public static GUIContent shapeLightAngleOffset = EditorGUIUtility.TrTextContent("Angle Offset", "Adjust the rotation of the object");
|
|
|
|
public static GUIContent sortingLayerPrefixLabel = EditorGUIUtility.TrTextContent("Target Sorting Layers", "Apply this light to the specified sorting layers.");
|
|
public static GUIContent sortingLayerAll = EditorGUIUtility.TrTextContent("All");
|
|
public static GUIContent sortingLayerNone = EditorGUIUtility.TrTextContent("None");
|
|
public static GUIContent sortingLayerMixed = EditorGUIUtility.TrTextContent("Mixed...");
|
|
|
|
public static GUIContent renderPipelineUnassignedWarning = EditorGUIUtility.TrTextContentWithIcon("Universal scriptable renderpipeline asset must be assigned in graphics settings", MessageType.Warning);
|
|
public static GUIContent asset2DUnassignedWarning = EditorGUIUtility.TrTextContentWithIcon("2D renderer data must be assigned to your universal render pipeline asset", MessageType.Warning);
|
|
}
|
|
|
|
const float k_GlobalLightGizmoSize = 1.2f;
|
|
const float k_AngleCapSize = 0.16f * k_GlobalLightGizmoSize;
|
|
const float k_AngleCapOffset = 0.08f * k_GlobalLightGizmoSize;
|
|
const float k_AngleCapOffsetSecondary = -0.05f;
|
|
const float k_RangeCapSize = 0.025f * k_GlobalLightGizmoSize;
|
|
const float k_InnerRangeCapSize = 0.08f * k_GlobalLightGizmoSize;
|
|
|
|
SerializedProperty m_LightType;
|
|
SerializedProperty m_LightColor;
|
|
SerializedProperty m_LightIntensity;
|
|
SerializedProperty m_UseNormalMap;
|
|
SerializedProperty m_ApplyToSortingLayers;
|
|
SerializedProperty m_VolumetricAlpha;
|
|
SerializedProperty m_BlendStyleIndex;
|
|
SerializedProperty m_FalloffIntensity;
|
|
SerializedProperty m_PointZDistance;
|
|
SerializedProperty m_LightOrder;
|
|
SerializedProperty m_AlphaBlendOnOverlap;
|
|
|
|
// Point Light Properties
|
|
SerializedProperty m_PointInnerAngle;
|
|
SerializedProperty m_PointOuterAngle;
|
|
SerializedProperty m_PointInnerRadius;
|
|
SerializedProperty m_PointOuterRadius;
|
|
SerializedProperty m_PointLightCookie;
|
|
SerializedProperty m_PointLightQuality;
|
|
|
|
// Shape Light Properties
|
|
SerializedProperty m_ShapeLightParametricRadius;
|
|
SerializedProperty m_ShapeLightFalloffSize;
|
|
SerializedProperty m_ShapeLightParametricSides;
|
|
SerializedProperty m_ShapeLightParametricAngleOffset;
|
|
SerializedProperty m_ShapeLightFalloffOffset;
|
|
SerializedProperty m_ShapeLightSprite;
|
|
|
|
int[] m_BlendStyleIndices;
|
|
GUIContent[] m_BlendStyleNames;
|
|
bool m_AnyBlendStyleEnabled = false;
|
|
Rect m_SortingLayerDropdownRect = new Rect();
|
|
SortingLayer[] m_AllSortingLayers;
|
|
GUIContent[] m_AllSortingLayerNames;
|
|
List<int> m_ApplyToSortingLayersList;
|
|
|
|
Light2D lightObject => target as Light2D;
|
|
|
|
int m_LastLightType = 0;
|
|
|
|
HeaderModifier m_HeaderModifier;
|
|
|
|
Analytics.Renderer2DAnalytics m_Analytics;
|
|
HashSet<Light2D> m_ModifiedLights;
|
|
|
|
private void AnalyticsTrackChanges(SerializedObject serializedObject)
|
|
{
|
|
if (serializedObject.hasModifiedProperties)
|
|
{
|
|
foreach (Object targetObj in serializedObject.targetObjects)
|
|
{
|
|
Light2D light2d = (Light2D)targetObj;
|
|
if(!m_ModifiedLights.Contains(light2d))
|
|
m_ModifiedLights.Add(light2d);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override VisualElement CreateInspectorGUI()
|
|
{
|
|
m_HeaderModifier = new HeaderModifier(OnInspectorGUI, () =>
|
|
{
|
|
if (Styles.lightIcons != null)
|
|
{
|
|
Color skinColor = EditorGUIUtility.isProSkin ? new Color32(56, 56, 56, 255) : new Color32(194, 194, 194, 255);
|
|
|
|
//GUISkin skin = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector);
|
|
|
|
Rect iconRect = new Rect(16, 2, 16, 16);
|
|
EditorGUI.DrawRect(iconRect, skinColor);
|
|
|
|
if (Styles.lightIcons[m_LastLightType])
|
|
{
|
|
GUI.DrawTexture(iconRect, Styles.lightIcons[m_LastLightType]);
|
|
}
|
|
}
|
|
});
|
|
return m_HeaderModifier;
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
m_Analytics = Analytics.Renderer2DAnalytics.instance;
|
|
m_ModifiedLights = new HashSet<Light2D>();
|
|
m_LightType = serializedObject.FindProperty("m_LightType");
|
|
m_LightColor = serializedObject.FindProperty("m_Color");
|
|
m_LightIntensity = serializedObject.FindProperty("m_Intensity");
|
|
m_UseNormalMap = serializedObject.FindProperty("m_UseNormalMap");
|
|
m_ApplyToSortingLayers = serializedObject.FindProperty("m_ApplyToSortingLayers");
|
|
m_VolumetricAlpha = serializedObject.FindProperty("m_LightVolumeOpacity");
|
|
m_BlendStyleIndex = serializedObject.FindProperty("m_BlendStyleIndex");
|
|
m_FalloffIntensity = serializedObject.FindProperty("m_FalloffIntensity");
|
|
m_PointZDistance = serializedObject.FindProperty("m_PointLightDistance");
|
|
m_LightOrder = serializedObject.FindProperty("m_LightOrder");
|
|
m_AlphaBlendOnOverlap = serializedObject.FindProperty("m_AlphaBlendOnOverlap");
|
|
|
|
// Point Light
|
|
m_PointInnerAngle = serializedObject.FindProperty("m_PointLightInnerAngle");
|
|
m_PointOuterAngle = serializedObject.FindProperty("m_PointLightOuterAngle");
|
|
m_PointInnerRadius = serializedObject.FindProperty("m_PointLightInnerRadius");
|
|
m_PointOuterRadius = serializedObject.FindProperty("m_PointLightOuterRadius");
|
|
m_PointLightCookie = serializedObject.FindProperty("m_LightCookieSprite");
|
|
m_PointLightQuality = serializedObject.FindProperty("m_PointLightQuality");
|
|
|
|
// Shape Light
|
|
m_ShapeLightParametricRadius = serializedObject.FindProperty("m_ShapeLightParametricRadius");
|
|
m_ShapeLightFalloffSize = serializedObject.FindProperty("m_ShapeLightFalloffSize");
|
|
m_ShapeLightParametricSides = serializedObject.FindProperty("m_ShapeLightParametricSides");
|
|
m_ShapeLightParametricAngleOffset = serializedObject.FindProperty("m_ShapeLightParametricAngleOffset");
|
|
m_ShapeLightFalloffOffset = serializedObject.FindProperty("m_ShapeLightFalloffOffset");
|
|
m_ShapeLightSprite = serializedObject.FindProperty("m_LightCookieSprite");
|
|
|
|
m_AnyBlendStyleEnabled = false;
|
|
var blendStyleIndices = new List<int>();
|
|
var blendStyleNames = new List<string>();
|
|
var pipelineAsset = UnityEngine.Rendering.GraphicsSettings.renderPipelineAsset as UniversalRenderPipelineAsset;
|
|
var rendererData = pipelineAsset != null ? pipelineAsset.scriptableRendererData as Renderer2DData : null;
|
|
if (rendererData != null)
|
|
{
|
|
for (int i = 0; i < rendererData.lightBlendStyles.Length; ++i)
|
|
{
|
|
blendStyleIndices.Add(i);
|
|
|
|
ref var blendStyle = ref rendererData.lightBlendStyles[i];
|
|
if (blendStyle.enabled)
|
|
{
|
|
blendStyleNames.Add(blendStyle.name);
|
|
m_AnyBlendStyleEnabled = true;
|
|
}
|
|
else
|
|
blendStyleNames.Add(blendStyle.name + " (Disabled)");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
blendStyleIndices.Add(i);
|
|
blendStyleNames.Add("Operation" + i);
|
|
}
|
|
}
|
|
|
|
m_BlendStyleIndices = blendStyleIndices.ToArray();
|
|
m_BlendStyleNames = blendStyleNames.Select(x => new GUIContent(x)).ToArray();
|
|
|
|
m_AllSortingLayers = SortingLayer.layers;
|
|
m_AllSortingLayerNames = m_AllSortingLayers.Select(x => new GUIContent(x.name)).ToArray();
|
|
|
|
int applyToSortingLayersSize = m_ApplyToSortingLayers.arraySize;
|
|
m_ApplyToSortingLayersList = new List<int>(applyToSortingLayersSize);
|
|
|
|
for (int i = 0; i < applyToSortingLayersSize; ++i)
|
|
{
|
|
int layerID = m_ApplyToSortingLayers.GetArrayElementAtIndex(i).intValue;
|
|
if (SortingLayer.IsValid(layerID))
|
|
m_ApplyToSortingLayersList.Add(layerID);
|
|
}
|
|
}
|
|
|
|
internal void SendModifiedAnalytics(Analytics.Renderer2DAnalytics analytics, Light2D light)
|
|
{
|
|
Analytics.Light2DData lightData = new Analytics.Light2DData();
|
|
lightData.was_create_event = false;
|
|
lightData.instance_id = light.GetInstanceID();
|
|
lightData.light_type = light.lightType;
|
|
Analytics.Renderer2DAnalytics.instance.SendData(Analytics.AnalyticsDataTypes.k_LightDataString, lightData);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
|
|
if(m_ModifiedLights.Count > 0)
|
|
{
|
|
foreach (Light2D light in m_ModifiedLights)
|
|
{
|
|
SendModifiedAnalytics(m_Analytics, light);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnPointLight(SerializedObject serializedObject)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.Slider(m_PointInnerAngle, 0, 360, Styles.pointLightInnerAngle);
|
|
if (EditorGUI.EndChangeCheck())
|
|
m_PointInnerAngle.floatValue = Mathf.Min(m_PointInnerAngle.floatValue, m_PointOuterAngle.floatValue);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.Slider(m_PointOuterAngle, 0, 360, Styles.pointLightOuterAngle);
|
|
if (EditorGUI.EndChangeCheck())
|
|
m_PointOuterAngle.floatValue = Mathf.Max(m_PointInnerAngle.floatValue, m_PointOuterAngle.floatValue);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.PropertyField(m_PointInnerRadius, Styles.pointLightInnerRadius);
|
|
if (EditorGUI.EndChangeCheck())
|
|
m_PointInnerRadius.floatValue = Mathf.Max(0.0f, Mathf.Min(m_PointInnerRadius.floatValue, m_PointOuterRadius.floatValue));
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.PropertyField(m_PointOuterRadius, Styles.pointLightOuterRadius);
|
|
if (EditorGUI.EndChangeCheck())
|
|
m_PointOuterRadius.floatValue = Mathf.Max(m_PointInnerRadius.floatValue, m_PointOuterRadius.floatValue);
|
|
|
|
EditorGUILayout.Slider(m_FalloffIntensity, 0, 1, Styles.generalFalloffIntensity);
|
|
EditorGUILayout.PropertyField(m_PointLightCookie, Styles.pointLightCookie);
|
|
}
|
|
|
|
void OnShapeLight(Light2D.LightType lightType, SerializedObject serializedObject)
|
|
{
|
|
if (!m_AnyBlendStyleEnabled)
|
|
EditorGUILayout.HelpBox(Styles.shapeLightNoLightDefined);
|
|
|
|
if (lightType == Light2D.LightType.Sprite)
|
|
{
|
|
EditorGUILayout.PropertyField(m_ShapeLightSprite, Styles.shapeLightSprite);
|
|
}
|
|
else if (lightType == Light2D.LightType.Parametric || lightType == Light2D.LightType.Freeform)
|
|
{
|
|
if (lightType == Light2D.LightType.Parametric)
|
|
{
|
|
EditorGUILayout.PropertyField(m_ShapeLightParametricRadius, Styles.shapeLightParametricRadius);
|
|
if (m_ShapeLightParametricRadius.floatValue < 0)
|
|
m_ShapeLightParametricRadius.floatValue = 0;
|
|
|
|
EditorGUILayout.IntSlider(m_ShapeLightParametricSides, 3, 48, Styles.shapeLightParametricSides);
|
|
EditorGUILayout.Slider(m_ShapeLightParametricAngleOffset, 0, 359, Styles.shapeLightAngleOffset);
|
|
}
|
|
|
|
EditorGUILayout.PropertyField(m_ShapeLightFalloffSize, Styles.generalFalloffSize);
|
|
if (m_ShapeLightFalloffSize.floatValue < 0)
|
|
m_ShapeLightFalloffSize.floatValue = 0;
|
|
|
|
EditorGUILayout.Slider(m_FalloffIntensity, 0, 1, Styles.generalFalloffIntensity);
|
|
|
|
if (lightType == Light2D.LightType.Parametric || lightType == Light2D.LightType.Freeform)
|
|
{
|
|
bool oldWideMode = EditorGUIUtility.wideMode;
|
|
EditorGUIUtility.wideMode = true;
|
|
EditorGUILayout.PropertyField(m_ShapeLightFalloffOffset, Styles.shapeLightFalloffOffset);
|
|
EditorGUIUtility.wideMode = oldWideMode;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateApplyToSortingLayersArray()
|
|
{
|
|
m_ApplyToSortingLayers.ClearArray();
|
|
for (int i = 0; i < m_ApplyToSortingLayersList.Count; ++i)
|
|
{
|
|
m_ApplyToSortingLayers.InsertArrayElementAtIndex(i);
|
|
m_ApplyToSortingLayers.GetArrayElementAtIndex(i).intValue = m_ApplyToSortingLayersList[i];
|
|
}
|
|
|
|
AnalyticsTrackChanges(serializedObject);
|
|
serializedObject.ApplyModifiedProperties();
|
|
|
|
foreach (Light2D light in targets)
|
|
{
|
|
if (light != null && light.lightType == Light2D.LightType.Global)
|
|
light.ErrorIfDuplicateGlobalLight();
|
|
}
|
|
}
|
|
|
|
void OnNoSortingLayerSelected()
|
|
{
|
|
m_ApplyToSortingLayersList.Clear();
|
|
UpdateApplyToSortingLayersArray();
|
|
}
|
|
|
|
void OnAllSortingLayersSelected()
|
|
{
|
|
m_ApplyToSortingLayersList.Clear();
|
|
m_ApplyToSortingLayersList.AddRange(m_AllSortingLayers.Select(x => x.id));
|
|
UpdateApplyToSortingLayersArray();
|
|
}
|
|
|
|
void OnSortingLayerSelected(object layerIDObject)
|
|
{
|
|
int layerID = (int)layerIDObject;
|
|
|
|
if (m_ApplyToSortingLayersList.Contains(layerID))
|
|
m_ApplyToSortingLayersList.RemoveAll(id => id == layerID);
|
|
else
|
|
m_ApplyToSortingLayersList.Add(layerID);
|
|
|
|
UpdateApplyToSortingLayersArray();
|
|
}
|
|
|
|
void OnTargetSortingLayers()
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.PrefixLabel(Styles.sortingLayerPrefixLabel);
|
|
|
|
GUIContent selectedLayers;
|
|
if (m_ApplyToSortingLayersList.Count == 1)
|
|
selectedLayers = new GUIContent(SortingLayer.IDToName(m_ApplyToSortingLayersList[0]));
|
|
else if (m_ApplyToSortingLayersList.Count == m_AllSortingLayers.Length)
|
|
selectedLayers = Styles.sortingLayerAll;
|
|
else if (m_ApplyToSortingLayersList.Count == 0)
|
|
selectedLayers = Styles.sortingLayerNone;
|
|
else
|
|
selectedLayers = Styles.sortingLayerMixed;
|
|
|
|
bool buttonDown = EditorGUILayout.DropdownButton(selectedLayers, FocusType.Keyboard, EditorStyles.popup);
|
|
|
|
if (Event.current.type == EventType.Repaint)
|
|
m_SortingLayerDropdownRect = GUILayoutUtility.GetLastRect();
|
|
|
|
if (buttonDown)
|
|
{
|
|
GenericMenu menu = new GenericMenu();
|
|
menu.allowDuplicateNames = true;
|
|
|
|
menu.AddItem(Styles.sortingLayerNone, m_ApplyToSortingLayersList.Count == 0, OnNoSortingLayerSelected);
|
|
menu.AddItem(Styles.sortingLayerAll, m_ApplyToSortingLayersList.Count == m_AllSortingLayers.Length, OnAllSortingLayersSelected);
|
|
menu.AddSeparator("");
|
|
|
|
for (int i = 0; i < m_AllSortingLayers.Length; ++i)
|
|
{
|
|
var sortingLayer = m_AllSortingLayers[i];
|
|
menu.AddItem(m_AllSortingLayerNames[i], m_ApplyToSortingLayersList.Contains(sortingLayer.id), OnSortingLayerSelected, sortingLayer.id);
|
|
}
|
|
|
|
menu.DropDown(m_SortingLayerDropdownRect);
|
|
}
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
|
|
Vector3 DrawAngleSlider2D(Transform transform, Quaternion rotation, float radius, float offset, Handles.CapFunction capFunc, float capSize, bool leftAngle, bool drawLine, bool useCapOffset, ref float angle)
|
|
{
|
|
float oldAngle = angle;
|
|
|
|
float angleBy2 = (angle / 2) * (leftAngle ? -1.0f : 1.0f);
|
|
Vector3 trcwPos = Quaternion.AngleAxis(angleBy2, -transform.forward) * (transform.up);
|
|
Vector3 cwPos = transform.position + trcwPos * (radius + offset);
|
|
|
|
float direction = leftAngle ? 1 : -1;
|
|
|
|
// Offset the handle
|
|
float size = .25f * capSize;
|
|
|
|
Vector3 handleOffset = useCapOffset ? rotation * new Vector3(direction * size, 0, 0) : Vector3.zero;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
var id = GUIUtility.GetControlID("AngleSlider".GetHashCode(), FocusType.Passive);
|
|
Vector3 cwHandle = Handles.Slider2D(id, cwPos, handleOffset, Vector3.forward, rotation * Vector3.up, rotation * Vector3.right, capSize, capFunc, Vector3.zero);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Vector3 toCwHandle = (transform.position - cwHandle).normalized;
|
|
|
|
angle = 360 - 2 * Quaternion.Angle(Quaternion.FromToRotation(transform.up, toCwHandle), Quaternion.identity);
|
|
angle = Mathf.Round(angle * 100) / 100f;
|
|
|
|
float side = Vector3.Dot(direction * transform.right, toCwHandle);
|
|
if (side < 0)
|
|
{
|
|
if (oldAngle < 180)
|
|
angle = 0;
|
|
else
|
|
angle = 360;
|
|
}
|
|
}
|
|
|
|
if (drawLine)
|
|
Handles.DrawLine(transform.position, cwHandle);
|
|
|
|
return cwHandle;
|
|
}
|
|
|
|
private float DrawAngleHandle(Transform transform, float radius, float offset, Handles.CapFunction capLeft, Handles.CapFunction capRight, ref float angle)
|
|
{
|
|
float old = angle;
|
|
float handleOffset = HandleUtility.GetHandleSize(transform.position) * offset;
|
|
float handleSize = HandleUtility.GetHandleSize(transform.position) * k_AngleCapSize;
|
|
|
|
Quaternion rotLt = Quaternion.AngleAxis(-angle / 2, -transform.forward) * transform.rotation;
|
|
DrawAngleSlider2D(transform, rotLt, radius, handleOffset, capLeft, handleSize, true, true, true, ref angle);
|
|
|
|
Quaternion rotRt = Quaternion.AngleAxis(angle / 2, -transform.forward) * transform.rotation;
|
|
DrawAngleSlider2D(transform, rotRt, radius, handleOffset, capRight, handleSize, false, true, true, ref angle);
|
|
|
|
return angle - old;
|
|
}
|
|
|
|
private void DrawRadiusArc(Transform transform, float radius, float angle, int steps, Handles.CapFunction capFunc, float capSize, bool even)
|
|
{
|
|
Handles.DrawWireArc(transform.position, transform.forward, Quaternion.AngleAxis(180 - angle / 2, transform.forward) * -transform.up, angle, radius);
|
|
}
|
|
|
|
Handles.CapFunction GetCapFunc(Texture texture, bool isAngleHandle)
|
|
{
|
|
return (controlID, position, rotation, size, eventType) => Light2DEditorUtility.GUITextureCap(controlID, texture, position, rotation, size, eventType, isAngleHandle);
|
|
}
|
|
|
|
private void DrawAngleHandles(Light2D light)
|
|
{
|
|
var oldColor = Handles.color;
|
|
Handles.color = Color.yellow;
|
|
|
|
float outerAngle = light.pointLightOuterAngle;
|
|
float diff = DrawAngleHandle(light.transform, light.pointLightOuterRadius, k_AngleCapOffset, GetCapFunc(Styles.lightCapTopRight, true), GetCapFunc(Styles.lightCapBottomRight, true), ref outerAngle);
|
|
light.pointLightOuterAngle = outerAngle;
|
|
|
|
if (diff != 0.0f)
|
|
light.pointLightInnerAngle = Mathf.Max(0.0f, light.pointLightInnerAngle + diff);
|
|
|
|
float innerAngle = light.pointLightInnerAngle;
|
|
diff = DrawAngleHandle(light.transform, light.pointLightOuterRadius, -k_AngleCapOffset, GetCapFunc(Styles.lightCapTopLeft, true), GetCapFunc(Styles.lightCapBottomLeft, true), ref innerAngle);
|
|
light.pointLightInnerAngle = innerAngle;
|
|
|
|
if (diff != 0.0f)
|
|
light.pointLightInnerAngle = light.pointLightInnerAngle < light.pointLightOuterAngle ? light.pointLightInnerAngle : light.pointLightOuterAngle;
|
|
|
|
light.pointLightInnerAngle = Mathf.Min(light.pointLightInnerAngle, light.pointLightOuterAngle);
|
|
|
|
Handles.color = oldColor;
|
|
}
|
|
|
|
private void DrawRangeHandles(Light2D light)
|
|
{
|
|
var dummy = 0.0f;
|
|
bool radiusChanged = false;
|
|
Vector3 handlePos = Vector3.zero;
|
|
Quaternion rotLeft = Quaternion.AngleAxis(0, -light.transform.forward) * light.transform.rotation;
|
|
float handleOffset = HandleUtility.GetHandleSize(light.transform.position) * k_AngleCapOffsetSecondary;
|
|
float handleSize = HandleUtility.GetHandleSize(light.transform.position) * k_AngleCapSize;
|
|
|
|
var oldColor = Handles.color;
|
|
Handles.color = Color.yellow;
|
|
|
|
float outerRadius = light.pointLightOuterRadius;
|
|
EditorGUI.BeginChangeCheck();
|
|
Vector3 returnPos = DrawAngleSlider2D(light.transform, rotLeft, outerRadius, -handleOffset, GetCapFunc(Styles.lightCapUp, false), handleSize, false, false, false, ref dummy);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
var vec = (returnPos - light.transform.position).normalized;
|
|
light.transform.up = new Vector3(vec.x, vec.y, 0);
|
|
outerRadius = (returnPos - light.transform.position).magnitude;
|
|
outerRadius = outerRadius + handleOffset;
|
|
radiusChanged = true;
|
|
}
|
|
DrawRadiusArc(light.transform, light.pointLightOuterRadius, light.pointLightOuterAngle, 0, Handles.DotHandleCap, k_RangeCapSize, false);
|
|
|
|
Handles.color = Color.gray;
|
|
float innerRadius = light.pointLightInnerRadius;
|
|
EditorGUI.BeginChangeCheck();
|
|
returnPos = DrawAngleSlider2D(light.transform, rotLeft, innerRadius, handleOffset, GetCapFunc(Styles.lightCapDown, false), handleSize, true, false, false, ref dummy);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
innerRadius = (returnPos - light.transform.position).magnitude;
|
|
innerRadius = innerRadius - handleOffset;
|
|
radiusChanged = true;
|
|
}
|
|
DrawRadiusArc(light.transform, light.pointLightInnerRadius, light.pointLightOuterAngle, 0, Handles.SphereHandleCap, k_InnerRangeCapSize, false);
|
|
|
|
Handles.color = oldColor;
|
|
|
|
if (radiusChanged)
|
|
{
|
|
light.pointLightInnerRadius = (outerRadius < innerRadius) ? outerRadius : innerRadius;
|
|
light.pointLightOuterRadius = (innerRadius > outerRadius) ? innerRadius : outerRadius;
|
|
}
|
|
}
|
|
|
|
void OnSceneGUI()
|
|
{
|
|
var light = target as Light2D;
|
|
if (light == null)
|
|
return;
|
|
|
|
Transform t = light.transform;
|
|
switch (light.lightType)
|
|
{
|
|
case Light2D.LightType.Point:
|
|
{
|
|
Undo.RecordObject(light.transform, "Edit Point Light Transform");
|
|
Undo.RecordObject(light, "Edit Point Light");
|
|
|
|
DrawRangeHandles(light);
|
|
DrawAngleHandles(light);
|
|
|
|
if (GUI.changed)
|
|
EditorUtility.SetDirty(light);
|
|
}
|
|
break;
|
|
case Light2D.LightType.Sprite:
|
|
{
|
|
var cookieSprite = light.lightCookieSprite;
|
|
if (cookieSprite != null)
|
|
{
|
|
Vector3 min = cookieSprite.bounds.min;
|
|
Vector3 max = cookieSprite.bounds.max;
|
|
|
|
Vector3 v0 = t.TransformPoint(new Vector3(min.x, min.y));
|
|
Vector3 v1 = t.TransformPoint(new Vector3(max.x, min.y));
|
|
Vector3 v2 = t.TransformPoint(new Vector3(max.x, max.y));
|
|
Vector3 v3 = t.TransformPoint(new Vector3(min.x, max.y));
|
|
|
|
Handles.DrawLine(v0, v1);
|
|
Handles.DrawLine(v1, v2);
|
|
Handles.DrawLine(v2, v3);
|
|
Handles.DrawLine(v3, v0);
|
|
}
|
|
}
|
|
break;
|
|
case Light2D.LightType.Parametric:
|
|
{
|
|
float radius = light.shapeLightParametricRadius;
|
|
float sides = light.shapeLightParametricSides;
|
|
float angleOffset = Mathf.PI / 2.0f + Mathf.Deg2Rad * light.shapeLightParametricAngleOffset;
|
|
|
|
if (sides < 3)
|
|
sides = 3;
|
|
|
|
if (sides == 4)
|
|
angleOffset = Mathf.PI / 4.0f + Mathf.Deg2Rad * light.shapeLightParametricAngleOffset;
|
|
|
|
Vector3 direction = new Vector3(Mathf.Cos(angleOffset), Mathf.Sin(angleOffset), 0);
|
|
Vector3 startPoint = radius * direction;
|
|
Vector3 featherStartPoint = startPoint + light.shapeLightFalloffSize * direction;
|
|
float radiansPerSide = 2 * Mathf.PI / sides;
|
|
Vector3 falloffOffset = light.shapeLightFalloffOffset;
|
|
|
|
for (int i = 0; i < sides; ++i)
|
|
{
|
|
float endAngle = (i + 1) * radiansPerSide;
|
|
|
|
direction = new Vector3(Mathf.Cos(endAngle + angleOffset), Mathf.Sin(endAngle + angleOffset), 0);
|
|
Vector3 endPoint = radius * direction;
|
|
Vector3 featherEndPoint = endPoint + light.shapeLightFalloffSize * direction;
|
|
|
|
Handles.DrawLine(t.TransformPoint(startPoint), t.TransformPoint(endPoint));
|
|
Handles.DrawLine(t.TransformPoint(featherStartPoint + falloffOffset), t.TransformPoint(featherEndPoint + falloffOffset));
|
|
|
|
startPoint = endPoint;
|
|
featherStartPoint = featherEndPoint;
|
|
}
|
|
}
|
|
break;
|
|
case Light2D.LightType.Freeform:
|
|
{
|
|
// Draw the falloff shape's outline
|
|
List<Vector2> falloffShape = light.GetFalloffShape();
|
|
Handles.color = Color.white;
|
|
|
|
for (int i = 0; i < falloffShape.Count - 1; ++i)
|
|
{
|
|
Handles.DrawLine(t.TransformPoint(falloffShape[i]), t.TransformPoint(falloffShape[i + 1]));
|
|
Handles.DrawLine(t.TransformPoint(light.shapePath[i]), t.TransformPoint(light.shapePath[i + 1]));
|
|
}
|
|
|
|
Handles.DrawLine(t.TransformPoint(falloffShape[falloffShape.Count - 1]), t.TransformPoint(falloffShape[0]));
|
|
Handles.DrawLine(t.TransformPoint(light.shapePath[falloffShape.Count - 1]), t.TransformPoint(light.shapePath[0]));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
UniversalRenderPipeline pipeline = UnityEngine.Rendering.RenderPipelineManager.currentPipeline as UniversalRenderPipeline;
|
|
if (pipeline == null)
|
|
{
|
|
EditorGUILayout.HelpBox(Styles.renderPipelineUnassignedWarning);
|
|
return;
|
|
}
|
|
|
|
UniversalRenderPipelineAsset asset = UniversalRenderPipeline.asset;
|
|
Renderer2DData assetData = asset.scriptableRendererData as Renderer2DData;
|
|
if(assetData == null)
|
|
{
|
|
EditorGUILayout.HelpBox(Styles.asset2DUnassignedWarning);
|
|
return;
|
|
}
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
serializedObject.Update();
|
|
|
|
EditorGUILayout.PropertyField(m_LightType, Styles.generalLightType);
|
|
m_LastLightType = m_LightType.intValue;
|
|
|
|
switch (m_LightType.intValue)
|
|
{
|
|
case (int)Light2D.LightType.Point:
|
|
{
|
|
OnPointLight(serializedObject);
|
|
}
|
|
break;
|
|
case (int)Light2D.LightType.Parametric:
|
|
case (int)Light2D.LightType.Freeform:
|
|
case (int)Light2D.LightType.Sprite:
|
|
{
|
|
OnShapeLight((Light2D.LightType)m_LightType.intValue, serializedObject);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(m_LightType.intValue != (int)Light2D.LightType.Global)
|
|
EditorGUILayout.PropertyField(m_AlphaBlendOnOverlap, Styles.generalLightOverlapMode);
|
|
|
|
EditorGUILayout.PropertyField(m_LightOrder, Styles.generalLightOrder);
|
|
|
|
EditorGUILayout.IntPopup(m_BlendStyleIndex, m_BlendStyleNames, m_BlendStyleIndices, Styles.generalBlendStyle);
|
|
EditorGUILayout.PropertyField(m_LightColor, Styles.generalLightColor);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.PropertyField(m_LightIntensity, Styles.generalLightIntensity);
|
|
if (EditorGUI.EndChangeCheck())
|
|
m_LightIntensity.floatValue = Mathf.Max(m_LightIntensity.floatValue, 0);
|
|
|
|
if (m_LightType.intValue != (int)Light2D.LightType.Global)
|
|
{
|
|
EditorGUILayout.PropertyField(m_UseNormalMap, Styles.generalUseNormalMap);
|
|
|
|
if (m_UseNormalMap.boolValue)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.PropertyField(m_PointZDistance, Styles.pointLightZDistance);
|
|
if (EditorGUI.EndChangeCheck())
|
|
m_PointZDistance.floatValue = Mathf.Max(0.0f, m_PointZDistance.floatValue);
|
|
EditorGUILayout.PropertyField(m_PointLightQuality, Styles.pointLightQuality);
|
|
}
|
|
|
|
EditorGUILayout.Slider(m_VolumetricAlpha, 0, 1, Styles.generalVolumeOpacity);
|
|
}
|
|
|
|
OnTargetSortingLayers();
|
|
|
|
if (m_LightType.intValue == (int)Light2D.LightType.Freeform)
|
|
{
|
|
DoEditButton<FreeformShapeTool>(PathEditorToolContents.icon, "Edit Shape");
|
|
DoPathInspector<FreeformShapeTool>();
|
|
DoSnappingInspector<FreeformShapeTool>();
|
|
}
|
|
|
|
AnalyticsTrackChanges(serializedObject);
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
}
|
|
}
|