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

unity urp 17 Bloom效果

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

Bloom的效果就是再模糊效果的基础上完成的。整体的思路就是设置一个阈值,提取图中高亮区域,对其进行模糊处理,然后再将处理后的图像与原图混合。
具体的过程是:创建一个Shader文件和一个Render Feature文件,Shader文件中有三个Pass(两个一个维高斯模糊的情况下有四个pass)
第一个pass中使用luminance函数获取纹理的亮度,然后根据设置的阈值来获取高亮区域。
第二个pass中则对纹理图像进行高斯模糊计算。
第三个pass讲原始纹理图像与高斯模糊后得到的纹理图像进行混合。
在SimpleBloom.cs文件中,依次使用shader中的三个pass来处理图像。其中高斯模糊计算后的图像可以使用CommandBuffer.SetGlobalTexture()来将buffer中的纹理存储在rendertexture中。
cmd.SetGlobalTexture("_Bloom", buffer2);另外,在shader入门精要中提到,在开启抗锯齿并且有多个rendertexture的情况下,要根据平台差异来改变纹理的y轴方向
                output.uv = input.texcoord;
                output.uv2 = input.texcoord;
                #if UNITY_UV_STARTS_AT_TOP
                if(_MainTex_TexelSize.y<0.0)
                    output.uv2.y = 1.0 - output.uv2.y;
                #endif二、代码

