using System.Collections.Generic; using UnityEngine.Rendering; using UnityEngine.Experimental.Rendering; using System; namespace UnityEngine.Rendering.HighDefinition { /// /// DrawRenderers Custom Pass /// [System.Serializable] public class DrawRenderersCustomPass : CustomPass { /// /// HDRP Shader passes /// public enum ShaderPass { // Ordered by frame time in HDRP ///Object Depth pre-pass, only the depth of the object will be rendered. DepthPrepass = 1, ///Forward pass, render the object color. Forward = 0, } // Used only for the UI to keep track of the toggle state [SerializeField] internal bool filterFoldout; [SerializeField] internal bool rendererFoldout; //Filter settings /// /// Render Queue filter to select which kind of object to render. /// public RenderQueueType renderQueueType = RenderQueueType.AllOpaque; /// /// Layer Mask filter, select which layer to render. /// public LayerMask layerMask = 1; // Layer mask Default enabled /// /// Sorting flags of the objects to render. /// public SortingCriteria sortingCriteria = HDUtils.k_OpaqueSortingCriteria; /// /// Select which type of override to apply on the DrawRenderers pass. /// public enum OverrideMaterialMode { /// Disable the material override None, /// Override the material for all renderers Material, /// Override the shader for all renderers. This option keeps the material properties of the renderer and can be used like a replacement shader. Shader }; /// /// Controls how the material on each renderer will be replaced. Material mode uses overrideMaterial. Shader mode uses overrideShader. /// public OverrideMaterialMode overrideMode = OverrideMaterialMode.Material; //default to Material as this was previously the only option // Override material /// /// Replaces the material of selected renders by this one, be sure to also set overrideMaterialPassName to a good value when using this property. /// public Material overrideMaterial = null; [SerializeField] int overrideMaterialPassIndex = 0; /// /// Select which pass will be used to render objects when using an override material. /// public string overrideMaterialPassName = "Forward"; // Override shader /// /// Replaces the shader of selected renderers while using the current material properties. /// public Shader overrideShader = null; [SerializeField] int overrideShaderPassIndex = 0; /// /// Select whih pass will be used to render objects when using an override material. /// public string overrideShaderPassName = "Forward"; /// /// When true, overrides the depth state of the objects. /// public bool overrideDepthState = false; /// /// Overrides the Depth comparison function, only used when overrideDepthState is true. /// public CompareFunction depthCompareFunction = CompareFunction.LessEqual; /// /// Overrides the Depth write, only used when overrideDepthState is true. /// public bool depthWrite = true; /// /// Override the stencil state of the objects. /// public bool overrideStencil = false; /// /// Stencil reference value. Be careful when using this value to write in the stencil buffer to not overwrite HDRP stencil bits. /// public int stencilReferenceValue = (int)UserStencilUsage.UserBit0; /// /// Write mask of the stencil. /// public int stencilWriteMask = (int)(UserStencilUsage.AllUserBits); /// /// Read mask of the stencil /// public int stencilReadMask = (int)(UserStencilUsage.AllUserBits); /// /// Comparison operation between the stencil buffer and the reference value. /// public CompareFunction stencilCompareFunction = CompareFunction.Always; /// /// Operation to execute if the stencil test passes. /// public StencilOp stencilPassOperation; /// /// Operation to execute if the stencil test fails. /// public StencilOp stencilFailOperation; /// /// Operation to execute if the depth test fails. /// public StencilOp stencilDepthFailOperation; /// /// Set the shader pass to use when the override material is null /// public ShaderPass shaderPass = ShaderPass.Forward; int fadeValueId; static ShaderTagId[] forwardShaderTags; static ShaderTagId[] depthShaderTags; // Cache the shaderTagIds so we don't allocate a new array each frame ShaderTagId[] cachedShaderTagIDs; /// /// Called before the first execution of the pass occurs. /// Allow you to allocate custom buffers. /// /// The render context /// Current command buffer of the frame protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) { fadeValueId = Shader.PropertyToID("_FadeValue"); // In case there was a pass index assigned, we retrieve the name of this pass if (String.IsNullOrEmpty(overrideMaterialPassName) && overrideMaterial != null) overrideMaterialPassName = overrideMaterial.GetPassName(overrideMaterialPassIndex); if (String.IsNullOrEmpty(overrideShaderPassName) && overrideShader != null) overrideShaderPassName = new Material(overrideShader).GetPassName(overrideShaderPassIndex); forwardShaderTags = new ShaderTagId[] { HDShaderPassNames.s_ForwardName, // HD Lit shader HDShaderPassNames.s_ForwardOnlyName, // HD Unlit shader HDShaderPassNames.s_SRPDefaultUnlitName, // Cross SRP Unlit shader HDShaderPassNames.s_EmptyName, // Add an empty slot for the override material }; depthShaderTags = new ShaderTagId[] { HDShaderPassNames.s_DepthForwardOnlyName, HDShaderPassNames.s_DepthOnlyName, HDShaderPassNames.s_EmptyName, // Add an empty slot for the override material }; } /// /// Use this method if you want to draw objects that are not visible in the camera. /// For example if you disable a layer in the camera and add it in the culling parameters, then the culling result will contains your layer. /// /// Aggregate the parameters in this property (use |= for masks fields, etc.) /// The camera where the culling is being done protected override void AggregateCullingParameters(ref ScriptableCullingParameters cullingParameters, HDCamera hdCamera) { cullingParameters.cullingMask |= (uint)(int)layerMask; } ShaderTagId[] GetShaderTagIds() { if (shaderPass == ShaderPass.DepthPrepass) return depthShaderTags; else return forwardShaderTags; } /// /// Execute the DrawRenderers with parameters setup from the editor /// /// The context of the custom pass. Contains command buffer, render context, buffer, etc. protected override void Execute(CustomPassContext ctx) { var shaderPasses = GetShaderTagIds(); if (overrideMaterial != null) { shaderPasses[shaderPasses.Length - 1] = new ShaderTagId(overrideMaterialPassName); overrideMaterial.SetFloat(fadeValueId, fadeValue); } if (shaderPasses.Length == 0) { Debug.LogWarning("Attempt to call DrawRenderers with an empty shader passes. Skipping the call to avoid errors"); return; } var mask = overrideDepthState ? RenderStateMask.Depth : 0; mask |= overrideDepthState && !depthWrite ? RenderStateMask.Stencil : 0; if (overrideStencil) mask |= RenderStateMask.Stencil; var stateBlock = new RenderStateBlock(mask) { depthState = new DepthState(depthWrite, depthCompareFunction), // We disable the stencil when the depth is overwritten but we don't write to it, to prevent writing to the stencil. stencilState = new StencilState(overrideStencil, (byte)stencilReadMask, (byte)stencilWriteMask, stencilCompareFunction, stencilPassOperation, stencilFailOperation, stencilDepthFailOperation), stencilReference = overrideStencil ? stencilReferenceValue : 0, }; PerObjectData renderConfig = HDUtils.GetRendererConfiguration(ctx.hdCamera.frameSettings.IsEnabled(FrameSettingsField.AdaptiveProbeVolume), ctx.hdCamera.frameSettings.IsEnabled(FrameSettingsField.Shadowmask)); var overrideShaderMaterial = (overrideShader != null) ? new Material(overrideShader) : null; var result = new RendererUtils.RendererListDesc(shaderPasses, ctx.cullingResults, ctx.hdCamera.camera) { rendererConfiguration = renderConfig, renderQueueRange = GetRenderQueueRange(renderQueueType), sortingCriteria = sortingCriteria, excludeObjectMotionVectors = false, overrideShader = overrideMode == OverrideMaterialMode.Shader ? overrideShader : null, overrideMaterial = overrideMode == OverrideMaterialMode.Material ? overrideMaterial : null, overrideMaterialPassIndex = (overrideMaterial != null) ? overrideMaterial.FindPass(overrideMaterialPassName) : 0, overrideShaderPassIndex = (overrideShader != null) ? overrideShaderMaterial.FindPass(overrideShaderPassName) : 0, stateBlock = stateBlock, layerMask = layerMask, }; Object.DestroyImmediate(overrideShaderMaterial); var renderCtx = ctx.renderContext; var rendererList = renderCtx.CreateRendererList(result); bool opaque = renderQueueType == RenderQueueType.AllOpaque || renderQueueType == RenderQueueType.OpaqueAlphaTest || renderQueueType == RenderQueueType.OpaqueNoAlphaTest; HDRenderPipeline.RenderForwardRendererList(ctx.hdCamera.frameSettings, rendererList, opaque, ctx.renderContext, ctx.cmd); } /// /// List all the materials that need to be displayed at the bottom of the component. /// All the materials gathered by this method will be used to create a Material Editor and then can be edited directly on the custom pass. /// /// An enumerable of materials to show in the inspector. These materials can be null, the list is cleaned afterwards public override IEnumerable RegisterMaterialForInspector() { yield return overrideMaterial; } } }