ainatipen 发表于 2022-7-14 12:29

unity urp 17 Bloom效果

一、思路

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
    {
      _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
{
    //定义配置类
   
    public class Setting
    {
      //默认在透明物体绘制完成后进行处理
      public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;
      //后续需要用到的材质
      public Material mat;
       public int iterations = 3;
       public float blurSpread = 0.6f;
       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效果不太理想。
页: [1]
查看完整版本: unity urp 17 Bloom效果