Bloom.shader
Shader "Unlit/20_Bloom"
{
    Properties
    {
        [HideInInspector]_MainTex ("Texture", 2D) = "white" {}
        _BlurSize("Blur Size", Float) = 1.0
        _Threshold("Threshold", Float) = 1.0
        _Bloom("Bloom",2D) = "Black" {}
        _Intensity("Intensity", Float) = 1.0
    }
    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 _BlurSize;   
        float4 _MainTex_TexelSize;
        float _Threshold;
        float _Intensity;
        CBUFFER_END
        TEXTURE2D(_MainTex);
        SAMPLER(sampler_MainTex);
        TEXTURE2D(_Bloom);
        SAMPLER(sampler_Bloom);
        struct Attributes
        {
            float4 positionOS: POSITION;
            float2 texcoord: TEXCOORD0;
        };
        struct Varyings
        {
            float4 positionCS:SV_POSITION;
            float2 uv:TEXCOORD0;
            float2 uv2: TEXCOORD1;
        };
        ENDHLSL
        
        //获取较亮部分
        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            float luminance(float4 color)
            {
                return 0.2125*color.r+0.7154*color.g+0.0721*color.b;
            }

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

            float4 frag (Varyings input) : SV_Target
            {
                half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
                float bloom = clamp(luminance(tex) - _Threshold, 0.0, 1.0);

                return tex*bloom;
            }
            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;
            }

            float4 frag (Varyings input) : SV_Target
            {
                half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
                float2 uv = input.uv;
                half4 col = float4(0,0,0,0);
                col += 0.060 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(-1,-1)*_MainTex_TexelSize.xy*_BlurSize);
                col += 0.098 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(0,-1)*_MainTex_TexelSize.xy*_BlurSize);
                col += 0.060 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(1,-1)*_MainTex_TexelSize.xy*_BlurSize);
                col += 0.098 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(-1,0)*_MainTex_TexelSize.xy*_BlurSize);
                col += 0.162 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
                col += 0.098 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(1,0)*_MainTex_TexelSize.xy*_BlurSize);
                col += 0.060 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(1,-1)*_MainTex_TexelSize.xy*_BlurSize);
                col += 0.022 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(1,0)*_MainTex_TexelSize.xy*_BlurSize);
                col += 0.060 * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(1,1)*_MainTex_TexelSize.xy*_BlurSize);

                return col;
            }
            ENDHLSL
        }
        
        //混合原图像,高亮区域高斯模糊的后的结果
        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            Varyings vert(Attributes input)
            {
                Varyings output;
                output.positionCS = TransformObjectToHClip(input.positionOS);
                output.uv = input.texcoord;
                output.uv2 = input.texcoord;
                #if UNITY_UV_STARTS_AT_TOP
                if(_MainTex_TexelSize.y<0.0)
                    output.uv2.y = 1.0 - output.uv2.y;
                #endif
                return output;
            }

            float4 frag (Varyings input) : SV_Target
            {
                half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
                half4 bloom = SAMPLE_TEXTURE2D(_Bloom, sampler_Bloom, input.uv2);
               
                return tex+bloom*_Intensity;
            }
            ENDHLSL
        }
    }
}
SimpleBloom.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class SimpleBloom : ScriptableRendererFeature
{
    //定义配置类
    [System.Serializable]
    public class Setting
    {
        //默认在透明物体绘制完成后进行处理
        public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;
        //后续需要用到的材质
        public Material mat;
        [Range(0, 4)] public int iterations = 3;
        [Range(0.2f, 3.0f)] public float blurSpread = 0.6f;
        [Range(1, 8)] public int downSample = 2;
    }
   
    public Setting setting = new Setting();
   
    //*************************************************
    //**********      自定义Pass类   **************
    //**************************************************
    class CustomRenderPass : ScriptableRenderPass
    {
        //后处理用到的材质
        public Material passMat = null;
        private RenderTargetIdentifier passSource { get; set; }//源图像,目标图像
        private RenderTargetIdentifier buffer1;
        private RenderTargetIdentifier buffer2;
        private RenderTargetHandle passTempleColorTex;//临时计算的图像
        //标签名,用于在帧调试器中显示缓冲区的名称
        private string passTag;
        public int iterations;
        public float blurSpread;
        public int downSample;
        public FilterMode passFilterMode { get; set; }

        //构造函数
        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)
        {
            int bufferid1 = Shader.PropertyToID("bufferblur1");
            int bufferid2 = Shader.PropertyToID("bufferblur2");
            //从命令缓冲区池获取一个带标签的命令缓冲区,该标签名在帧调试器中可以见到
            CommandBuffer cmd = CommandBufferPool.Get(passTag);
            //获取目标相机的描述信息,创建一个结构体,里面有render texture各中信息,比如尺寸,深度图精度等等
            RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
            int width = opaqueDesc.width / downSample;
            int height = opaqueDesc.height / downSample;
            //设置深度缓冲区,0表示不需要深度缓冲区
            opaqueDesc.depthBufferBits = 0;
            //申请临时图像
            cmd.GetTemporaryRT(bufferid1, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
            cmd.GetTemporaryRT(bufferid2, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
            buffer1 = new RenderTargetIdentifier(bufferid1);
            buffer2 = new RenderTargetIdentifier(bufferid2);
            //获取index为0个pass,进行处理
            //获取高亮区域
            cmd.Blit(passSource, buffer1,passMat,0);
            for (int i = 0; i < iterations; i++)
            {
                cmd.SetGlobalFloat("BlurSize", 1.0f+i*blurSpread);
                //进行高斯模糊
               cmd.Blit(buffer1, buffer2, passMat,1);
               var tmpRT = buffer1;
               buffer1 = buffer2;
               buffer2 = tmpRT;
            }
            
            //生成名为Bloom的Render Texture
            //passMat.SetTexture("_Bloom", bufferid1);
            cmd.SetGlobalTexture("_Bloom", buffer2);
            //执行pass:混合高亮区域和原图像
            cmd.Blit(passSource,buffer1, passMat ,2);
            cmd.Blit(buffer1, passSource);
            //执行命令缓冲区
            context.ExecuteCommandBuffer(cmd);
            //释放命令缓存
            CommandBufferPool.Release(cmd);
            cmd.ReleaseTemporaryRT(bufferid1);
            cmd.ReleaseTemporaryRT(bufferid2);
        }
    }

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

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



法线图像有些模糊,并且bloom效果不太理想。

本帖子中包含更多资源

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

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

本版积分规则

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

GMT+8, 2024-5-19 02:21 , Processed in 0.095247 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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