123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- using System;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- using UnityEngine;
- using UnityEngine.Rendering;
- using UnityEngine.Rendering.Universal;
- #if XR_MANAGEMENT_4_0_1_OR_NEWER
- using UnityEditor.XR.Management;
- #endif
-
- namespace UnityEditor.Rendering.Universal
- {
- using CED = CoreEditorDrawer<UniversalRenderPipelineSerializedLight>;
-
- internal partial class UniversalRenderPipelineLightUI
- {
- [URPHelpURL("light-component")]
- enum Expandable
- {
- General = 1 << 0,
- Shape = 1 << 1,
- Emission = 1 << 2,
- Rendering = 1 << 3,
- Shadows = 1 << 4,
- LightCookie = 1 << 5
- }
-
- static readonly ExpandedState<Expandable, Light> k_ExpandedState = new(~-1, "URP");
-
- public static readonly CED.IDrawer Inspector = CED.Group(
- CED.Conditional(
- (_, __) =>
- {
- if (SceneView.lastActiveSceneView == null)
- return false;
-
- #if UNITY_2019_1_OR_NEWER
- var sceneLighting = SceneView.lastActiveSceneView.sceneLighting;
- #else
- var sceneLighting = SceneView.lastActiveSceneView.m_SceneLighting;
- #endif
- return !sceneLighting;
- },
- (_, __) => EditorGUILayout.HelpBox(Styles.DisabledLightWarning.text, MessageType.Warning)),
- CED.FoldoutGroup(LightUI.Styles.generalHeader,
- Expandable.General,
- k_ExpandedState,
- DrawGeneralContent),
- CED.Conditional(
- (serializedLight, editor) => !serializedLight.settings.lightType.hasMultipleDifferentValues && serializedLight.settings.light.type == LightType.Spot,
- CED.FoldoutGroup(LightUI.Styles.shapeHeader, Expandable.Shape, k_ExpandedState, DrawSpotShapeContent)),
- CED.Conditional(
- (serializedLight, editor) =>
- {
- if (serializedLight.settings.lightType.hasMultipleDifferentValues)
- return false;
- var lightType = serializedLight.settings.light.type;
- return lightType == LightType.Rectangle || lightType == LightType.Disc;
- },
- CED.FoldoutGroup(LightUI.Styles.shapeHeader, Expandable.Shape, k_ExpandedState, DrawAreaShapeContent)),
- CED.FoldoutGroup(LightUI.Styles.emissionHeader,
- Expandable.Emission,
- k_ExpandedState,
- CED.Group(
- LightUI.DrawColor,
- DrawEmissionContent)),
- CED.FoldoutGroup(LightUI.Styles.renderingHeader,
- Expandable.Rendering,
- k_ExpandedState,
- DrawRenderingContent),
- CED.FoldoutGroup(LightUI.Styles.shadowHeader,
- Expandable.Shadows,
- k_ExpandedState,
- DrawShadowsContent)
- );
-
- static Func<int> s_SetGizmosDirty = SetGizmosDirty();
- static Func<int> SetGizmosDirty()
- {
- var type = Type.GetType("UnityEditor.AnnotationUtility,UnityEditor");
- var method = type.GetMethod("SetGizmosDirty", BindingFlags.Static | BindingFlags.NonPublic);
- var lambda = Expression.Lambda<Func<int>>(Expression.Call(method));
- return lambda.Compile();
- }
-
- static Action<GUIContent, SerializedProperty, LightEditor.Settings> k_SliderWithTexture = GetSliderWithTexture();
- static Action<GUIContent, SerializedProperty, LightEditor.Settings> GetSliderWithTexture()
- {
- //quicker than standard reflection as it is compiled
- var paramLabel = Expression.Parameter(typeof(GUIContent), "label");
- var paramProperty = Expression.Parameter(typeof(SerializedProperty), "property");
- var paramSettings = Expression.Parameter(typeof(LightEditor.Settings), "settings");
- System.Reflection.MethodInfo sliderWithTextureInfo = typeof(EditorGUILayout)
- .GetMethod(
- "SliderWithTexture",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static,
- null,
- System.Reflection.CallingConventions.Any,
- new[] { typeof(GUIContent), typeof(SerializedProperty), typeof(float), typeof(float), typeof(float), typeof(Texture2D), typeof(GUILayoutOption[]) },
- null);
- var sliderWithTextureCall = Expression.Call(
- sliderWithTextureInfo,
- paramLabel,
- paramProperty,
- Expression.Constant((float)typeof(LightEditor.Settings).GetField("kMinKelvin", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetRawConstantValue()),
- Expression.Constant((float)typeof(LightEditor.Settings).GetField("kMaxKelvin", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetRawConstantValue()),
- Expression.Constant((float)typeof(LightEditor.Settings).GetField("kSliderPower", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetRawConstantValue()),
- Expression.Field(paramSettings, typeof(LightEditor.Settings).GetField("m_KelvinGradientTexture", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)),
- Expression.Constant(null, typeof(GUILayoutOption[])));
- var lambda = Expression.Lambda<System.Action<GUIContent, SerializedProperty, LightEditor.Settings>>(sliderWithTextureCall, paramLabel, paramProperty, paramSettings);
- return lambda.Compile();
- }
-
- static void DrawGeneralContent(UniversalRenderPipelineSerializedLight serializedLight, Editor owner)
- {
- DrawGeneralContentInternal(serializedLight, owner, isInPreset: false);
- }
-
- static void DrawGeneralContentPreset(UniversalRenderPipelineSerializedLight serializedLight, Editor owner)
- {
- DrawGeneralContentInternal(serializedLight, owner, isInPreset: true);
- }
-
- static void DrawGeneralContentInternal(UniversalRenderPipelineSerializedLight serializedLight, Editor owner, bool isInPreset)
- {
- // To the user, we will only display it as a area light, but under the hood, we have Rectangle and Disc. This is not to confuse people
- // who still use our legacy light inspector.
-
- int selectedLightType = serializedLight.settings.lightType.intValue;
-
- // Handle all lights that are not in the default set
- if (!Styles.LightTypeValues.Contains(serializedLight.settings.lightType.intValue))
- {
- if (serializedLight.settings.lightType.intValue == (int)LightType.Disc)
- {
- selectedLightType = (int)LightType.Rectangle;
- }
- }
-
- var rect = EditorGUILayout.GetControlRect();
- EditorGUI.BeginProperty(rect, Styles.Type, serializedLight.settings.lightType);
- EditorGUI.BeginChangeCheck();
- int type;
- if (Styles.LightTypeValues.Contains(selectedLightType))
- {
- // ^ The currently selected light type is supported in the
- // current pipeline.
- type = EditorGUI.IntPopup(rect, Styles.Type, selectedLightType, Styles.LightTypeTitles, Styles.LightTypeValues);
- }
- else
- {
- // ^ The currently selected light type is not supported in
- // the current pipeline. Add it to the dropdown, since it
- // would show up as a blank entry.
- string currentTitle = ((LightType)selectedLightType).ToString();
- GUIContent[] titles = Styles.LightTypeTitles.Append(EditorGUIUtility.TrTextContent(currentTitle)).ToArray();
- int[] values = Styles.LightTypeValues.Append(selectedLightType).ToArray();
- type = EditorGUI.IntPopup(rect, Styles.Type, selectedLightType, titles, values);
- }
-
- if (EditorGUI.EndChangeCheck())
- {
- s_SetGizmosDirty();
- serializedLight.settings.lightType.intValue = type;
- }
- EditorGUI.EndProperty();
-
- if (!Styles.LightTypeValues.Contains(type))
- {
- EditorGUILayout.HelpBox(
- "This light type is not supported in the current active render pipeline. Change the light type or the active Render Pipeline to use this light.",
- MessageType.Info
- );
- }
-
- Light light = serializedLight.settings.light;
- var lightType = light.type;
- if (LightType.Directional != lightType && light == RenderSettings.sun)
- {
- EditorGUILayout.HelpBox(Styles.SunSourceWarning.text, MessageType.Warning);
- }
-
- if (!serializedLight.settings.lightType.hasMultipleDifferentValues)
- {
- using (new EditorGUI.DisabledScope(serializedLight.settings.isAreaLightType))
- serializedLight.settings.DrawLightmapping();
-
- if (serializedLight.settings.isAreaLightType && serializedLight.settings.lightmapping.intValue != (int)LightmapBakeType.Baked)
- {
- serializedLight.settings.lightmapping.intValue = (int)LightmapBakeType.Baked;
- serializedLight.Apply();
- }
- }
- }
-
- internal static void SyncLightAndShadowLayers(UniversalRenderPipelineSerializedLight serializedLight, SerializedProperty serialized)
- {
- // If we're not in decoupled mode for light layers, we sync light with shadow layers.
- // In mixed state, it makes sense to do it only on Light that links the mode.
- foreach (var lightTarget in serializedLight.serializedObject.targetObjects)
- {
- var additionData = (lightTarget as Component).gameObject.GetComponent<UniversalAdditionalLightData>();
- if (additionData.customShadowLayers)
- continue;
-
- Light target = lightTarget as Light;
- if (target.renderingLayerMask != serialized.intValue)
- target.renderingLayerMask = serialized.intValue;
- }
- }
-
- static void DrawSpotShapeContent(UniversalRenderPipelineSerializedLight serializedLight, Editor owner)
- {
- serializedLight.settings.DrawInnerAndOuterSpotAngle();
- }
-
- static void DrawAreaShapeContent(UniversalRenderPipelineSerializedLight serializedLight, Editor owner)
- {
- int selectedShape = serializedLight.settings.isAreaLightType ? serializedLight.settings.lightType.intValue : 0;
-
- // Handle all lights that are not in the default set
- if (!Styles.LightTypeValues.Contains(serializedLight.settings.lightType.intValue))
- {
- if (serializedLight.settings.lightType.intValue == (int)LightType.Disc)
- {
- selectedShape = (int)LightType.Disc;
- }
- }
-
- var rect = EditorGUILayout.GetControlRect();
- EditorGUI.BeginProperty(rect, Styles.AreaLightShapeContent, serializedLight.settings.lightType);
- EditorGUI.BeginChangeCheck();
- int shape = EditorGUI.IntPopup(rect, Styles.AreaLightShapeContent, selectedShape, Styles.AreaLightShapeTitles, Styles.AreaLightShapeValues);
-
- if (EditorGUI.EndChangeCheck())
- {
- Undo.RecordObject(serializedLight.settings.light, "Adjust Light Shape");
- serializedLight.settings.lightType.intValue = shape;
- }
- EditorGUI.EndProperty();
-
- using (new EditorGUI.IndentLevelScope())
- serializedLight.settings.DrawArea();
- }
-
- static void DrawEmissionContent(UniversalRenderPipelineSerializedLight serializedLight, Editor owner)
- {
- serializedLight.settings.DrawIntensity();
- serializedLight.settings.DrawBounceIntensity();
-
- if (!serializedLight.settings.lightType.hasMultipleDifferentValues)
- {
- var lightType = serializedLight.settings.light.type;
- if (lightType != LightType.Directional)
- {
- #if UNITY_2020_1_OR_NEWER
- serializedLight.settings.DrawRange();
- #else
- serializedLight.settings.DrawRange(false);
- #endif
- }
- }
-
- DrawLightCookieContent(serializedLight, owner);
- }
-
- static void DrawRenderingContent(UniversalRenderPipelineSerializedLight serializedLight, Editor owner)
- {
- if (serializedLight.settings.light.type != LightType.Rectangle &&
- !serializedLight.settings.isCompletelyBaked)
- {
- EditorGUI.BeginChangeCheck();
- GUI.enabled = UniversalRenderPipeline.asset.useRenderingLayers;
- EditorUtils.DrawRenderingLayerMask(
- serializedLight.renderingLayers,
- UniversalRenderPipeline.asset.useRenderingLayers ? Styles.RenderingLayers : Styles.RenderingLayersDisabled
- );
- GUI.enabled = true;
- if (EditorGUI.EndChangeCheck())
- {
- if (!serializedLight.customShadowLayers.boolValue)
- SyncLightAndShadowLayers(serializedLight, serializedLight.renderingLayers);
- }
- }
-
- EditorGUILayout.PropertyField(serializedLight.settings.cullingMask, Styles.CullingMask);
- if (serializedLight.settings.cullingMask.intValue != -1)
- {
- EditorGUILayout.HelpBox(Styles.CullingMaskWarning.text, MessageType.Info);
- }
- }
-
- static void DrawShadowsContent(UniversalRenderPipelineSerializedLight serializedLight, Editor owner)
- {
- if (serializedLight.settings.lightType.hasMultipleDifferentValues)
- {
- EditorGUILayout.HelpBox("Cannot multi edit shadows from different light types.", MessageType.Info);
- return;
- }
-
- serializedLight.settings.DrawShadowsType();
-
- if (serializedLight.settings.shadowsType.hasMultipleDifferentValues)
- {
- EditorGUILayout.HelpBox("Cannot multi edit different shadow types", MessageType.Info);
- return;
- }
-
- if (serializedLight.settings.light.shadows == LightShadows.None)
- return;
-
- var lightType = serializedLight.settings.light.type;
-
- using (new EditorGUI.IndentLevelScope())
- {
- if (serializedLight.settings.isBakedOrMixed)
- {
- switch (lightType)
- {
- // Baked Shadow radius
- case LightType.Point:
- case LightType.Spot:
- serializedLight.settings.DrawBakedShadowRadius();
- break;
- case LightType.Directional:
- serializedLight.settings.DrawBakedShadowAngle();
- break;
- }
- }
-
- if (lightType != LightType.Rectangle && !serializedLight.settings.isCompletelyBaked)
- {
- EditorGUILayout.LabelField(Styles.ShadowRealtimeSettings, EditorStyles.boldLabel);
- using (new EditorGUI.IndentLevelScope())
- {
- // Resolution
- if (lightType == LightType.Point || lightType == LightType.Spot)
- DrawShadowsResolutionGUI(serializedLight);
-
- EditorGUILayout.Slider(serializedLight.settings.shadowsStrength, 0f, 1f, Styles.ShadowStrength);
-
- // Bias
- DrawAdditionalShadowData(serializedLight, owner);
-
- // this min bound should match the calculation in SharedLightData::GetNearPlaneMinBound()
- float nearPlaneMinBound = Mathf.Min(0.01f * serializedLight.settings.range.floatValue, 0.1f);
- EditorGUILayout.Slider(serializedLight.settings.shadowsNearPlane, nearPlaneMinBound, 10.0f, Styles.ShadowNearPlane);
- var isHololens = false;
- var isQuest = false;
- #if XR_MANAGEMENT_4_0_1_OR_NEWER
- var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
- var buildTargetSettings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(buildTargetGroup);
- if (buildTargetSettings != null && buildTargetSettings.AssignedSettings != null && buildTargetSettings.AssignedSettings.activeLoaders.Count > 0)
- {
- isHololens = buildTargetGroup == BuildTargetGroup.WSA;
- isQuest = buildTargetGroup == BuildTargetGroup.Android;
- }
-
- #endif
- // Soft Shadow Quality
- if (serializedLight.settings.light.shadows == LightShadows.Soft)
- EditorGUILayout.PropertyField(serializedLight.softShadowQualityProp, Styles.SoftShadowQuality);
-
- if (isHololens || isQuest)
- {
- EditorGUILayout.HelpBox(
- "Per-light soft shadow quality level is not supported on HoloLens and Oculus platforms. Use the Soft Shadow Quality setting in the URP Asset instead",
- MessageType.Warning
- );
- }
-
- }
-
- if (UniversalRenderPipeline.asset.useRenderingLayers)
- {
- EditorGUI.BeginChangeCheck();
- EditorGUILayout.PropertyField(serializedLight.customShadowLayers, Styles.customShadowLayers);
- // Undo the changes in the light component because the SyncLightAndShadowLayers will change the value automatically when link is ticked
- if (EditorGUI.EndChangeCheck())
- {
- if (serializedLight.customShadowLayers.boolValue)
- {
- serializedLight.settings.light.renderingLayerMask = serializedLight.shadowRenderingLayers.intValue;
- }
- else
- {
- serializedLight.serializedAdditionalDataObject.ApplyModifiedProperties(); // we need to push above modification the modification on object as it is used to sync
- SyncLightAndShadowLayers(serializedLight, serializedLight.renderingLayers);
- }
- }
-
- if (serializedLight.customShadowLayers.boolValue)
- {
- using (new EditorGUI.IndentLevelScope())
- {
- EditorGUI.BeginChangeCheck();
- EditorUtils.DrawRenderingLayerMask(serializedLight.shadowRenderingLayers, Styles.ShadowLayer);
- if (EditorGUI.EndChangeCheck())
- {
- serializedLight.settings.light.renderingLayerMask = serializedLight.shadowRenderingLayers.intValue;
- serializedLight.Apply();
- }
- }
- }
- }
- }
- }
-
- if (!UnityEditor.Lightmapping.bakedGI && !serializedLight.settings.lightmapping.hasMultipleDifferentValues && serializedLight.settings.isBakedOrMixed)
- EditorGUILayout.HelpBox(Styles.BakingWarning.text, MessageType.Warning);
- }
-
- static void DrawAdditionalShadowData(UniversalRenderPipelineSerializedLight serializedLight, Editor editor)
- {
- // 0: Custom bias - 1: Bias values defined in Pipeline settings
- int selectedUseAdditionalData = serializedLight.additionalLightData.usePipelineSettings ? 1 : 0;
- Rect r = EditorGUILayout.GetControlRect(true);
- EditorGUI.BeginProperty(r, Styles.shadowBias, serializedLight.useAdditionalDataProp);
- {
- using (var checkScope = new EditorGUI.ChangeCheckScope())
- {
- selectedUseAdditionalData = EditorGUI.IntPopup(r, Styles.shadowBias, selectedUseAdditionalData, Styles.displayedDefaultOptions, Styles.optionDefaultValues);
- if (checkScope.changed)
- {
- Undo.RecordObjects(serializedLight.lightsAdditionalData, "Modified light additional data");
- foreach (var additionData in serializedLight.lightsAdditionalData)
- additionData.usePipelineSettings = selectedUseAdditionalData != 0;
-
- serializedLight.Apply();
- (editor as UniversalRenderPipelineLightEditor)?.ReconstructReferenceToAdditionalDataSO();
- }
- }
- }
- EditorGUI.EndProperty();
-
- if (!serializedLight.useAdditionalDataProp.hasMultipleDifferentValues)
- {
- if (selectedUseAdditionalData != 1) // Custom Bias
- {
- using (new EditorGUI.IndentLevelScope())
- {
- using (var checkScope = new EditorGUI.ChangeCheckScope())
- {
- EditorGUILayout.Slider(serializedLight.settings.shadowsBias, 0f, 10f, Styles.ShadowDepthBias);
- EditorGUILayout.Slider(serializedLight.settings.shadowsNormalBias, 0f, 10f, Styles.ShadowNormalBias);
- if (checkScope.changed)
- serializedLight.Apply();
- }
- }
- }
- }
- }
-
- static void DrawShadowsResolutionGUI(UniversalRenderPipelineSerializedLight serializedLight)
- {
- int shadowResolutionTier = serializedLight.additionalLightData.additionalLightsShadowResolutionTier;
-
- using (new EditorGUILayout.HorizontalScope())
- {
- using (var checkScope = new EditorGUI.ChangeCheckScope())
- {
- Rect r = EditorGUILayout.GetControlRect(true);
- r.width += 30;
-
- shadowResolutionTier = EditorGUI.IntPopup(r, Styles.ShadowResolution, shadowResolutionTier, Styles.ShadowResolutionDefaultOptions, Styles.ShadowResolutionDefaultValues);
- if (shadowResolutionTier == UniversalAdditionalLightData.AdditionalLightsShadowResolutionTierCustom)
- {
- // show the custom value field GUI.
- var newResolution = EditorGUILayout.IntField(serializedLight.settings.shadowsResolution.intValue, GUILayout.ExpandWidth(false));
- serializedLight.settings.shadowsResolution.intValue = Mathf.Max(UniversalAdditionalLightData.AdditionalLightsShadowMinimumResolution, Mathf.NextPowerOfTwo(newResolution));
- }
- else
- {
- if (GraphicsSettings.currentRenderPipeline is UniversalRenderPipelineAsset urpAsset)
- EditorGUILayout.LabelField($"{urpAsset.GetAdditionalLightsShadowResolution(shadowResolutionTier)} ({urpAsset.name})", GUILayout.ExpandWidth(false));
- }
- if (checkScope.changed)
- {
- serializedLight.additionalLightsShadowResolutionTierProp.intValue = shadowResolutionTier;
- serializedLight.Apply();
- }
- }
- }
-
- EditorGUILayout.HelpBox(Styles.ShadowInfo.text, MessageType.Info);
- }
-
- static void DrawLightCookieContent(UniversalRenderPipelineSerializedLight serializedLight, Editor owner)
- {
- var settings = serializedLight.settings;
- if (settings.lightType.hasMultipleDifferentValues)
- {
- EditorGUILayout.HelpBox("Cannot multi edit light cookies from different light types.", MessageType.Info);
- return;
- }
-
- settings.DrawCookie();
-
- // Draw 2D cookie size for directional lights
- bool isDirectionalLight = settings.light.type == LightType.Directional;
- if (isDirectionalLight)
- {
- if (settings.cookie != null)
- {
- EditorGUI.BeginChangeCheck();
- EditorGUILayout.PropertyField(serializedLight.lightCookieSizeProp, Styles.LightCookieSize);
- EditorGUILayout.PropertyField(serializedLight.lightCookieOffsetProp, Styles.LightCookieOffset);
- if (EditorGUI.EndChangeCheck())
- Experimental.Lightmapping.SetLightDirty((UnityEngine.Light)serializedLight.serializedObject.targetObject);
- }
- }
- }
- }
- }
|