using System; using UnityEngine.Experimental.Rendering; namespace UnityEngine.Rendering.Universal.PostProcessing { /// /// Custom Post Processing injection points. /// Since this is a flag, you can write a renderer that can be injected at multiple locations. /// [Flags] public enum InjectionPoint { /// After Opaque and Sky. AfterOpaqueAndSky = 1, /// Before Post Processing. BeforePostProcess = 2, /// After Post Processing. AfterPostProcess = 4, } /// /// The Base Class for all the custom post process renderers /// public abstract class CompoundRenderer : IDisposable { private bool _initialized = false; protected GraphicsFormat _defaultHDRFormat; protected bool _useRGBM; /// /// True if you want your custom post process to be visible in the scene view. False otherwise. /// public virtual bool visibleInSceneView => true; /// /// Specifies the input needed by this custom post process. Default is Color only. /// public virtual ScriptableRenderPassInput input => ScriptableRenderPassInput.Color; /// /// Whether the function initialize has already been called /// public bool Initialized => _initialized; /// /// An intialize function for internal use only /// internal void InitializeInternal() { Initialize(); _initialized = true; } /// /// Initialize function, called once before the effect is first rendered. /// If the effect is never rendered, then this function will never be called. /// public virtual void Initialize() { // Texture format pre-lookup if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, FormatUsage.Linear | FormatUsage.Render)) { _defaultHDRFormat = GraphicsFormat.B10G11R11_UFloatPack32; _useRGBM = false; } else { _defaultHDRFormat = QualitySettings.activeColorSpace == ColorSpace.Linear ? GraphicsFormat.R8G8B8A8_SRGB : GraphicsFormat.R8G8B8A8_UNorm; _useRGBM = true; } } /// /// Setup function, called every frame once for each camera before render is called. /// /// Current Rendering Data /// The injection point from which the renderer is being called /// /// True if render should be called for this camera. False Otherwise. /// public virtual bool Setup(in RenderingData renderingData, InjectionPoint injectionPoint) { return true; } /// /// Called every frame for each camera when the post process needs to be rendered. /// /// Command Buffer used to issue your commands /// Source Render Target, it contains the camera color buffer in it's current state /// Destination Render Target /// Current Rendering Data /// The injection point from which the renderer is being called public abstract void Render(CommandBuffer cmd, RTHandle source, RTHandle destination, ref RenderingData renderingData, InjectionPoint injectionPoint); /// /// Dispose function, called when the renderer is disposed. /// /// If true, dispose of managed objects public virtual void Dispose(bool disposing) { } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Create a descriptor for intermediate render targets based on the rendering data. /// Mainly used to create intermediate render targets. /// /// a descriptor similar to the camera target but with no depth buffer or multisampling public static RenderTextureDescriptor GetTempRTDescriptor(in RenderingData renderingData) { RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor; descriptor.depthBufferBits = 0; descriptor.msaaSamples = 1; return descriptor; } public static RenderTextureDescriptor GetTempRTDescriptor(in RenderingData renderingData, int width, int height, GraphicsFormat format) { if (width <= 0 || height <= 0) { Debug.LogError($"Invalid parameters for GetTempRTDescriptor: {width}, {height}."); } RenderTextureDescriptor descriptor = GetTempRTDescriptor(renderingData); // descriptor.graphicsFormat = format; descriptor.width = width; descriptor.height = height; return descriptor; } public static void SetSourceSize(CommandBuffer cmd, RenderTextureDescriptor desc) { float width = desc.width; float height = desc.height; if (desc.useDynamicScale) { width *= ScalableBufferManager.widthScaleFactor; height *= ScalableBufferManager.heightScaleFactor; } cmd.SetGlobalVector(ShaderConstants._SourceSize, new Vector4(width, height, 1.0f / width, 1.0f / height)); } // Precomputed shader ids to same some CPU cycles (mostly affects mobile) static class ShaderConstants { public static readonly int _SourceSize = Shader.PropertyToID("_SourceSize"); } } /// /// Use this attribute to mark classes that can be used as a custom post-processing renderer /// [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public sealed class CompoundRendererFeatureAttribute : Attribute { // Name of the effect in the custom post-processing render feature editor readonly string name; // In which render pass this effect should be injected readonly InjectionPoint injectionPoint; // In case the renderer is added to multiple injection points, // If shareInstance = true, one instance of the renderer will be constructed and shared between the injection points. // Otherwise, a different instance will be constructed for every injection point. readonly bool shareInstance; /// Name of the effect in the custom post-processing render feature editor public string Name => name; /// In which render pass this effect should be injected public InjectionPoint InjectionPoint => injectionPoint; /// /// In case the renderer is added to multiple injection points, /// If shareInstance = true, one instance of the renderer will be constructed and shared between the injection points. /// Otherwise, a different instance will be constructed for every injection point. /// public bool ShareInstance => shareInstance; /// /// Marks this class as a custom post processing renderer /// /// Name of the effect in the custom post-processing render feature editor /// In which render pass this effect should be injected public CompoundRendererFeatureAttribute(string name, InjectionPoint injectionPoint, bool shareInstance = false) { this.name = name; this.injectionPoint = injectionPoint; this.shareInstance = shareInstance; } /// /// Get the CompoundRendererFeatureAttribute attached to the type. /// /// the type on which the attribute is attached /// the attached CompoundRendererFeatureAttribute or null if none were attached public static CompoundRendererFeatureAttribute GetAttribute(Type type) { if (type == null) return null; var attributes = type.GetCustomAttributes(typeof(CompoundRendererFeatureAttribute), false); return (attributes.Length != 0) ? (attributes[0] as CompoundRendererFeatureAttribute) : null; } } }