unity在URP中实现自定义Volume

  在unity默认bulit-in管线中,后处理效果一般可以在在相机上挂一个脚本加上OnRenderImage函数,并使用Graphics.Blit用某个材质对最后相机展现的画面进行处理。
  在URP中OnRenderImage不生效了,并且有了一个专门做后处理的Volume。但由于相关代码都写在了一个叫PostProcessPass的脚本中,除非修改源码,否则无法仅通过扩展一个VolumeComponent来实现一个自定义后处理。好在URP提供了一个RendererFeature的功能,我们可以通过这个自行添加一个pass管理我们的自定义Volume。事实上URP也是这么做的。

1.创建自定义VolumeComponent

  要注意的是这里要写在面板上显示参数,不能定义int,float这些基础类型,unity做了一层封装FloatParameter,IntParameter之类。要定义限制范围的参数要使用ClampedFloatParameter等而不是FloatRangeParameter,一开始被坑了一下。

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

[System.Serializable, VolumeComponentMenu("XPostProcess/ColorAdjustMenstsBasedPosAndDepth")]
public class ColorAdjustMenstsBasedPosAndDepth : VolumeComponent, IPostProcessComponent
{
    public BoolParameter enableEffect = new BoolParameter(true);

    public FloatParameter radius = new FloatParameter(1000000);
    public Vector3Parameter center = new Vector3Parameter(Vector3.zero);
    public ClampedFloatParameter intensity = new ClampedFloatParameter(0.5f, 0, 1);
    public ClampedFloatParameter backgraoundIntensity = new ClampedFloatParameter(0.5f, 0, 1);
    public ColorParameter backgroundColor = new ColorParameter(Color.black);
    public Vector3Parameter colorScale = new Vector3Parameter(Vector3.one);

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

    public bool IsTileCompatible() => false;
}

  VolumetiComponent定义完后就可以在Volume的面板上看到并添加了。

在这里插入图片描述

2.创建自定义RenderFeature

using UnityEngine.Rendering.Universal;

public class XPostProcessRenderFeature : ScriptableRendererFeature
{
    XPostProcessRenderPass m_ScriptablePass;

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {

        var src = renderer.cameraColorTarget;
        var dest = RenderTargetHandle.CameraTarget;
        m_ScriptablePass.Setup(src, dest, renderingData.cameraData.camera);
        renderer.EnqueuePass(m_ScriptablePass);
    }

    public override void Create()
    {
        m_ScriptablePass = new XPostProcessRenderPass();
    }
}

3.创建自定义RenderPass

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class XPostProcessRenderPass : ScriptableRenderPass
{
    RenderTargetHandle m_temporaryColorTexture;
    RenderTargetIdentifier source;
    RenderTargetHandle destination;
    Camera m_camera;

    private ColorAdjustMenstsBasedPosAndDepth m_CustomVolume;

    private readonly string CUSTOM_PASS_TAG = "Custom Pass";
    private readonly MaterialLibrary m_MaterialLibrary = new MaterialLibrary();


    public XPostProcessRenderPass()
    {
        this.renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
        m_temporaryColorTexture.Init("temporaryColorTexture");
    }

    public void Setup(RenderTargetIdentifier src, RenderTargetHandle dest, Camera camera)
    {
        this.source = src;
        this.destination = dest;
        this.m_camera = camera;
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        if (!renderingData.cameraData.postProcessEnabled) return;

        ConfigCamera();

        VolumeStack stack = VolumeManager.instance.stack;
        m_CustomVolume = stack.GetComponent<ColorAdjustMenstsBasedPosAndDepth>();
        // 这里可以继续添加别的后处理效果


        CommandBuffer cmd = CommandBufferPool.Get(CUSTOM_PASS_TAG);

        Render(cmd, ref renderingData);

        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }

    private void Render(CommandBuffer cmd, ref RenderingData renderingData)
    {
        var frustumCorners = ConfigCamera();

        if (m_CustomVolume.IsActive() && m_CustomVolume.active)
        {
            var colorAdjustmentsBasedPosAndDepth = m_MaterialLibrary.colorAdjustmentsBasedPosAndDepth;
            colorAdjustmentsBasedPosAndDepth.SetFloat(ShaderConstants.Intensity, m_CustomVolume.intensity.value);
            colorAdjustmentsBasedPosAndDepth.SetFloat(ShaderConstants.BackGroundIntensity, m_CustomVolume.backgraoundIntensity.value);
            colorAdjustmentsBasedPosAndDepth.SetVector(ShaderConstants.Center, m_CustomVolume.center.value);
            colorAdjustmentsBasedPosAndDepth.SetVector(ShaderConstants.ColorScale, m_CustomVolume.colorScale.value);
            colorAdjustmentsBasedPosAndDepth.SetFloat(ShaderConstants.Radius, m_CustomVolume.radius.value);
            colorAdjustmentsBasedPosAndDepth.SetColor(ShaderConstants.BarkGroundColor, m_CustomVolume.backgroundColor.value);
            colorAdjustmentsBasedPosAndDepth.SetMatrix("_FrustumCornersRay", frustumCorners);

            RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
            opaqueDesc.depthBufferBits = 0;
            //不能读写同一个颜色target,创建一个临时的render Target去blit
            if (destination == RenderTargetHandle.CameraTarget)
            {
                cmd.GetTemporaryRT(m_temporaryColorTexture.id, opaqueDesc, FilterMode.Bilinear);
                Blit(cmd, source, m_temporaryColorTexture.Identifier(), colorAdjustmentsBasedPosAndDepth);
                Blit(cmd, m_temporaryColorTexture.Identifier(), source);
            }
            else
            {
                Blit(cmd, source, destination.Identifier(), colorAdjustmentsBasedPosAndDepth);
            }
        }
    }

    public override void FrameCleanup(CommandBuffer cmd)
    {
        if (destination == RenderTargetHandle.CameraTarget)
            cmd.ReleaseTemporaryRT(m_temporaryColorTexture.id);
    }

    private Matrix4x4 ConfigCamera()
    {
        Matrix4x4 frustumCorners = Matrix4x4.identity;

        float fov = m_camera.fieldOfView;
        float near = m_camera.nearClipPlane;
        float aspect = m_camera.aspect;
        Transform transform = m_camera.transform;

        float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
        Vector3 toRight = transform.right * halfHeight * aspect;
        Vector3 toTop = transform.up * halfHeight;

        Vector3 topLeft = transform.forward * near + toTop - toRight;
        float scale = topLeft.magnitude / near;

        topLeft.Normalize();
        topLeft *= scale;



        Vector3 topRight = transform.forward * near + toRight + toTop;
        topRight.Normalize();
        topRight *= scale;

        Vector3 bottomLeft = transform.forward * near - toTop - toRight;
        bottomLeft.Normalize();
        bottomLeft *= scale;

        Vector3 bottomRight = transform.forward * near + toRight - toTop;
        bottomRight.Normalize();
        bottomRight *= scale;

        frustumCorners.SetRow(0, bottomLeft);
        frustumCorners.SetRow(1, bottomRight);
        frustumCorners.SetRow(2, topRight);
        frustumCorners.SetRow(3, topLeft);

        return frustumCorners;
    }
}


