using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using StringBuilder = System.Text.StringBuilder;
namespace UnityEditor.Rendering.Universal
{
///
/// The default implementation for the Universal Render Pipeline (URP).
/// This editor manages custom UI for volume components in the URP context. It handles rendering feature checks
/// and UI warnings for missing features needed by the volume component.
///
///
/// This editor class is designed to work with volume components in Unity's URP. It extends the
/// to customize the inspector UI for volume components and add checks for required renderer features.
///
/// When using this editor, ensure that the relevant renderer features for the volume are enabled in the active URP
/// renderer asset. If any required features are missing, a warning will be displayed with an option to open the
/// relevant renderer settings.
///
///
///
///
///
[SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))]
[CustomEditor(typeof(VolumeComponent), true)]
public class UniversalRenderPipelineVolumeComponentEditor : VolumeComponentEditor
{
private VolumeRequiresRendererFeatures m_FeatureAttribute;
///
/// Initializes the editor. It caches the attribute from the target component.
///
///
/// The method caches the renderer features attribute for the volume component. This ensures
/// that UI elements relying on these features are updated efficiently. This method is called when the editor is first enabled.
///
///
/// The method is automatically called when the editor is initialized, making it suitable
/// for setting up references and caching.
///
public override void OnEnable()
{
base.OnEnable();
// Caching the attribute as UI code can be called multiple times in the same editor frame
if (m_FeatureAttribute == null)
m_FeatureAttribute = target.GetType().GetCustomAttribute();
}
///
/// Retrieves the names of the missing renderer features as a formatted string.
///
/// A set of objects representing the missing renderer features.
/// A formatted string containing the names of the missing feature types.
///
/// This helper method generates a space-separated string of the feature types that need to be added to the active
/// URP renderer asset for the volume component to work correctly. The names of the missing feature types are
/// appended to the string for display in the warning message.
///
private string GetFeatureTypeNames(in HashSet types)
{
var typeNameString = new StringBuilder();
foreach (var type in types)
typeNameString.AppendFormat("\"{0}\" ", type.Name);
return typeNameString.ToString();
}
///
/// Displays the UI for the volume component and checks for missing renderer features required by the volume.
///
///
/// This method draws the inspector UI for the volume component and checks whether the necessary renderer features
/// are enabled in the active URP asset. If any required features are missing, a warning box will be displayed.
/// The warning includes a button that opens the active renderer asset for quick modification.
///
///
/// The method is called before rendering the inspector GUI for the volume component,
/// ensuring that feature checks are performed and UI warnings are shown before displaying the inspector.
///
protected override void OnBeforeInspectorGUI()
{
if (m_FeatureAttribute == null)
return;
var rendererFeatures = (GraphicsSettings.currentRenderPipeline is UniversalRenderPipelineAsset urpAsset && urpAsset.scriptableRendererData != null)
? urpAsset.scriptableRendererData.rendererFeatures
: null;
using (HashSetPool.Get(out var missingFeatureTypes))
{
foreach (var elem in m_FeatureAttribute.TargetFeatureTypes)
missingFeatureTypes.Add(elem);
if (rendererFeatures != null)
{
foreach (var feature in rendererFeatures)
{
var featureType = feature.GetType();
if (missingFeatureTypes.Contains(featureType))
{
missingFeatureTypes.Remove(featureType);
if (missingFeatureTypes.Count == 0)
break;
}
}
}
if (missingFeatureTypes.Count > 0)
{
CoreEditorUtils.DrawFixMeBox(
$"For this effect to work, the following renderer feature(s) need to be added and enabled on the active renderer asset: {GetFeatureTypeNames(in missingFeatureTypes)}",
MessageType.Warning,
"Open",
() =>
{
Selection.activeObject = UniversalRenderPipeline.asset.scriptableRendererData;
GUIUtility.ExitGUI();
});
}
}
}
}
}