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 = SortingCriteria.CommonOpaque; // 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"; /// /// 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; /// /// 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); 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; 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(false), }; PerObjectData renderConfig = ctx.hdCamera.frameSettings.IsEnabled(FrameSettingsField.Shadowmask) ? HDUtils.GetBakedLightingWithShadowMaskRenderConfig() : HDUtils.GetBakedLightingRenderConfig(); var result = new RendererListDesc(shaderPasses, ctx.cullingResults, ctx.hdCamera.camera) { rendererConfiguration = renderConfig, renderQueueRange = GetRenderQueueRange(renderQueueType), sortingCriteria = sortingCriteria, excludeObjectMotionVectors = false, overrideMaterial = overrideMaterial, overrideMaterialPassIndex = (overrideMaterial != null) ? overrideMaterial.FindPass(overrideMaterialPassName) : 0, stateBlock = stateBlock, layerMask = layerMask, }; CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, RendererList.Create(result)); } /// /// 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; } } }