using System; using UnityEngine; using UnityEngine.Rendering; namespace UnityEditor.Rendering { internal enum DirectionalLightUnit { Lux = LightUnit.Lux, } internal enum AreaLightUnit { Lumen = LightUnit.Lumen, Nits = LightUnit.Nits, Ev100 = LightUnit.Ev100, } internal enum PunctualLightUnit { Lumen = LightUnit.Lumen, Candela = LightUnit.Candela, Lux = LightUnit.Lux, Ev100 = LightUnit.Ev100 } /// /// Contains a set of methods to help render the inspectors of Lights across SRP's /// public partial class LightUI { /// /// Draws the color temperature for a serialized light /// /// The serizalized light /// The editor public static void DrawColor(ISerializedLight serialized, Editor owner) { if (GraphicsSettings.lightsUseLinearIntensity && GraphicsSettings.lightsUseColorTemperature) { // Use the color temperature bool to create a popup dropdown to choose between the two modes. var serializedUseColorTemperature = serialized.settings.useColorTemperature; using (var check = new EditorGUI.ChangeCheckScope()) using (new EditorGUI.MixedValueScope(serializedUseColorTemperature.hasMultipleDifferentValues)) { var colorTemperaturePopupValue = Convert.ToInt32(serializedUseColorTemperature.boolValue); colorTemperaturePopupValue = EditorGUILayout.Popup(Styles.lightAppearance, colorTemperaturePopupValue, Styles.lightAppearanceOptions); if(check.changed) serializedUseColorTemperature.boolValue = Convert.ToBoolean(colorTemperaturePopupValue); } if (serialized.settings.useColorTemperature.boolValue) { EditorGUI.indentLevel += 1; EditorGUILayout.PropertyField(serialized.settings.color, Styles.colorFilter); // Light unit slider const int k_ValueUnitSeparator = 2; var lineRect = EditorGUILayout.GetControlRect(); var labelRect = lineRect; labelRect.width = EditorGUIUtility.labelWidth; EditorGUI.LabelField(labelRect, Styles.colorTemperature); var temperatureSliderRect = lineRect; temperatureSliderRect.x += EditorGUIUtility.labelWidth + k_ValueUnitSeparator; temperatureSliderRect.width -= EditorGUIUtility.labelWidth + k_ValueUnitSeparator; TemperatureSliderUIDrawer.Draw(serialized.settings, serialized.serializedObject, serialized.settings.colorTemperature, temperatureSliderRect); // Value and unit label // Match const defined in EditorGUI.cs const int k_IndentPerLevel = 15; const int k_UnitWidth = 60 + k_IndentPerLevel; int indent = k_IndentPerLevel * EditorGUI.indentLevel; Rect valueRect = EditorGUILayout.GetControlRect(); valueRect.width += indent - k_ValueUnitSeparator - k_UnitWidth; Rect unitRect = valueRect; unitRect.x += valueRect.width - indent + k_ValueUnitSeparator; unitRect.width = k_UnitWidth + k_ValueUnitSeparator; EditorGUI.PropertyField(valueRect, serialized.settings.colorTemperature, CoreEditorStyles.empty); EditorGUI.LabelField(unitRect, Styles.lightAppearanceUnits[0]); EditorGUI.indentLevel -= 1; } else EditorGUILayout.PropertyField(serialized.settings.color, Styles.color); } else EditorGUILayout.PropertyField(serialized.settings.color, Styles.color); } /// /// Draws the intensity field and slider, including the light unit dropdown for a serialized light. /// /// The serialized light. /// The editor. public static void DrawIntensity(ISerializedLight serialized, Editor owner) { // Match const defined in EditorGUI.cs const int k_IndentPerLevel = 15; const int k_ValueUnitSeparator = 2; const int k_UnitWidth = 100; float indent = k_IndentPerLevel * EditorGUI.indentLevel; Rect lineRect = EditorGUILayout.GetControlRect(); Rect labelRect = lineRect; labelRect.width = EditorGUIUtility.labelWidth; // Expand to reach both lines of the intensity field. var interlineOffset = EditorGUIUtility.singleLineHeight + 2f; labelRect.height += interlineOffset; //handling of prefab overrides in a parent label GUIContent parentLabel = Styles.lightIntensity; parentLabel = EditorGUI.BeginProperty(labelRect, parentLabel, serialized.settings.lightUnit); parentLabel = EditorGUI.BeginProperty(labelRect, parentLabel, serialized.settings.intensity); { // Restore the original rect for actually drawing the label. labelRect.height -= interlineOffset; EditorGUI.LabelField(labelRect, parentLabel); } EditorGUI.EndProperty(); EditorGUI.EndProperty(); Light light = serialized.settings.light; LightType lightType = serialized.settings.lightType.GetEnumValue(); LightUnit nativeUnit = LightUnitUtils.GetNativeLightUnit(lightType); LightUnit lightUnit = serialized.settings.lightUnit.GetEnumValue(); float nativeIntensity = serialized.settings.intensity.floatValue; // Verify that ui light unit is in fact supported or revert to native. lightUnit = LightUnitUtils.IsLightUnitSupported(lightType, lightUnit) ? lightUnit : nativeUnit; // Draw the light unit slider + icon + tooltip Rect lightUnitSliderRect = lineRect; // TODO: Move the value and unit rects to new line lightUnitSliderRect.x += EditorGUIUtility.labelWidth + k_ValueUnitSeparator; lightUnitSliderRect.width -= EditorGUIUtility.labelWidth + k_ValueUnitSeparator; LightIntensitySlider.Draw(serialized, owner, lightUnitSliderRect); // We use PropertyField to draw the value to keep the handle at left of the field // This will apply the indent again thus we need to remove it time for alignment Rect valueRect = EditorGUILayout.GetControlRect(); labelRect.width = EditorGUIUtility.labelWidth; valueRect.width += indent - k_ValueUnitSeparator - k_UnitWidth; Rect unitRect = valueRect; unitRect.x += valueRect.width - indent + k_ValueUnitSeparator; unitRect.width = k_UnitWidth + .5f; // Draw the intensity float field EditorGUI.BeginChangeCheck(); float curIntensity = LightUnitUtils.ConvertIntensity(light, nativeIntensity, nativeUnit, lightUnit); EditorGUI.showMixedValue = serialized.settings.lightUnit.hasMultipleDifferentValues; float newIntensity = EditorGUI.FloatField(valueRect, CoreEditorStyles.empty, curIntensity); if (EditorGUI.EndChangeCheck()) { serialized.settings.intensity.floatValue = Mathf.Max( 0f, LightUnitUtils.ConvertIntensity(light, newIntensity, lightUnit, nativeUnit) ); } EditorGUI.showMixedValue = false; // Draw the light unit dropdown { EditorGUI.BeginChangeCheck(); EditorGUI.BeginProperty(unitRect, GUIContent.none, serialized.settings.lightUnit); EditorGUI.showMixedValue = serialized.settings.lightUnit.hasMultipleDifferentValues; LightUnit selectedLightUnit = DrawLightIntensityUnitPopup( unitRect, serialized.settings.lightUnit.GetEnumValue(), lightType ); EditorGUI.showMixedValue = false; EditorGUI.EndProperty(); if (EditorGUI.EndChangeCheck()) { serialized.settings.lightUnit.SetEnumValue(selectedLightUnit); } } } /// /// Draws additional light intensity modifiers, depending on light type/unit for a serialized light. /// /// The serialized light. /// If true, the reflector checkbox will be hidden. public static void DrawIntensityModifiers(ISerializedLight serialized, bool hideReflector = false) { LightType lightType = serialized.settings.lightType.GetEnumValue(); LightUnit lightUnit = serialized.settings.lightUnit.GetEnumValue(); // Draw the "Lux At Distance" field if (lightType != LightType.Directional && lightType != LightType.Box && lightUnit == LightUnit.Lux) { // Box and directional lights shouldn't display this widget, since their light source are considered to // be at infinity, and the distance is always infinity. So we only display this widget for light types // that support the Lux unit, and whose sources aren't positioned at infinity. EditorGUI.indentLevel++; EditorGUI.BeginChangeCheck(); float oldLuxAtDistance = serialized.settings.luxAtDistance.floatValue; EditorGUILayout.PropertyField(serialized.settings.luxAtDistance, Styles.luxAtDistance); if (EditorGUI.EndChangeCheck()) { serialized.settings.luxAtDistance.floatValue = Mathf.Max(serialized.settings.luxAtDistance.floatValue, 0.01f); // Derive the lux from intensity, which is in Candela, and the old distance value float lux = LightUnitUtils.CandelaToLux(serialized.settings.intensity.floatValue, oldLuxAtDistance); // Calculate the new intensity in Candela from the lux value, and the new distance serialized.settings.intensity.floatValue = LightUnitUtils.LuxToCandela(lux, serialized.settings.luxAtDistance.floatValue); } EditorGUI.indentLevel--; } // Draw the "Reflector" checkbox if ((lightType == LightType.Spot || lightType == LightType.Pyramid) && lightUnit == (int)LightUnit.Lumen && !hideReflector) { EditorGUI.indentLevel++; EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(serialized.settings.enableSpotReflector, Styles.enableSpotReflector); if (EditorGUI.EndChangeCheck()) { // ^ The reflector bool has changed, and the light unit is set to Lumen. Update the intensity (in Candela). float oldCandela = serialized.settings.intensity.floatValue; float spotAngle = serialized.settings.spotAngle.floatValue; float aspectRatio = serialized.settings.areaSizeX.floatValue; bool enableSpotReflector = serialized.settings.enableSpotReflector.boolValue; float oldSolidAngle = LightUnitUtils.GetSolidAngle(lightType, !enableSpotReflector, spotAngle, aspectRatio); float oldLumen = LightUnitUtils.CandelaToLumen(oldCandela, oldSolidAngle); float newSolidAngle = LightUnitUtils.GetSolidAngle(lightType, enableSpotReflector, spotAngle, aspectRatio); serialized.settings.intensity.floatValue = LightUnitUtils.LumenToCandela(oldLumen, newSolidAngle); } EditorGUI.indentLevel--; } } /// /// Draws a light unit dropdown. /// /// Rectangle on the screen to use for the field. /// The light unit the field shows. /// The type of the light. This determines which options are available. /// The light unit that has been selected by the user. public static LightUnit DrawLightIntensityUnitPopup(Rect position, LightUnit selected, LightType type) { switch (type) { case LightType.Box: case LightType.Directional: return (LightUnit)EditorGUI.EnumPopup(position, (DirectionalLightUnit)selected); case LightType.Point: case LightType.Spot: case LightType.Pyramid: return (LightUnit)EditorGUI.EnumPopup(position, (PunctualLightUnit)selected); default: return (LightUnit)EditorGUI.EnumPopup(position, (AreaLightUnit)selected); } } } }