class MaterialLibrary
{
    public readonly Material colorAdjustmentsBasedPosAndDepth;

    public MaterialLibrary()
    {
        colorAdjustmentsBasedPosAndDepth = Load(Shader.Find("XPostProcess/ColorAdjustmentsBasedPosAndDepth"));
    }

    Material Load(Shader shader)
    {
        if (shader == null)
        {
            Debug.LogErrorFormat($"Missing shader. {GetType().DeclaringType.Name} render pass will not execute. Check for missing reference in the renderer resources.");
            return null;
        }
        else if (!shader.isSupported)
        {
            return null;
        }

        return CoreUtils.CreateEngineMaterial(shader);
    }

    internal void Cleanup()
    {
        CoreUtils.Destroy(colorAdjustmentsBasedPosAndDepth);
    }
}

static class ShaderConstants
{
    public static readonly int Intensity = Shader.PropertyToID("_Intensity");
    public static readonly int BackGroundIntensity = Shader.PropertyToID("_BackGroundIntensity");
    public static readonly int Center = Shader.PropertyToID("_Center");
    public static readonly int Radius = Shader.PropertyToID("_Radius");
    public static readonly int BarkGroundColor = Shader.PropertyToID("_BarkGroundColor");
    public static readonly int ColorScale = Shader.PropertyToID("_ColorScale");
}

4.添加RenderFeature

  至此就可以给RenderData添加一个自定义feature了,添加完后自定义的Volume效果就可以使用了。如果有超过一个后处理效果需要添加,可以新增自定义Volume并修改RenderPass。

在这里插入图片描述

5.小结

  目前还有一个问题没有找到原因,就是自定义的Voume添加之后再移除,效果依然在,并没有从VolumeManager.instance.stack中去掉。不知道这是个bug还是我哪儿写的有问题。不过不怎么影响,给Volume加个enable参数就行了,就随他去了。也有办法解决,VolumeComponent就是个存储后处理数据的方式,并不实际处理后处理效果,完全可以自己写个管理器管理自定义Volume的添加删除,就是还得自己再写一下编辑器扩展。

原文地址:https://blog.csdn.net/xdedzl/article/details/114746972

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了Unity游戏开发中外观模式是什么意思,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章主要介绍Unity中地面检测方案的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1.普通射线在角色坐标(一般是脚底)...
这篇文章主要介绍了Unity游戏开发中如何消除不想要的黄色警告,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带...
这篇文章主要介绍了Unity中有多少种渲染队列,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解
这篇文章主要介绍Unity中如何实现Texture,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!了解Texture2D 如上图,Texture2D是一张
小编给大家分享一下Unity中DOTS要实现的特点有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让...
这篇文章给大家分享的是有关unity中如何实现UGUI遮罩流光特效的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。下面是核心shader:Sh...
这篇文章主要为大家展示了“Unity中如何实现3D坐标转换UGUI坐标”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下...
这篇文章主要介绍了Unity游戏开发中设计模式的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章主要介绍了Unity中如何实现仿真丝袜渲染,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了...
这篇文章给大家分享的是有关Unity插件OVRLipSync有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。项目需要接入对话口型动...
这篇文章主要介绍了Unity性能优化之DrawCall的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章给大家分享的是有关Unity给力插件之Final IK怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。这插件有什么用:一般游...
这篇文章给大家分享的是有关Unity中如何内嵌网页插件UniWebView的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、常见Unity中内...
小编给大家分享一下Unity如何做流体物理的几个轮子,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让...
小编给大家分享一下Unity中Lod和Occlusion Culling的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收...
这篇文章将为大家详细讲解有关Unity中LineRenderer与TrailRenderer有什么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获...
这篇文章主要介绍了Unity中coroutine问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起...
这篇文章将为大家详细讲解有关unity中spine怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。骨骼动画首先我们来看到...
这篇文章主要为大家展示了“Unity Shader后处理中如何实现简单均值模糊”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学...