HDRP(SRP) 渲染一个摄像机剔除遮罩外的物体

4 篇文章 1 订阅

设置一个被剔除的图层

在这里插入图片描述

编写一个 CustomPass

AggregateCullingParameters 中,额外包含了目标图层,以进行接下来的渲染。

Execute() 中,这个 Pass 主要做了以下事情:

  1. 对目标图层进行完整渲染。(cameraColorBuffer
  2. 对目标图层写入Motion Vector。(cameraMotionVectorsBuffer
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
using System.Collections.Generic;
using System;

/// <summary>
/// DrawRenderers Custom Pass
/// </summary>
[System.Serializable]
public class ViewingObjectPass : CustomPass
{
    /// <summary>
    /// HDRP Shader passes
    /// </summary>
    public enum ShaderPass
    {
        // Ordered by frame time in HDRP
        ///<summary>Object Depth pre-pass, only the depth of the object will be rendered.</summary>
        DepthPrepass = 1,
        ///<summary>Forward pass, render the object color.</summary>
        Forward = 0,
    }

    // Used only for the UI to keep track of the toggle state
    [SerializeField] internal bool filterFoldout;
    [SerializeField] internal bool rendererFoldout;

    //Filter settings
    /// <summary>
    /// Render Queue filter to select which kind of object to render.
    /// </summary>
    public RenderQueueType renderQueueType = RenderQueueType.AllOpaque;
    /// <summary>
    /// Layer Mask filter, select which layer to render.
    /// </summary>
    public LayerMask layerMask = 1; // Layer mask Default enabled
    /// <summary>
    /// Sorting flags of the objects to render.
    /// </summary>
    public SortingCriteria sortingCriteria = SortingCriteria.CommonOpaque;

    /// <summary>
    /// When true, overrides the depth state of the objects.
    /// </summary>
    public bool overrideDepthState = false;
    /// <summary>
    /// Overrides the Depth comparison function, only used when overrideDepthState is true.
    /// </summary>
    public CompareFunction depthCompareFunction = CompareFunction.LessEqual;
    /// <summary>
    /// Overrides the Depth write, only used when overrideDepthState is true.
    /// </summary>
    public bool depthWrite = true;

    /// <summary>
    /// Set the shader pass to use when the override material is null
    /// </summary>
    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;

    [SerializeField, HideInInspector]
    Shader motionVectorShader;
    Material motionVector;

    /// <summary>
    /// Called before the first execution of the pass occurs.
    /// Allow you to allocate custom buffers.
    /// </summary>
    /// <param name="renderContext">The render context</param>
    /// <param name="cmd">Current command buffer of the frame</param>
    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
        };

        
        motionVectorShader = Shader.Find("Hidden/HDRP/MotionVectors");
        motionVector = CoreUtils.CreateEngineMaterial(motionVectorShader);
    }

    /// <summary>
    /// 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.
    /// </summary>
    /// <param name="cullingParameters">Aggregate the parameters in this property (use |= for masks fields, etc.)</param>
    /// <param name="hdCamera">The camera where the culling is being done</param>
    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;
    }

    /// <summary>
    /// Execute the DrawRenderers with parameters setup from the editor
    /// </summary>
    /// <param name="ctx">The context of the custom pass. Contains command buffer, render context, buffer, etc.</param>
    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 UnityEngine.Rendering.RendererUtils.RendererListDesc(shaderPasses, ctx.cullingResults, ctx.hdCamera.camera)
        {
            rendererConfiguration = renderConfig,
            renderQueueRange = GetRenderQueueRange(renderQueueType),
            sortingCriteria = sortingCriteria,
            excludeObjectMotionVectors = false,
            stateBlock = stateBlock,
            layerMask = layerMask,
        };

        var renderCtx = ctx.renderContext;
        CoreUtils.SetRenderTarget(ctx.cmd, ctx.cameraColorBuffer, ctx.cameraDepthBuffer, ClearFlag.None);
        CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, renderCtx.CreateRendererList(result));

        result = new UnityEngine.Rendering.RendererUtils.RendererListDesc(HDShaderPassNames.s_MotionVectorsName, ctx.cullingResults, ctx.hdCamera.camera)
        {
            rendererConfiguration = PerObjectData.MotionVectors,
            renderQueueRange = GetRenderQueueRange(renderQueueType),
            sortingCriteria = sortingCriteria,
            excludeObjectMotionVectors = false,
            stateBlock = stateBlock,
            layerMask = layerMask,
        };

        CoreUtils.SetRenderTarget(ctx.cmd, ctx.cameraMotionVectorsBuffer, ctx.cameraDepthBuffer, ClearFlag.None);
        CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, renderCtx.CreateRendererList(result));
    }

    protected override void Cleanup()
    {
        CoreUtils.Destroy(motionVector);
    }
}

把 Pass 挂起来,如图进行配置

在这里插入图片描述

效果

理论上不出bug的话跟正常渲染没啥区别(
在这里插入图片描述

可能会有奇怪的地方出BUG,比如SSAO(这个我直接禁用了),比如运动模糊和TAA(已经修复,即代码中的写入Motion Vector),欢迎留言讨论。
抛砖引玉,恳请批评指正!

参考文献:

Unity SRP 中渲染 Motion Vector 的正确姿势 - SardineFish - https://www.sardinefish.com/blog/458

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值