using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEditor.Rendering; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; namespace Beautify.Universal { #if UNITY_2022_2_OR_NEWER [CustomEditor(typeof(Beautify))] #else [VolumeComponentEditor(typeof(Beautify))] #endif public class BeautifyEditor : VolumeComponentEditor { Beautify beautify; GUIStyle sectionGroupStyle, foldoutStyle, blackBack; PropertyFetcher propertyFetcher; Texture2D headerTex; bool pixelateExpanded; // Cached BeautifySettings instances to avoid frequent FindObjectsOfType calls BeautifySettings[] cachedBeautifySettingsInstances; // settings group class SectionContents { public Dictionary> groups = new Dictionary>(); public List singleFields = new List(); } readonly Dictionary sections = new Dictionary(); readonly Dictionary> groupedFields = new Dictionary>(); readonly Dictionary unpackedFields = new Dictionary(); readonly Dictionary sectionFoldStates = new Dictionary(); const string SECTION_FOLD_PREF_PREFIX = "Beautify_SectionFold_"; #if !UNITY_2021_2_OR_NEWER public override bool hasAdvancedMode => false; #endif public override void OnEnable () { if (target == null) return; base.OnEnable(); headerTex = Resources.Load("beautifyHeader"); blackBack = new GUIStyle(); blackBack.normal.background = MakeTex(4, 4, Color.black); blackBack.alignment = TextAnchor.MiddleCenter; beautify = (Beautify)target; propertyFetcher = new PropertyFetcher(serializedObject); // Cache BeautifySettings instances on enable #if UNITY_2023_1_OR_NEWER cachedBeautifySettingsInstances = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); #else cachedBeautifySettingsInstances = UnityEngine.Object.FindObjectsOfType(true); #endif // get volume fx settings var settings = beautify.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(t => t.FieldType.IsSubclassOf(typeof(VolumeParameter))) .Where(t => (t.IsPublic && t.GetCustomAttributes(typeof(NonSerializedAttribute), false).Length == 0) || (t.GetCustomAttributes(typeof(SerializeField), false).Length > 0)) .Where(t => t.GetCustomAttributes(typeof(HideInInspector), false).Length == 0) .Where(t => t.GetCustomAttributes(typeof(Beautify.SectionGroup), false).Any()); // group by settings first unpackedFields.Clear(); sections.Clear(); groupedFields.Clear(); foreach (var setting in settings) { SectionContents sectionContents = null; foreach (var section in setting.GetCustomAttributes(typeof(Beautify.SectionGroup)) as IEnumerable) { if (!sections.TryGetValue(section, out sectionContents)) { sectionContents = sections[section] = new SectionContents(); } bool isGrouped = false; foreach (var settingGroup in setting.GetCustomAttributes(typeof(Beautify.SettingsGroup)) as IEnumerable) { if (!groupedFields.ContainsKey(settingGroup)) { sectionContents.groups[settingGroup] = groupedFields[settingGroup] = new List(); } groupedFields[settingGroup].Add(setting); isGrouped = true; unpackedFields[setting] = Unpack(propertyFetcher.Find(setting.Name)); } if (!isGrouped) { sectionContents.singleFields.Add(setting); unpackedFields[setting] = Unpack(propertyFetcher.Find(setting.Name)); } } } } public override void OnDisable() { EditorApplication.delayCall -= RepaintAllViews; cachedBeautifySettingsInstances = null; } public override void OnInspectorGUI () { serializedObject.Update(); SetStyles(); Beautify.TonemapOperator prevTonemap = beautify.tonemap.value; bool prevDirectWrite = beautify.directWrite.value; int prevBloomExclusionLayerMask = beautify.bloomExclusionLayerMask.overrideState ? (int)beautify.bloomExclusionLayerMask.value : 0; int prevAnamorphicFlaresExclusionLayerMask = beautify.anamorphicFlaresExclusionLayerMask.overrideState ? (int)beautify.anamorphicFlaresExclusionLayerMask.value : 0; EditorGUILayout.BeginVertical(); { GUILayout.BeginHorizontal(blackBack); GUILayout.Label(headerTex, blackBack, GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(new GUIContent("Clear Effects", "Clears all effect overrides"), EditorStyles.miniButton)) { if (EditorUtility.DisplayDialog("Clear Effects", "Do you want to clear all effects?", "Yes", "Cancel")) { beautify.sharpenIntensity.overrideState = false; beautify.antialiasStrength.overrideState = false; beautify.ditherIntensity.overrideState = false; beautify.tonemap.overrideState = false; beautify.saturate.Override(0); beautify.brightness.overrideState = false; beautify.contrast.overrideState = false; beautify.daltonize.overrideState = false; beautify.sepia.overrideState = false; beautify.tintColor.overrideState = false; beautify.colorTemp.overrideState = false; beautify.colorTempBlend.overrideState = false; beautify.lut.overrideState = false; beautify.bloomIntensity.overrideState = false; beautify.anamorphicFlaresIntensity.overrideState = false; beautify.sunFlaresIntensity.overrideState = false; beautify.lensDirtIntensity.overrideState = false; beautify.chromaticAberrationIntensity.overrideState = false; beautify.depthOfField.overrideState = false; beautify.eyeAdaptation.overrideState = false; beautify.purkinje.overrideState = false; beautify.vignettingOuterRing.overrideState = false; beautify.vignettingInnerRing.overrideState = false; beautify.vignettingFade.overrideState = false; beautify.vignettingBlink.overrideState = false; beautify.outline.overrideState = false; beautify.nightVision.overrideState = false; beautify.thermalVision.overrideState = false; beautify.frame.overrideState = false; beautify.blurIntensity.overrideState = false; EditorUtility.SetDirty(beautify); } } if (GUILayout.Button(new GUIContent("Quick Settings", "Applies a default set of effects including color improvement, sharpening, vignette and bloom."), EditorStyles.miniButton)) { if (EditorUtility.DisplayDialog("Quick Settings", "Do you want to apply a collection of example effect settings (including color improvements, dithering, sharpening, vignette and bloom)?\nYou can adjust them later as you wish.", "Yes", "No")) { beautify.sharpenIntensity.Override(4f); beautify.ditherIntensity.Override(0.005f); beautify.brightness.Override(1.05f); beautify.saturate.Override(1f); beautify.contrast.Override(1.02f); beautify.bloomIntensity.Override(0.25f); beautify.bloomThreshold.Override(0.75f); beautify.vignettingOuterRing.Override(0.325f); beautify.vignettingInnerRing.Override(0.925f); EditorUtility.SetDirty(beautify); } } if (GUILayout.Button("Online Resources & Support")) { ContactUsWindow.ShowScreen(); } EditorGUILayout.EndHorizontal(); // Add "Configure Build Settings" button after the first section is fully drawn string strippedKeywords = PlayerPrefs.GetString(BeautifyRendererFeature.PLAYER_PREF_KEYNAME, ""); if (string.IsNullOrEmpty(strippedKeywords)) { EditorGUILayout.HelpBox("All features are currently included in the build, which may significantly increase compilation time. Click the button below to configure and exclude unnecessary features from the build.", MessageType.Warning); } if (GUILayout.Button("Configure Build Settings >")) { SelectActiveURPRendererAsset(); } // Check for multiple BeautifySettings instances BeautifySettings[] beautifySettingsInstances = cachedBeautifySettingsInstances; if (beautifySettingsInstances != null && beautifySettingsInstances.Length > 1) { EditorGUILayout.HelpBox($"Multiple BeautifySettings instances found in the scene ({beautifySettingsInstances.Length}). It's recommended to keep only one instance.", MessageType.Warning); EditorGUILayout.LabelField("Found instances:", EditorStyles.boldLabel); foreach (BeautifySettings settingsInstance in beautifySettingsInstances) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(settingsInstance.gameObject.name, GUILayout.ExpandWidth(true)); if (GUILayout.Button("Select", GUILayout.Width(60))) { Selection.activeObject = settingsInstance.gameObject; } EditorGUILayout.EndHorizontal(); } EditorGUILayout.Separator(); } UniversalRenderPipelineAsset pipe = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset; Camera cam = Camera.main; if (cam != null) { UniversalAdditionalCameraData data = cam.GetComponent(); if (data != null && !data.renderPostProcessing && !BeautifyRendererFeature.ignoringPostProcessingOption) { EditorGUILayout.HelpBox("Post Processing option is disabled in the camera. Either enable it or enable the option 'Ignore Post Processing Option' in the Beautify Render Feature.", MessageType.Warning); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Go to Camera")) { Selection.activeObject = cam; } if (GUILayout.Button("Go to Universal Rendering Pipeline Asset")) { Selection.activeObject = pipe; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); } } if (pipe == null) { EditorGUILayout.HelpBox("Universal Rendering Pipeline asset is not set in 'Project Settings / Graphics' !", MessageType.Error); EditorGUILayout.Separator(); GUI.enabled = false; } else if (!BeautifyRendererFeature.installed) { EditorGUILayout.HelpBox("Beautify Render Feature must be added to the rendering pipeline renderer.", MessageType.Error); if (GUILayout.Button("Go to Universal Rendering Pipeline Asset")) { Selection.activeObject = pipe; } EditorGUILayout.Separator(); GUI.enabled = false; } else if (beautify.RequiresDepthTexture()) { #if !UNITY_2021_3_OR_NEWER if (!pipe.supportsCameraDepthTexture) { EditorGUILayout.HelpBox("Depth Texture option may be required for certain effects. Check Universal Rendering Pipeline asset!", MessageType.Warning); if (GUILayout.Button("Go to Universal Rendering Pipeline Asset")) { Selection.activeObject = pipe; } EditorGUILayout.Separator(); } #endif } bool usesHDREffect = beautify.tonemap.value != Beautify.TonemapOperator.Linear; if (usesHDREffect && (QualitySettings.activeColorSpace != ColorSpace.Linear || (Camera.main != null && !Camera.main.allowHDR))) { EditorGUILayout.HelpBox("Some effects, like bloom or tonemapping, works better with Linear Color Space and HDR enabled. Enable Linear color space in Player Settings and check your camera and pipeline HDR setting.", MessageType.Warning); } if ((bool)beautify.directWrite) { #if !UNITY_2022_3_OR_NEWER if (UnityEngine.XR.XRSettings.enabled) { EditorGUILayout.HelpBox("Direct Write To Camera option is not compatible with VR.", MessageType.Warning); } #endif } // sections foreach (var section in sections) { string sectionName = ObjectNames.NicifyVariableName(section.Key.GetType().Name); bool sectionExpanded = GetSectionFoldState(sectionName); GUILayout.Space(6.0f); Rect rect = GUILayoutUtility.GetRect(16f, 22f, sectionGroupStyle); // Draw foldout arrow Rect foldoutRect = new Rect(rect.x + 4f, rect.y + 3f, 13f, 13f); if (Event.current.type == EventType.Repaint) { EditorStyles.foldout.Draw(foldoutRect, false, false, sectionExpanded, false); } // Draw section header with offset for arrow GUIStyle headerStyle = new GUIStyle(sectionGroupStyle); headerStyle.contentOffset = new Vector2(12f, -2f); GUI.Box(rect, sectionName, headerStyle); // Handle click on header if (Event.current.type == EventType.MouseDown && rect.Contains(Event.current.mousePosition)) { sectionExpanded = !sectionExpanded; SetSectionFoldState(sectionName, sectionExpanded); Event.current.Use(); } EditorGUIUtility.AddCursorRect(rect, MouseCursor.Link); if (!sectionExpanded) continue; // individual properties EditorGUI.indentLevel++; foreach (var field in section.Value.singleFields) { if (!unpackedFields.TryGetValue(field, out var parameter)) continue; bool indent; if (!IsVisible(parameter, field, out indent)) { if (field.GetCustomAttribute() != null) { EditorGUILayout.BeginHorizontal(); GUI.enabled = false; DrawPropertyField(parameter, field, indent); GUILayout.Label("(Not available - Check General Options)"); GUI.enabled = true; EditorGUILayout.EndHorizontal(); } continue; } var displayName = parameter.displayName; if (field.GetCustomAttribute(typeof(Beautify.DisplayName)) is Beautify.DisplayName displayNameAttrib) { displayName = displayNameAttrib.name; } DrawPropertyField(parameter, field, indent); if (beautify.disabled.value) GUI.enabled = false; } EditorGUI.indentLevel--; GUILayout.Space(6.0f); // grouped properties foreach (var group in section.Value.groups) { Beautify.SettingsGroup settingsGroup = group.Key; string groupName = ObjectNames.NicifyVariableName(settingsGroup.GetType().Name); bool printGroupFoldout = true; bool firstField = true; bool groupHasContent = false; foreach (var field in group.Value) { if (!unpackedFields.TryGetValue(field, out var parameter)) continue; bool indent; if (!IsVisible(parameter, field, out indent)) { if (firstField) { if (field.GetCustomAttribute() != null) { EditorGUILayout.BeginHorizontal(); GUI.enabled = false; EditorGUILayout.Foldout(false, groupName, true, foldoutStyle); GUILayout.FlexibleSpace(); GUILayout.Label("(Not available - Check General Options)"); GUI.enabled = true; EditorGUILayout.EndHorizontal(); GUILayout.Space(6.0f); } break; } continue; } firstField = false; if (printGroupFoldout) { printGroupFoldout = false; settingsGroup.IsExpanded = EditorGUILayout.Foldout(settingsGroup.IsExpanded, groupName, true, foldoutStyle); if (!settingsGroup.IsExpanded) break; EditorGUI.indentLevel++; } DrawPropertyField(parameter, field, indent); groupHasContent = true; if (parameter.value.propertyType == SerializedPropertyType.Boolean) { if (!parameter.value.boolValue) { var hasToggleSectionBegin = field.GetCustomAttributes(typeof(Beautify.ToggleAllFields)).Any(); if (hasToggleSectionBegin) break; } } else if (field.Name.Equals("depthOfFieldFocusMode")) { if (BeautifySettings.instance != null && BeautifySettings.instance.depthOfFieldTarget == null) { SerializedProperty prop = serializedObject.FindProperty(field.Name); if (prop != null) { var value = prop.FindPropertyRelative("m_Value"); if (value != null && value.enumValueIndex == (int)Beautify.DoFFocusMode.FollowTarget) { EditorGUILayout.HelpBox("Assign target in the Beautify Settings component.", MessageType.Info); } } } } } if (groupHasContent) { EditorGUI.indentLevel--; GUILayout.Space(6.0f); } } } } EditorGUILayout.EndVertical(); if (GetSectionFoldState("Artistic Choices")) { EditorGUILayout.BeginHorizontal(); GUILayout.Space(6.0f); pixelateExpanded = EditorGUILayout.Foldout(pixelateExpanded, "Pixelate", true, foldoutStyle); EditorGUILayout.EndHorizontal(); if (pixelateExpanded) { EditorGUILayout.HelpBox("Use the Downsampling option in General Settings to apply a pixelate effect.", MessageType.Info); } } if (serializedObject.ApplyModifiedProperties()) { if (beautify.directWrite.value != prevDirectWrite || (beautify.bloomExclusionLayerMask.overrideState ? (int)beautify.bloomExclusionLayerMask.value : 0) != prevBloomExclusionLayerMask || (beautify.anamorphicFlaresExclusionLayerMask.overrideState ? (int)beautify.anamorphicFlaresExclusionLayerMask.value : 0) != prevAnamorphicFlaresExclusionLayerMask || beautify.outline.value) { EditorApplication.delayCall += RepaintAllViews; } } if (prevTonemap != beautify.tonemap.value && beautify.tonemap.value != Beautify.TonemapOperator.Linear) { beautify.saturate.value = 0; beautify.saturate.overrideState = true; beautify.contrast.value = 1f; beautify.contrast.overrideState = true; } } static void RepaintAllViews() { UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); } bool IsVisible (SerializedDataParameter property, MemberInfo field, out bool indent) { bool visible = true; indent = false; Beautify.DisplayConditionEnum enumCondition = field.GetCustomAttribute(typeof(Beautify.DisplayConditionEnum)) as Beautify.DisplayConditionEnum; Beautify.DisplayConditionBool boolCondition = field.GetCustomAttribute(typeof(Beautify.DisplayConditionBool)) as Beautify.DisplayConditionBool; bool isEnumCondition = enumCondition != null; bool isBoolCondition = boolCondition != null; bool canIndent = isEnumCondition ^ isBoolCondition; if (isEnumCondition) { SerializedProperty condProp = propertyFetcher.Find(enumCondition.field); if (condProp != null) { var value = condProp.FindPropertyRelative("m_Value"); if (value != null) { visible = false; if (enumCondition.isEqual) { if (value.enumValueIndex == enumCondition.enumValueIndex) { indent = canIndent; return true; } } else if (value.enumValueIndex != enumCondition.enumValueIndex) { indent = canIndent; return true; } } } } /* OR */ if (isBoolCondition) { SerializedProperty condProp = propertyFetcher.Find(boolCondition.field); if (condProp != null) { var value = condProp.FindPropertyRelative("m_Value"); if (value != null) { if (value.boolValue != boolCondition.value) { return false; } indent = value.boolValue; } } /* AND */ SerializedProperty condProp2 = propertyFetcher.Find(boolCondition.field2); if (condProp2 != null) { var value2 = condProp2.FindPropertyRelative("m_Value"); if (value2 != null) { if (value2.boolValue != boolCondition.value2) { return false; } indent = indent || value2.boolValue; } } indent &= canIndent; visible = true; } return visible; } void DrawPropertyField (SerializedDataParameter property, MemberInfo field, bool indent) { if (indent) { EditorGUI.indentLevel++; } var displayName = property.displayName; if (field.GetCustomAttribute(typeof(Beautify.DisplayName)) is Beautify.DisplayName displayNameAttrib) { displayName = displayNameAttrib.name; } if (property.value.propertyType == SerializedPropertyType.Boolean) { if (field.GetCustomAttribute(typeof(Beautify.GlobalOverride)) != null) { BoolParameter pr = property.GetObjectRef(); bool prev = pr.value; using (new EditorGUILayout.HorizontalScope()) { float w = 17f; if (EditorGUI.indentLevel > 0) w += 8f; var overrideRect = GUILayoutUtility.GetRect(w, 20f, GUILayout.ExpandWidth(false)); overrideRect.yMin += 4f; if (EditorGUI.indentLevel > 0) { overrideRect.xMin += 12f; } bool value = GUI.Toggle(overrideRect, prev, GUIContent.none); string tooltip = null; if (field.GetCustomAttribute(typeof(TooltipAttribute)) is TooltipAttribute tooltipAttribute) { tooltip = tooltipAttribute.tooltip; } using (new EditorGUI.DisabledScope(!prev)) { EditorGUILayout.LabelField(new GUIContent(displayName, tooltip)); } if (value != prev) { pr.value = value; SerializedProperty prop = serializedObject.FindProperty(field.Name); if (prop != null) { var boolProp = prop.FindPropertyRelative("m_Value"); if (boolProp != null) { boolProp.boolValue = value; } if (value) { var overrideProp = prop.FindPropertyRelative("m_OverrideState"); if (overrideProp != null) { overrideProp.boolValue = true; } } } } } } else { PropertyField(property, new GUIContent(displayName)); } } else { PropertyField(property, new GUIContent(displayName)); } if (indent) { EditorGUI.indentLevel--; } // Add warning messages for stripped features if (field.GetCustomAttribute() != null) { string strippedKeywords = PlayerPrefs.GetString(BeautifyRendererFeature.PLAYER_PREF_KEYNAME, ""); bool isEnabled = false; bool isOverridden = property.overrideState.boolValue; if (isOverridden) { if (property.value.propertyType == SerializedPropertyType.Boolean) { isEnabled = property.value.boolValue; } else if (property.value.propertyType == SerializedPropertyType.Float) { isEnabled = property.value.floatValue > 0; } else if (property.value.propertyType == SerializedPropertyType.Enum) { isEnabled = property.value.enumValueIndex > 0; } else if (property.value.propertyType == SerializedPropertyType.LayerMask) { isEnabled = property.value.intValue != 0; } else if (property.value.propertyType == SerializedPropertyType.ObjectReference) { isEnabled = property.value.objectReferenceValue != null; } } if (isEnabled) { string warningMessage = null; string fieldName = field.Name; // Check each stripped feature against the keywords in PlayerPrefs if ((fieldName == "sharpenIntensity" && strippedKeywords.Contains(ShaderParams.SKW_SHARPEN)) || (fieldName == "sharpenExclusionLayerMask" && strippedKeywords.Contains(ShaderParams.SKW_SHARPEN_EXCLUSION_MASK)) || (fieldName == "ditherIntensity" && strippedKeywords.Contains(ShaderParams.SKW_DITHER)) || (fieldName == "tonemap" && ((property.value.enumValueIndex == (int)Beautify.TonemapOperator.ACES && strippedKeywords.Contains(ShaderParams.SKW_TONEMAP_ACES)) || (property.value.enumValueIndex == (int)Beautify.TonemapOperator.ACESFitted && strippedKeywords.Contains(ShaderParams.SKW_TONEMAP_ACES_FITTED)) || (property.value.enumValueIndex == (int)Beautify.TonemapOperator.AGX && strippedKeywords.Contains(ShaderParams.SKW_TONEMAP_AGX)))) || (fieldName == "lut" && strippedKeywords.Contains(ShaderParams.SKW_LUT3D) && strippedKeywords.Contains(ShaderParams.SKW_LUT)) || ((fieldName == "bloomIntensity" || fieldName == "anamorphicFlaresIntensity" || fieldName == "sunFlaresIntensity") && strippedKeywords.Contains(ShaderParams.SKW_BLOOM)) || (fieldName == "outline" && strippedKeywords.Contains(ShaderParams.SKW_OUTLINE)) || (fieldName == "nightVision" && strippedKeywords.Contains(ShaderParams.SKW_NIGHT_VISION)) || (fieldName == "thermalVision" && strippedKeywords.Contains(ShaderParams.SKW_THERMAL_VISION)) || (fieldName == "chromaticAberrationIntensity" && strippedKeywords.Contains(ShaderParams.SKW_CHROMATIC_ABERRATION)) || (fieldName == "depthOfField" && strippedKeywords.Contains(ShaderParams.SKW_DEPTH_OF_FIELD)) || (fieldName == "depthOfFieldTransparentSupport" && strippedKeywords.Contains(ShaderParams.SKW_DEPTH_OF_FIELD_TRANSPARENT)) || (fieldName == "depthOfFieldAlphaTestSupport" && strippedKeywords.Contains(ShaderParams.SKW_DEPTH_OF_FIELD_TRANSPARENT)) || (fieldName == "eyeAdaptation" && strippedKeywords.Contains(ShaderParams.SKW_EYE_ADAPTATION)) || (fieldName == "purkinje" && strippedKeywords.Contains(ShaderParams.SKW_PURKINJE)) || (fieldName == "vignettingOuterRing" && strippedKeywords.Contains(ShaderParams.SKW_VIGNETTING)) || (fieldName == "vignettingMask" && strippedKeywords.Contains(ShaderParams.SKW_VIGNETTING_MASK)) || (fieldName == "filmGrainIntensity" && strippedKeywords.Contains(ShaderParams.SKW_FILM_GRAIN)) || (fieldName == "filmGrainEnabled" && strippedKeywords.Contains(ShaderParams.SKW_FILM_GRAIN)) || (fieldName == "frame" && strippedKeywords.Contains(ShaderParams.SKW_FRAME)) || (fieldName == "lensDirtIntensity" && strippedKeywords.Contains(ShaderParams.SKW_DIRT)) || (fieldName == "antialiasStrength" && strippedKeywords.Contains(ShaderParams.SKW_EDGE_ANTIALIASING)) || ((fieldName == "sepia" || fieldName == "daltonize" || fieldName == "colorTemp") && strippedKeywords.Contains(ShaderParams.SKW_COLOR_TWEAKS))) { warningMessage = "This feature is stripped in the build."; } if (warningMessage != null) { var linkContent = new GUIContent("(click to configure)"); var linkSize = EditorStyles.linkLabel.CalcSize(linkContent); var height = EditorGUIUtility.singleLineHeight + 8; var warningRect = EditorGUILayout.GetControlRect(false, height); warningRect.xMin += 8; warningRect.xMax -= 8; EditorGUI.HelpBox(warningRect, "", MessageType.Warning); var textRect = warningRect; textRect.xMin += 24f; textRect.xMax -= linkSize.x + 8; EditorGUI.LabelField(textRect, warningMessage); var linkRect = warningRect; linkRect.xMin = textRect.xMax; linkRect.y = textRect.y + 3; if (GUI.Button(linkRect, linkContent, EditorStyles.linkLabel)) { SelectActiveURPRendererAsset(); } } } } } void SetStyles () { // section header style Color titleColor = EditorGUIUtility.isProSkin ? new Color(0.52f, 0.66f, 0.9f) : new Color(0.12f, 0.16f, 0.4f); GUIStyle skurikenModuleTitleStyle = "ShurikenModuleTitle"; sectionGroupStyle = new GUIStyle(skurikenModuleTitleStyle); sectionGroupStyle.contentOffset = new Vector2(5f, -2f); sectionGroupStyle.normal.textColor = titleColor; sectionGroupStyle.fixedHeight = 22; sectionGroupStyle.fontStyle = FontStyle.Bold; // foldout style foldoutStyle = new GUIStyle(EditorStyles.foldout); foldoutStyle.margin = new RectOffset(0, 0, 0, 0); } bool GetSectionFoldState(string sectionName) { if (!sectionFoldStates.TryGetValue(sectionName, out bool state)) { state = EditorPrefs.GetBool(SECTION_FOLD_PREF_PREFIX + sectionName, true); sectionFoldStates[sectionName] = state; } return state; } void SetSectionFoldState(string sectionName, bool expanded) { sectionFoldStates[sectionName] = expanded; EditorPrefs.SetBool(SECTION_FOLD_PREF_PREFIX + sectionName, expanded); } [VolumeParameterDrawer(typeof(Beautify.MinMaxFloatParameter))] public class MinMaxFloatParameterDrawer : VolumeParameterDrawer { public override bool OnGUI (SerializedDataParameter parameter, GUIContent title) { if (parameter.value.propertyType == SerializedPropertyType.Vector2) { var o = parameter.GetObjectRef(); var range = o.value; float x = range.x; float y = range.y; EditorGUI.BeginChangeCheck(); EditorGUILayout.MinMaxSlider(title, ref x, ref y, o.min, o.max); x = EditorGUILayout.FloatField(x, GUILayout.Width(40)); y = EditorGUILayout.FloatField(y, GUILayout.Width(40)); if (EditorGUI.EndChangeCheck()) { range.x = x; range.y = y; o.SetValue(new Beautify.MinMaxFloatParameter(range, o.min, o.max)); } return true; } else { EditorGUILayout.PropertyField(parameter.value); return false; } } } Texture2D MakeTex (int width, int height, Color col) { Color[] pix = new Color[width * height]; for (int i = 0; i < pix.Length; i++) pix[i] = col; TextureFormat tf = SystemInfo.SupportsTextureFormat(TextureFormat.RGBAFloat) ? TextureFormat.RGBAFloat : TextureFormat.RGBA32; Texture2D result = new Texture2D(width, height, tf, false); result.hideFlags = HideFlags.DontSave; result.SetPixels(pix); result.Apply(); return result; } void SelectActiveURPRendererAsset () { var urpAsset = UniversalRenderPipeline.asset; if (urpAsset != null && urpAsset.scriptableRenderer is UniversalRenderer urpRenderer) { var rendererDataField = typeof(UniversalRenderPipelineAsset).GetField("m_RendererDataList", BindingFlags.NonPublic | BindingFlags.Instance); var rendererDataList = rendererDataField?.GetValue(urpAsset) as ScriptableRendererData[]; if (rendererDataList?.Length > 0) { Selection.activeObject = rendererDataList[0]; } } } } }