Unity的URP的自定义后处理效果(二)之 自定义扩展Volume

7 篇文章 2 订阅
2 篇文章 0 订阅

抓手

本文将会具体阐述,如何扩展Unity URP的Volume。

之前写过一篇叫《Unity的URP的自定义后处理效果》的文章,传送门:

https://blog.csdn.net/zakerhero/article/details/106793571,但是并不完全是我想要的效果。

因为最终我是希望像Unity 的Volume一样去添加自定义的后处理效果,可以随时关闭和打开。

最近参考了一些文章,终于知道怎么做了。以下是具体做法。

具体实现:

一共五个大步骤。

步骤一:

创建VolumeComponent类。

在com.unity.render-pipelines.universal@7.4.3\Runtime\Overrides源码里,有URP自带的后处理的类。

参考它们的bloom.cs,在URP的命名空间下定义自己的VolumeComponent类,这里我的类名叫HologramBlock。

using System;

namespace UnityEngine.Rendering.Universal
{
    //定义类
}

接着,在定义类的上面加上以下代码,就是把我们的类加入到Volume的组件里。 

[System.Serializable, VolumeComponentMenu("HL/HologramBlock")]

整个文件的代码如下:

using System;

namespace UnityEngine.Rendering.Universal
{
    [System.Serializable, VolumeComponentMenu("HL/HologramBlock")]
    public sealed class HologramBlock : VolumeComponent, IPostProcessComponent
    {
        [Tooltip("是否开启效果")]
        public BoolParameter enableEffect = new BoolParameter(true);

        public bool IsActive() => enableEffect==true;

        public bool IsTileCompatible() => false;
    }
}

然后就可以在Volume下面找到我们的Volume组件啦!

但是目前还没有任何效果哈,下面的步骤就是给我们的Volume添加实际的效果。

步骤二:

创建自定义的ScriptableRendererFeatureScriptableRenderPass

 因为Unity暂时在URP自定义扩展Volume并没有太多接口和相关文档说明,也有可能是我没找到。

所以目前的方法还是通过ScriptableRendererFeature和ScriptableRenderPass去做。

如果对部分理论有不理解的可以参考我之前的文章,传送门:Unity的URP的自定义后处理效果

首先定义我们的ScriptableRendererFeature

using UnityEngine.Rendering.Universal;

public class HologramBlockRenderFeature : ScriptableRendererFeature
{

    HologramBlockRenderPass m_ScriptablePass;

    public override void Create()
    {
        m_ScriptablePass = new HologramBlockRenderPass();
        m_ScriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
        m_renderTargetHandle.Init("_ScreenTexture2");
    }
    RenderTargetHandle m_renderTargetHandle;

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        var dest =  RenderTargetHandle.CameraTarget;
        m_ScriptablePass.Setup(renderer.cameraColorTarget, dest);
        renderer.EnqueuePass(m_ScriptablePass);
    }
}

接着定义我们的ScriptableRenderPass,在Override的Execute方法里做我们的具体的后处理:

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        if (holoMat == null)
        {
            UnityEngine.Debug.LogError("材质没找到!"); 
            return;
        }
        if (!renderingData.cameraData.postProcessEnabled) return;
        //通过队列来找到HologramBlock组件,然后
        var stack = VolumeManager.instance.stack;
        hologramBlock = stack.GetComponent<HologramBlock>();
        if (hologramBlock == null){return;}
        if (!hologramBlock.IsActive())return;

        var cmd = CommandBufferPool.Get(k_RenderTag);
        Render(cmd, ref renderingData);
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);        
    }

上面使用了VolumeManager.instance.stack的GetComponent方法获得我们的自定义Volume类的实例。

并获取里面的属性变量来做具体的后处理。

可以调用我们的HologramBlock组件的IsActive方法来判断是否执行该后处理。

诚然,这个IsActive返回的值,是你自己在继承的VolumeComponent类里定义的,

并非是VolumeComponent组件的启用和禁用决定的。

步骤三:

写后处理所需的shader。

写我们后处理的shader,该shader是一个视频错误效果。

我在ScriptableRenderPass的构造函数中用该shader创建了一个Material。

    public HologramBlockRenderPass()
    {
        var shader = Shader.Find("Hidden/HL/HologramBlockPE");
        holoMat = CoreUtils.CreateEngineMaterial(shader);
        m_temporaryColorTexture.Init("temporaryColorTexture");

    }

 shader文件内容在源码下载中可见,文件名是HologramBlockPE.shader。

步骤四:

配置我们的东西到Unity里。

在ForwardRendererData里Add Renderer Feature。

在Camera中勾选Post Processing

同时,在Camera的Environment的Volume Mask中选择相应的volume的gameObject的Layer。

步骤五:

最后,把HologramBlock添加到Volume里,就可以生效了。我使用了

这里我在代码里添加了Enable Effect来控制是否生效。

因为RenderFeature一旦加入到ForwardRendererData里,

它就一直会执行ScriptableRenderPass的Execute方法。这个我感觉挺不喜欢的。

最终效果:

该方法存在的问题:

RenderFeature一旦加入到ForwardRendererData里,它就一直会执行ScriptableRenderPass的Execute方法。

所以我只能通过外部的代码来控制Execute方法里的东西是否执行。勾线掉该组件,并非能让它不生效。

也可能是我没找到相应的接口吧。如果有问题,请朋友们指出。

为了解决这个问题,比如我可以写一个PostEffectCtrl的类,如果我不需要该后处理,

我就会将PostEffectCtrl的静态变量Close的值设为false,然后

使用PostEffectCtrl.Close来判断是否执行ScriptableRenderPass的Execute的内容,

不需要就return。

另外,可以给VolumeComponent类配对一个VolumeComponentEditor

如果你对界面显示有要求的话,可以写一个VolumeComponentEditor哈。

代码也比较简单,只需继承VolumeComponentEditor类,并且

在定义类的上面添加[VolumeComponentEditor(typeof(你的VolumeComponent类名))],大体如下:

using UnityEngine.Rendering.Universal;

namespace UnityEditor.Rendering.Universal
{
    [VolumeComponentEditor(typeof(HologramBlock))]
    sealed class HologramBlockEditor : VolumeComponentEditor
    {
    }
}

具体可以看我提供的工程里的源码哈,文件名为HologramBlockEditor.cs

源码下载:

链接:https://pan.baidu.com/s/1_9lkdanrnnZAFZAeIvbtEQ 
提取码:amqx

参考文章:

感谢这位日本朋友的文章,还有知乎的会编程的猫的文章。感谢他们前人栽树后人乘凉。

https://qiita.com/t-matsunaga/items/09343ae7c683269374c4

https://zhuanlan.zhihu.com/p/161658349

HDRP如何自定义扩展Volume可以参考Keijiro Takahashi大神的工程:

https://gitee.com/langlang1988/KinoEight

以上,最后,希望这篇文章能给在使用URP的朋友们带来帮助。

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值