Files
Cielonos/Assets/Plugins/FlexibleUI/Editor/FlexibleBlur/UIBlurEditor.cs
SoulliesOfficial 649b7a5ddc 更新
2026-05-23 08:27:50 -04:00

279 lines
15 KiB
C#

using System.Reflection;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace JeffGrawAssets.FlexibleUI
{
[CustomEditor(typeof(UIBlur))]
[CanEditMultipleObjects]
public class UIBlurEditor : Editor
{
private static GUIStyle _warningStyle;
private static GUIStyle WarningStyle
{
get
{
if (_warningStyle == null && EditorStyles.textField != null)
_warningStyle = new GUIStyle(EditorStyles.textField) { normal = { textColor = Color.yellow }, alignment = TextAnchor.MiddleCenter };
return _warningStyle ?? GUIStyle.none;
}
}
private static GUIStyle _errorStyle;
private static GUIStyle ErrorStyle
{
get
{
if (_errorStyle == null && EditorStyles.textField != null)
_errorStyle = new GUIStyle(EditorStyles.textField) { normal = { textColor = Color.red }, alignment = TextAnchor.MiddleCenter };
return _errorStyle ?? GUIStyle.none;
}
}
public static readonly GUIContent LayerContent = new ("Layer", $"The layer to which this Blur belongs. Lower layers are drawn first. {nameof(FlexibleBlurFeature)}.{FlexibleBlurFeature.UIBlurLayersSeeLowerFieldName}, {nameof(FlexibleBlurFeature)}.{FlexibleBlurFeature.BlurredImagesSeeUIBlursFieldName}, and {nameof(FlexibleBlurFeature)}.{FlexibleBlurFeature.BlurredImageLayersSeeLowerFieldName} control how layers interact with one another.");
public static readonly GUIContent PriorityContent = new ("Priority", "The order in which Blurs are processed within a layer (lower values are drawn first).");
public static readonly GUIContent BlurStrengthContent = new ("Blur Strength", "The overall strength of the blur effect. For static blurs (eg. blurs where the strength property never changes), it is *always* preferable to leave this at 1 and modify downscale/blur passes to achieve the desired outcome. Blurs with different blur strengths can never be batched.");
private static readonly GUIContent StayActiveAtZeroCanvasAlphaContent = new ("Active At 0 Canvas Alpha", $"By default, when Canvas alpha is 0 the {nameof(UIBlur)} will turn off to conserve performance. If you're trying to achieve a \"subtractive blur\" effect, this may be unwanted.");
public static readonly GUIContent BlurReferencesFromContent = new ("Blur References", $"Whether this component will supply its own references to the Camera to blur, and the {nameof(FlexibleBlurFeature)} on that Camera's renderer which will do the blurring, or whether those references will be supplied by a {nameof(BlurReferenceProvider)} component (which should be placed on the same GameObject as the Canvas).");
private static readonly GUIContent CameraReferenceContent = new ("Camera", "The Camera that supplies the blur effect. In other words the Camera whose output is seen by the component.");
public static readonly GUIContent FeatureNumberContent = new("Feature #", $"Which {nameof(FlexibleBlurFeature)} to use (there may be more than one belonging to the same renderer). Determined by the order of {nameof(FlexibleBlurFeature)}s in the renderer's feature list. Does not count any other type of feature (eg. if there are two {nameof(FlexibleBlurFeature)}s in the feature list, and 10 other features in between them in the list, then the first {nameof(FlexibleBlurFeature)} is #0 and the second is still #1).");
private ReorderableList downscaleSectionList;
private ReorderableList blurSectionList;
private BlurPresetEditor _blurEditor;
private BlurPresetEditor BlurEditor => _blurEditor != null
? _blurEditor
: _blurEditor = target is IBlur blur && blur.Common.blurPreset != null
? (BlurPresetEditor)CreateEditor(blur.Common.blurPreset)
: null;
private SerializedProperty stayActiveAtZeroCanvasAlphaProperty;
private SerializedProperty referencesFromProperty;
private SerializedProperty cameraReferencePoperty;
private SerializedProperty featureNumberProperty;
private SerializedProperty blurStrengthProperty;
private SerializedProperty priorityProperty;
private SerializedProperty layerProperty;
private SerializedProperty blurPresetProperty;
private SerializedProperty blurInstanceSettingsProperty;
private BlurPreset prevBlurPreset;
void OnEnable()
{
stayActiveAtZeroCanvasAlphaProperty = serializedObject.FindProperty(nameof(UIBlur.zeroCanvasAlphaActive));
referencesFromProperty = serializedObject.FindProperty($"{UIBlur.BlurCommonFieldName}.{nameof(UIBlurCommon.blurReferencesFrom)}");
cameraReferencePoperty = serializedObject.FindProperty($"{UIBlur.BlurCommonFieldName}.{nameof(UIBlurCommon.cameraReference)}");
featureNumberProperty = serializedObject.FindProperty($"{UIBlur.BlurCommonFieldName}.{nameof(UIBlurCommon.featureNumber)}");
blurStrengthProperty = serializedObject.FindProperty($"{UIBlur.BlurCommonFieldName}.{nameof(UIBlurCommon.blurStrength)}");
layerProperty = serializedObject.FindProperty($"{UIBlur.BlurCommonFieldName}.{nameof(UIBlurCommon.unrankedLayer)}");
priorityProperty = serializedObject.FindProperty($"{UIBlur.BlurCommonFieldName}.{nameof(UIBlurCommon.priority)}");
blurPresetProperty = serializedObject.FindProperty($"{UIBlur.BlurCommonFieldName}.{nameof(UIBlurCommon.blurPreset)}");
blurInstanceSettingsProperty = serializedObject.FindProperty($"{UIBlur.BlurCommonFieldName}.{nameof(UIBlurCommon.blurInstanceSettings)}");
}
void OnDisable()
{
if (_blurEditor == null)
return;
DestroyImmediate(_blurEditor);
_blurEditor = null;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(stayActiveAtZeroCanvasAlphaProperty, StayActiveAtZeroCanvasAlphaContent);
if (!DrawBlurCommonPropertiesOne(referencesFromProperty, cameraReferencePoperty, featureNumberProperty, ((UIBlur)serializedObject.targetObject).gameObject, nameof(UIBlur)))
return;
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
EditorGUILayout.PropertyField(blurStrengthProperty, BlurStrengthContent);
EditorGUILayout.BeginVertical(GUI.skin.box);
EditorGUILayout.PropertyField(layerProperty, LayerContent);
EditorGUILayout.PropertyField(priorityProperty, PriorityContent);
EditorGUILayout.EndVertical();
_ = BlurEditor;
EditorGUILayout.BeginVertical(GUI.skin.box);
DrawBlurCommonPropertiesTwo(serializedObject, blurPresetProperty, blurInstanceSettingsProperty, EditorGUIUtility.labelWidth, ref _blurEditor, ref prevBlurPreset, ref downscaleSectionList, ref blurSectionList);
serializedObject.ApplyModifiedProperties();
}
public static bool DrawBlurCommonPropertiesOne(SerializedProperty referencesFrom, SerializedProperty cameraReferenceSelf, SerializedProperty featureNumber, GameObject go, string componentName)
{
var isPreviewScene = EditorSceneManager.IsPreviewScene(go.scene);
var canvas = go.GetComponentInParent<Canvas>(true);
if (!isPreviewScene && !canvas)
{
EditorGUI.LabelField(EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * 2), $"No parent canvas detected!\n{componentName} only works inside a UGUI UI.", ErrorStyle);
return false;
}
var usingInstanceSettings = true;
var cameraReference = cameraReferenceSelf.objectReferenceValue as Camera;
if (referencesFrom != null)
{
EditorGUILayout.PropertyField(referencesFrom, BlurReferencesFromContent);
if (referencesFrom.enumValueFlag == (int)UIBlurCommon.BlurReferencesFrom.ReferenceProvider)
{
var referenceProvider = canvas.GetComponent<BlurReferenceProvider>();
if (referenceProvider == null)
{
EditorGUI.LabelField(EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * 2), $"No {nameof(BlurReferenceProvider)} component on canvas.\n Defaulting to instance settings.", WarningStyle);
}
else
{
usingInstanceSettings = false;
cameraReference = referenceProvider.CameraReference;
}
}
}
var actualUsedCamera = cameraReference != null ? cameraReference : Camera.main; // can't use null coalescing due to Unity overloads.
var numberOfFeaturesPresent = GetNumberOfFlexibleBlurFeatures(actualUsedCamera, out var rendererData);
if (usingInstanceSettings)
{
EditorGUILayout.PropertyField(cameraReferenceSelf, CameraReferenceContent);
if (!cameraReference)
{
if (Camera.main)
EditorGUILayout.LabelField("No Camera reference supplied. Using Camera.main.", WarningStyle);
else
EditorGUILayout.LabelField("No Camera reference supplied.", ErrorStyle);
}
if (numberOfFeaturesPresent > 1 || featureNumber.intValue != 0)
{
EditorGUILayout.PropertyField(featureNumber, FeatureNumberContent);
featureNumber.intValue = Mathf.Max(featureNumber.intValue, 0);
if (featureNumber.intValue >= numberOfFeaturesPresent)
EditorGUILayout.LabelField($"Invalid feature #. {nameof(FlexibleBlurFeature)} count is {numberOfFeaturesPresent}.", WarningStyle);
}
}
if (numberOfFeaturesPresent == 0)
{
EditorGUILayout.LabelField($"{actualUsedCamera.name} is missing {nameof(FlexibleBlurFeature)}!", ErrorStyle);
if (GUILayout.Button("Open Renderer?", GUILayout.Height(28)))
{
EditorGUIUtility.PingObject(rendererData);
Selection.activeObject = rendererData;
}
EditorGUILayout.Space(24);
}
return true;
}
public static void DrawBlurCommonPropertiesTwo(SerializedObject serializedObject, SerializedProperty blurPresetProperty, SerializedProperty blurInstanceSettings, float originalLabelWidth, ref BlurPresetEditor presetEditor, ref BlurPreset previousBlurPreset, ref ReorderableList downscaleSections, ref ReorderableList blurSections)
{
var blurPreset = blurPresetProperty.objectReferenceValue as BlurPreset;
if (blurPreset == null)
{
var propertyRect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth - 35, EditorGUIUtility.singleLineHeight);
var buttonRect = propertyRect;
buttonRect.width = 50;
buttonRect.x = originalLabelWidth + 20;
EditorGUIUtility.labelWidth += 50;
EditorGUI.PropertyField(propertyRect, blurPresetProperty);
EditorGUIUtility.labelWidth = originalLabelWidth;
if (GUI.Button(buttonRect, "New"))
{
presetEditor = null;
blurPreset = CreateInstance<BlurPreset>();
var path = PresetSavePath.GetPresetSavePath("New Blur Preset.asset");
AssetDatabase.CreateAsset(blurPreset, path);
AssetDatabase.SaveAssets();
blurPreset.TryFillSettings();
var instanceSettings = blurInstanceSettings.boxedValue as BlurSettings;
foreach (var qualityLevelSettings in blurPreset.Settings)
qualityLevelSettings.CopySettings(instanceSettings);
blurPresetProperty.objectReferenceValue = blurPreset;
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space(2);
EditorGUILayout.LabelField("No preset selected—using instance settings.", WarningStyle);
BlurPresetEditor.DrawBlurProperties(blurInstanceSettings.Copy(), ref downscaleSections, ref blurSections);
}
else
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(blurPresetProperty);
if (EditorGUI.EndChangeCheck())
blurPreset.TryFillSettings();
EditorGUILayout.EndVertical();
if (blurPreset == previousBlurPreset)
presetEditor.DrawGUI();
else
presetEditor = null;
}
previousBlurPreset = blurPreset;
}
public static int GetNumberOfFlexibleBlurFeatures(Camera camera, out ScriptableRendererData rendererData)
{
rendererData = null;
if (camera == null)
return -1;
var data = camera.GetUniversalAdditionalCameraData();
var rendererIdxField = typeof(UniversalAdditionalCameraData).GetField("m_RendererIndex", BindingFlags.NonPublic | BindingFlags.Instance);
var rendererIdxFieldObj = rendererIdxField?.GetValue(data);
if (rendererIdxFieldObj is not int rendererIdx)
return -1;
var currentPipelineAsset = QualitySettings.renderPipeline as UniversalRenderPipelineAsset;
if (currentPipelineAsset == null)
currentPipelineAsset = GraphicsSettings.defaultRenderPipeline as UniversalRenderPipelineAsset;
if (currentPipelineAsset == null)
return -1;
// -1 signifies the default renderer
if (rendererIdx == -1)
{
var defaultRendererIdxField = typeof(UniversalRenderPipelineAsset).GetField("m_DefaultRendererIndex", BindingFlags.NonPublic | BindingFlags.Instance);
var defaultRendererIdxFieldObj = defaultRendererIdxField?.GetValue(currentPipelineAsset);
if (defaultRendererIdxFieldObj is not int actualRendererIdx)
return -1;
rendererIdx = actualRendererIdx;
}
#if UNITY_2023_2_OR_NEWER
rendererData = currentPipelineAsset.rendererDataList[rendererIdx];
#else
var dataListField = typeof(UniversalRenderPipelineAsset).GetField("m_RendererDataList", BindingFlags.NonPublic | BindingFlags.Instance);
var dataListObj = dataListField?.GetValue(currentPipelineAsset);
if (dataListObj is not ScriptableRendererData[] dataList)
return -1;
rendererData = dataList[rendererIdx];
#endif
int featureCount = 0;
foreach (var feature in rendererData.rendererFeatures)
{
if (feature is FlexibleBlurFeature)
featureCount++;
}
return featureCount;
}
}
}