找回密码
 立即注册
查看: 190|回复: 0

unity urp 14 render feature实现简单后处理系统

[复制链接]
发表于 2022-7-4 18:42 | 显示全部楼层 |阅读模式
一、思路

在unity urp中,unity官方不像在build in管线种一样提供了后处理的接口,所以需要借助render feature来实现后处理效果。
总的思路就是,render feature可以获取到某一时刻绘制出来的图像(比如全部不透明物体,或者全部物体绘制后),之后获取到这个图像进行处理,再将处理的结果放回到渲染管线中。
1.1流程

首先要建立一个类继承ScriptableRendererFeature
public class BrightnessPosetProcessing : ScriptableRendererFeature
{
   //...
}然后创建一个自己的pass类
public class BrightnessPosetProcessing : ScriptableRendererFeature
{
    //*************************************************
    //**********      自定义Pass类   **************
    //**************************************************
    class CustomRenderPass : ScriptableRenderPass
    {
       //....
    }
}之后在Create接口中,对自己的Pass进行初始化(这里也是最开始运行的地方),注意pass的声明要写在函数外
    private CustomRenderPass pass;
    //*************************************************
    //**********          初始化      **************
    //**************************************************
    public override void Create()
    {
        pass = new CustomRenderPass(setting.passEvent, setting.mat, name);
    }最后,获取相机输出的图像,使用该pass处理,然后将这个pass添加进渲染管线中
    private CustomRenderPass pass;
    //*************************************************
    //**********          初始化      **************
    //**************************************************
    public override void Create()
    {
        pass = new CustomRenderPass(setting.passEvent, setting.mat, name);
    }  
    //*************************************************
    //**********      将pass添加到渲染管线   **************
    //**************************************************
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        //获取当前相机中的图像
        var src = renderer.cameraColorTarget;
        pass.SetUp(src);
        //将该pass添加到渲染管线中
        renderer.EnqueuePass(pass);
    }1.2核心实现

以上流程中的核心是自定义pass的实现,而自定义pass中的核心是Execute函数的实现,这个函数会在每一帧绘制的时候被调用。
        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            //从命令缓冲区池获取一个带标签的命令缓冲区,该标签名在帧调试器中可以见到
            CommandBuffer cmd = CommandBufferPool.Get(passTag);
            //获取目标相机的描述信息,创建一个结构体,里面有render texture各中信息,比如尺寸,深度图精度等等
            RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
            //设置深度缓冲区,0表示不需要深度缓冲区
            opaqueDesc.depthBufferBits = 0;
            //申请临时图像
            cmd.GetTemporaryRT(passTempleColorTex.id, opaqueDesc);
            //将源图像放入材质中计算,然后存储到临时缓冲区中
            cmd.Blit(passSource, passTempleColorTex.Identifier(), passMat);
            //将临时缓冲区的结果存回源图像中
            cmd.Blit(passTempleColorTex.Identifier(), passSource);
            //执行命令缓冲区
            context.ExecuteCommandBuffer(cmd);
            //释放命令缓存
            CommandBufferPool.Release(cmd);
            //释放临时render texture
            cmd.ReleaseTemporaryRT(passTempleColorTex.id);
        }二、代码

