using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering.HighDefinition; using UnityEngine.Rendering; using UnityEngine.UIElements; using UnityEditorInternal; using System.Linq; namespace UnityEditor.Rendering.HighDefinition { class DefaultSettingsPanelProvider { static DefaultSettingsPanelIMGUI s_IMGUIImpl = new DefaultSettingsPanelIMGUI(); [SettingsProvider] public static SettingsProvider CreateSettingsProvider() { return new SettingsProvider("Project/HDRP Default Settings", SettingsScope.Project) { activateHandler = s_IMGUIImpl.OnActivate, keywords = SettingsProvider.GetSearchKeywordsFromGUIContentProperties() .Concat(SettingsProvider.GetSearchKeywordsFromGUIContentProperties()) .Concat(OverridableFrameSettingsArea.frameSettingsKeywords).ToArray(), guiHandler = s_IMGUIImpl.DoGUI, }; } class DefaultSettingsPanelIMGUI { // A wrapper for CoreEditorDrawers class CoreEditorDrawerEditorWrapper : Editor, IDefaultFrameSettingsType { public FrameSettingsRenderType GetFrameSettingsType() { switch (HDRenderPipelineUI.selectedFrameSettings) { case HDRenderPipelineUI.SelectedFrameSettings.Camera: return FrameSettingsRenderType.Camera; case HDRenderPipelineUI.SelectedFrameSettings.RealtimeReflection: return FrameSettingsRenderType.RealtimeReflection; case HDRenderPipelineUI.SelectedFrameSettings.BakedOrCustomReflection: return FrameSettingsRenderType.CustomOrBakedReflection; } throw new Exception("unreachable"); } } public class Styles { public const int labelWidth = 220; public static GUIContent defaultHDRPAsset = new GUIContent("Asset with the default settings"); public static GUIContent defaultVolumeProfileLabel = new GUIContent("Default Volume Profile Asset"); public static GUIContent lookDevVolumeProfileLabel = new GUIContent("LookDev Volume Profile Asset"); public static GUIContent frameSettingsLabel = new GUIContent("Frame Settings"); public static GUIContent volumeComponentsLabel = new GUIContent("Volume Components"); public static GUIContent customPostProcessOrderLabel = new GUIContent("Custom Post Process Orders"); public static GUIContent diffusionProfileSettingsLabel = new GUIContent("Default Diffusion Profile Assets"); } Vector2 m_ScrollViewPosition = Vector2.zero; Editor m_CachedDefaultVolumeProfileEditor; Editor m_CachedLookDevVolumeProfileEditor; ReorderableList m_BeforeTransparentCustomPostProcesses; ReorderableList m_BeforeTAACustomPostProcesses; ReorderableList m_BeforePostProcessCustomPostProcesses; ReorderableList m_AfterPostProcessCustomPostProcesses; int m_CurrentVolumeProfileInstanceID; private Editor m_Cache; DiffusionProfileSettingsListUI m_DiffusionProfileUI; SerializedHDRenderPipelineAsset m_SerializeHDRPAsset; public void DoGUI(string searchContext) { if (HDRenderPipeline.defaultAsset == null) { EditorGUILayout.HelpBox("Base SRP Asset is not a HDRenderPipelineAsset.", MessageType.Warning); return; } m_SerializeHDRPAsset.Update(); m_ScrollViewPosition = GUILayout.BeginScrollView(m_ScrollViewPosition, EditorStyles.largeLabel); Draw_GeneralSettings(); EditorGUILayout.Space(); EditorGUILayout.LabelField(Styles.frameSettingsLabel, EditorStyles.largeLabel); Draw_DefaultFrameSettings(); EditorGUILayout.Space(); EditorGUILayout.LabelField(Styles.volumeComponentsLabel, EditorStyles.largeLabel); Draw_VolumeInspector(); EditorGUILayout.Space(); EditorGUILayout.LabelField(Styles.customPostProcessOrderLabel, EditorStyles.largeLabel); Draw_CustomPostProcess(); EditorGUILayout.LabelField(Styles.diffusionProfileSettingsLabel, EditorStyles.largeLabel); Draw_DiffusionProfileSettings(); GUILayout.EndScrollView(); } /// /// Executed when activate is called from the settings provider. /// /// /// public void OnActivate(string searchContext, VisualElement rootElement) { if (HDRenderPipeline.defaultAsset == null) return; m_ScrollViewPosition = Vector2.zero; InitializeCustomPostProcessesLists(); m_DiffusionProfileUI = new DiffusionProfileSettingsListUI() { drawElement = DrawDiffusionProfileElement }; var serializedObject = new SerializedObject(HDRenderPipeline.defaultAsset); m_SerializeHDRPAsset = new SerializedHDRenderPipelineAsset(serializedObject); var editorResources = HDRenderPipeline.defaultAsset.renderPipelineEditorResources; if (!EditorUtility.IsPersistent(editorResources)) { var editorResourcesPath = HDUtils.GetHDRenderPipelinePath() + "Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset"; HDRenderPipeline.defaultAsset.renderPipelineEditorResources = AssetDatabase.LoadAssetAtPath(editorResourcesPath); } } void InitializeCustomPostProcessesLists() { var hdrpAsset = HDRenderPipeline.defaultAsset; if (hdrpAsset == null) return; var ppVolumeTypes = TypeCache.GetTypesDerivedFrom(); var ppVolumeTypeInjectionPoints = new Dictionary(); foreach (var ppVolumeType in ppVolumeTypes) { if (ppVolumeType.IsAbstract) continue; var comp = ScriptableObject.CreateInstance(ppVolumeType) as CustomPostProcessVolumeComponent; ppVolumeTypeInjectionPoints[ppVolumeType] = comp.injectionPoint; CoreUtils.Destroy(comp); } InitList(ref m_BeforeTransparentCustomPostProcesses, hdrpAsset.beforeTransparentCustomPostProcesses, "After Opaque And Sky", CustomPostProcessInjectionPoint.AfterOpaqueAndSky); InitList(ref m_BeforeTAACustomPostProcesses, hdrpAsset.beforeTAACustomPostProcesses, "Before TAA", CustomPostProcessInjectionPoint.BeforeTAA); InitList(ref m_BeforePostProcessCustomPostProcesses, hdrpAsset.beforePostProcessCustomPostProcesses, "Before Post Process", CustomPostProcessInjectionPoint.BeforePostProcess); InitList(ref m_AfterPostProcessCustomPostProcesses, hdrpAsset.afterPostProcessCustomPostProcesses, "After Post Process", CustomPostProcessInjectionPoint.AfterPostProcess); void InitList(ref ReorderableList reorderableList, List customPostProcessTypes, string headerName, CustomPostProcessInjectionPoint injectionPoint) { // Sanitize the list: customPostProcessTypes.RemoveAll(s => Type.GetType(s) == null); reorderableList = new ReorderableList(customPostProcessTypes, typeof(string)); reorderableList.drawHeaderCallback = (rect) => EditorGUI.LabelField(rect, headerName, EditorStyles.boldLabel); reorderableList.drawElementCallback = (rect, index, isActive, isFocused) => { rect.height = EditorGUIUtility.singleLineHeight; var elemType = Type.GetType(customPostProcessTypes[index]); EditorGUI.LabelField(rect, elemType.ToString(), EditorStyles.boldLabel); }; reorderableList.onAddCallback = (list) => { var menu = new GenericMenu(); foreach (var kp in ppVolumeTypeInjectionPoints) { if (kp.Value == injectionPoint && !customPostProcessTypes.Contains(kp.Key.AssemblyQualifiedName)) menu.AddItem(new GUIContent(kp.Key.ToString()), false, () => { Undo.RegisterCompleteObjectUndo(hdrpAsset, $"Added {kp.Key.ToString()} Custom Post Process"); customPostProcessTypes.Add(kp.Key.AssemblyQualifiedName); }); } if (menu.GetItemCount() == 0) menu.AddDisabledItem(new GUIContent("No Custom Post Process Availble")); menu.ShowAsContext(); EditorUtility.SetDirty(hdrpAsset); }; reorderableList.onRemoveCallback = (list) => { Undo.RegisterCompleteObjectUndo(hdrpAsset, $"Removed {list.list[list.index].ToString()} Custom Post Process"); customPostProcessTypes.RemoveAt(list.index); EditorUtility.SetDirty(hdrpAsset); }; reorderableList.elementHeightCallback = _ => EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; reorderableList.onReorderCallback = (list) => EditorUtility.SetDirty(hdrpAsset); } } void Draw_CustomPostProcess() { var hdrpAsset = HDRenderPipeline.defaultAsset; if (hdrpAsset == null) return; m_BeforeTransparentCustomPostProcesses.DoLayoutList(); m_BeforeTAACustomPostProcesses.DoLayoutList(); m_BeforePostProcessCustomPostProcesses.DoLayoutList(); m_AfterPostProcessCustomPostProcesses.DoLayoutList(); } void Draw_GeneralSettings() { var hdrpAsset = HDRenderPipeline.defaultAsset; if (hdrpAsset == null) { EditorGUILayout.HelpBox("Base SRP Asset is not a HDRenderPipelineAsset.", MessageType.Warning); return; } var oldWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = Styles.labelWidth; GUI.enabled = false; EditorGUILayout.ObjectField(Styles.defaultHDRPAsset, hdrpAsset, typeof(HDRenderPipelineAsset), false); GUI.enabled = true; HDRenderPipelineUI.GeneralSection.Draw(m_SerializeHDRPAsset, null); m_SerializeHDRPAsset.serializedObject.ApplyModifiedProperties(); EditorGUIUtility.labelWidth = oldWidth; } void Draw_VolumeInspector() { var hdrpAsset = HDRenderPipeline.defaultAsset; if (hdrpAsset == null) return; var oldWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = Styles.labelWidth; EditorGUILayout.BeginHorizontal(); var asset = EditorDefaultSettings.GetOrAssignDefaultVolumeProfile(); var newAsset = (VolumeProfile)EditorGUILayout.ObjectField(Styles.defaultVolumeProfileLabel, asset, typeof(VolumeProfile), false); if (newAsset == null) { Debug.Log("Default Volume Profile Asset cannot be null. Rolling back to previous value."); } else if (newAsset != asset) { Undo.RegisterCompleteObjectUndo(hdrpAsset, "Default Volume Profile Asset Change."); asset = newAsset; hdrpAsset.defaultVolumeProfile = asset; EditorUtility.SetDirty(hdrpAsset); } if (GUILayout.Button(EditorGUIUtility.TrTextContent("New", "Create a new Volume Profile for default in your default resource folder (defined in Wizard)"), GUILayout.Width(38), GUILayout.Height(18))) { DefaultVolumeProfileCreator.CreateAndAssign(DefaultVolumeProfileCreator.Kind.Default); } EditorGUILayout.EndHorizontal(); // The state of the profile can change without the asset reference changing so in this case we need to reset the editor. if (m_CurrentVolumeProfileInstanceID != asset.GetInstanceID() && m_CachedDefaultVolumeProfileEditor != null) { m_CurrentVolumeProfileInstanceID = asset.GetInstanceID(); m_CachedDefaultVolumeProfileEditor = null; } Editor.CreateCachedEditor(asset, Type.GetType("UnityEditor.Rendering.VolumeProfileEditor"), ref m_CachedDefaultVolumeProfileEditor); EditorGUIUtility.labelWidth -= 18; bool oldEnabled = GUI.enabled; GUI.enabled = AssetDatabase.IsOpenForEdit(asset); m_CachedDefaultVolumeProfileEditor.OnInspectorGUI(); GUI.enabled = oldEnabled; EditorGUIUtility.labelWidth = oldWidth; EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); var lookDevAsset = EditorDefaultSettings.GetOrAssignLookDevVolumeProfile(); EditorGUIUtility.labelWidth = 221; var newLookDevAsset = (VolumeProfile)EditorGUILayout.ObjectField(Styles.lookDevVolumeProfileLabel, lookDevAsset, typeof(VolumeProfile), false); if (lookDevAsset == null) { Debug.Log("LookDev Volume Profile Asset cannot be null. Rolling back to previous value."); } else if (newLookDevAsset != lookDevAsset) { hdrpAsset.defaultLookDevProfile = newLookDevAsset; EditorUtility.SetDirty(hdrpAsset); } if (GUILayout.Button(EditorGUIUtility.TrTextContent("New", "Create a new Volume Profile for default in your default resource folder (defined in Wizard)"), GUILayout.Width(38), GUILayout.Height(18))) { DefaultVolumeProfileCreator.CreateAndAssign(DefaultVolumeProfileCreator.Kind.LookDev); } EditorGUILayout.EndHorizontal(); Editor.CreateCachedEditor(lookDevAsset, Type.GetType("UnityEditor.Rendering.VolumeProfileEditor"), ref m_CachedLookDevVolumeProfileEditor); EditorGUIUtility.labelWidth -= 18; oldEnabled = GUI.enabled; GUI.enabled = AssetDatabase.IsOpenForEdit(asset); m_CachedLookDevVolumeProfileEditor.OnInspectorGUI(); GUI.enabled = oldEnabled; EditorGUIUtility.labelWidth = oldWidth; if (lookDevAsset.Has()) EditorGUILayout.HelpBox("VisualEnvironment is not modifiable and will be overridden by the LookDev", MessageType.Warning); if (lookDevAsset.Has()) EditorGUILayout.HelpBox("HDRISky is not modifiable and will be overridden by the LookDev", MessageType.Warning); } void Draw_DefaultFrameSettings() { var hdrpAsset = HDRenderPipeline.defaultAsset; if (hdrpAsset == null) return; Editor.CreateCachedEditor(hdrpAsset, typeof(CoreEditorDrawerEditorWrapper), ref m_Cache); HDRenderPipelineUI.FrameSettingsSection.Draw(m_SerializeHDRPAsset, m_Cache); m_SerializeHDRPAsset.serializedObject.ApplyModifiedProperties(); } void DrawDiffusionProfileElement(SerializedProperty element, Rect rect, int index) { EditorGUI.BeginChangeCheck(); EditorGUI.ObjectField(rect, element, EditorGUIUtility.TrTextContent("Profile " + index)); if (EditorGUI.EndChangeCheck()) m_SerializeHDRPAsset.serializedObject.ApplyModifiedProperties(); } void Draw_DiffusionProfileSettings() { m_DiffusionProfileUI.OnGUI(m_SerializeHDRPAsset.diffusionProfileSettingsList); } } } class DefaultVolumeProfileCreator : ProjectWindowCallback.EndNameEditAction { public enum Kind { Default, LookDev } Kind m_Kind; void SetKind(Kind kind) => m_Kind = kind; public override void Action(int instanceId, string pathName, string resourceFile) { var profile = VolumeProfileFactory.CreateVolumeProfileAtPath(pathName); ProjectWindowUtil.ShowCreatedAsset(profile); Assign(profile); } void Assign(VolumeProfile profile) { var hdrpAsset = HDRenderPipeline.defaultAsset; switch (m_Kind) { case Kind.Default: hdrpAsset.defaultVolumeProfile = profile; break; case Kind.LookDev: hdrpAsset.defaultLookDevProfile = profile; break; } } static string GetDefaultName(Kind kind) { string defaultName; switch (kind) { case Kind.Default: defaultName = "DefaultVolumeSettingsProfile"; break; case Kind.LookDev: defaultName = "LookDevVolumeSettingsProfile"; break; default: defaultName = "N/A"; break; } return defaultName; } public static void CreateAndAssign(Kind kind) { var assetCreator = ScriptableObject.CreateInstance(); assetCreator.SetKind(kind); ProjectWindowUtil.StartNameEditingIfProjectWindowExists(assetCreator.GetInstanceID(), assetCreator, $"Assets/{HDProjectSettings.projectSettingsFolderPath}/{GetDefaultName(kind)}.asset", null, null); } } }