SimplePostProcessing.shader
Shader "Unlit/16_SimplePostProcessing"
{
    Properties
    {
        [HideInInspector]_MainTex ("Texture", 2D) = "white" {}
        _Brightness("Brightness", Range(0,1)) = 1
        _Saturate("Saturate", Range(0,1)) = 1
        _Contrast("Constrast", Range(-1,2)) = 1
    }
    SubShader
    {
        Tags
        {
            "RenderPipeline"="UniversalRenderPipeline"
        }
        Cull Off
        ZWrite Off
        ZTest Always
        
        HLSLINCLUDE
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        CBUFFER_START(UnityPerMaterial)
        float _Brightness;
        float _Saturate;
        float _Contrast;        
        CBUFFER_END
        TEXTURE2D(_MainTex);
        SAMPLER(sampler_MainTex);
        struct Attributes
        {
            float4 positionOS: POSITION;
            float2 texcoord: TEXCOORD0;
        };
        struct Varyings
        {
            float4 positionCS:SV_POSITION;
            float2 uv:TEXCOORD0;
        };
        ENDHLSL

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            Varyings vert(Attributes input)
            {
                Varyings output;
                output.positionCS = TransformObjectToHClip(input.positionOS);
                output.uv = input.texcoord;
                return output;
            }

            half4 frag (Varyings input) : SV_Target
            {
                half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
                float grey = 0.21*tex.x+0.72*tex.y+0.072*tex.z;
                tex.xyz *= _Brightness;
                tex.xyz = lerp(float3(grey,grey,grey), tex.xyz, _Saturate);
                tex.xyz = lerp(float3(0.5,0.5,0.5),tex.xyz, _Contrast);
                return tex;
            }
            ENDHLSL
        }
    }
}
BrightnessPostProcessing.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class BrightnessPosetProcessing : ScriptableRendererFeature
{
    //定义配置类
    [System.Serializable]
    public class Setting
    {
        //默认在透明物体绘制完成后进行处理
        public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;
        //后续需要用到的材质
        public Material mat;
    }
   
    public Setting setting = new Setting();
   
    //*************************************************
    //**********      自定义Pass类   **************
    //**************************************************
    class CustomRenderPass : ScriptableRenderPass
    {
        //后处理用到的材质
        public Material passMat = null;
        private RenderTargetIdentifier passSource { get; set; }//源图像,目标图像
        private RenderTargetHandle passTempleColorTex;//临时计算的图像
        //标签名,用于在帧调试器中显示缓冲区的名称
        private string passTag;
        
        //构造函数
        public CustomRenderPass(RenderPassEvent passEvent, Material material, string tag)
        {
            this.renderPassEvent = passEvent;
            this.passMat = material;
            passTag = tag;
        }

        //设置Pass
        public void SetUp(RenderTargetIdentifier source)
        {
            this.passSource = source;
        }

        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            //从命令缓冲区池获取一个带标签的命令缓冲区,该标签名在帧调试器中可以见到
            CommandBuffer cmd = CommandBufferPool.Get(passTag);
            //获取目标相机的描述信息,创建一个结构体,里面有render texture各中信息,比如尺寸,深度图精度等等
            RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
            //设置深度缓冲区,0表示不需要深度缓冲区
            opaqueDesc.depthBufferBits = 0;
            //申请临时图像
            cmd.GetTemporaryRT(passTempleColorTex.id, opaqueDesc);
            //将源图像放入材质中计算,然后存储到临时缓冲区中
            cmd.Blit(passSource, passTempleColorTex.Identifier(), passMat);
            //将临时缓冲区的结果存回源图像中
            cmd.Blit(passTempleColorTex.Identifier(), passSource);
            //执行命令缓冲区
            context.ExecuteCommandBuffer(cmd);
            //释放命令缓存
            CommandBufferPool.Release(cmd);
            //释放临时render texture
            cmd.ReleaseTemporaryRT(passTempleColorTex.id);
        }
    }

    private CustomRenderPass pass;
    //*************************************************
    //**********          初始化      **************
    //**************************************************
    public override void Create()
    {
        pass = new CustomRenderPass(setting.passEvent, setting.mat, name);
    }

    //*************************************************
    //**********      将pass添加到渲染管线   **************
    //**************************************************
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        //获取当前相机中的图像
        var src = renderer.cameraColorTarget;
        pass.SetUp(src);
        //将该pass添加到渲染管线中
        renderer.EnqueuePass(pass);
    }
}
三、结果





四、参考

[笔记]URP-屏幕后处理
[Unity]为了更好用的后处理——扩展URP后处理踩坑记录
urp管线的自学hlsl之路 第十七篇 建立自己的后处理系统并调整屏幕的亮度饱和度对比度

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-19 02:59 , Processed in 0.089052 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表