URP管线中自定义Bloom

非HDR开启bloom的效果
主要是URP作者的教程

URP管线中自定义Bloom_第1张图片

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;

partial class PostFXStack
{
    private const string bufferName = "Post FX";
    CommandBuffer buffer = new CommandBuffer()
    {
        name = bufferName
    };

    private ScriptableRenderContext context;
    private Camera camera;
    private PostFXSettings settings;

    private int fxSourceId = Shader.PropertyToID("_PostFXSource");
    private int fxSource2Id = Shader.PropertyToID("_PostFXSource2");
    private int bloomBucibicUpsamplingId = Shader.PropertyToID("_BloomBicubicUpsampling");
    private int bloomPrefilterId = Shader.PropertyToID("_BloomPrefilter");
    private int bloomThresholdId = Shader.PropertyToID("_BloomThreshold");
    private int bloomIntensityId = Shader.PropertyToID("_BloomIntensity");
    public bool IsActive => settings != null;
    private const int maxBloomPyramidLevels = 16;
    private int bloomPyramidId;
    enum Pass
    {
        // BloomPrefilter,
        // BloomCombine,
        BloomVertical,
        BloomHorizontal,
        BloomCombine,
        BloomPrefilter,
        Copy,
    }

    public PostFXStack()
    {
        bloomPyramidId = Shader.PropertyToID("_BloomPyramid0");
        for (int i = 0; i < maxBloomPyramidLevels * 2; i++)
        {
            // id的结果是 申请的顺序 +1的结果
            Shader.PropertyToID("_BloomPyramid"+i);
        }
    }


    void DoBloom(int sourceId)
    {
        buffer.BeginSample("Bloom");
        PostFXSettings.BloomSettings bloom = settings.Bloom;
        int width = camera.pixelWidth / 2, height = camera.pixelHeight / 2;
        
        Vector4 threshold;
        threshold.x = Mathf.GammaToLinearSpace(bloom.threshold);
        threshold.y = threshold.x * bloom.thresholdKnee;
        threshold.z = threshold.y * 2f;
        threshold.w = 0.25f /( threshold.y + 0.00001f);
        threshold.y -= threshold.x;
        buffer.SetGlobalVector(bloomThresholdId,threshold);
        
        
        
        RenderTextureFormat format = RenderTextureFormat.Default;
        buffer.GetTemporaryRT(bloomPrefilterId,width,height,0,FilterMode.Bilinear,format);
        Draw(sourceId,bloomPrefilterId,Pass.BloomPrefilter);
        width /= 2;
        height /= 2;
        int formId = bloomPrefilterId;
        int toId = bloomPyramidId + 1;

        int i;
        for ( i = 0; i < bloom.maxIterations; i++)
        {
            if (bloom.maxIterations == 0 || bloom.intensity <=0 || height < bloom.downscaleLimit * 2 || width < bloom.downscaleLimit * 2)
            {
                break;
            }

            int midId = toId - 1;
            buffer.GetTemporaryRT(midId,width,height,0,FilterMode.Bilinear,format);
            buffer.GetTemporaryRT(toId,width,height,0,FilterMode.Bilinear,format);
            Draw(formId, midId,Pass.BloomHorizontal);
            Draw(midId,toId,Pass.BloomVertical);
            formId = toId;
            toId += 2;
            width /= 2;
            height /= 2;
        }
        buffer.ReleaseTemporaryRT(bloomPrefilterId);
        buffer.SetGlobalFloat(bloomBucibicUpsamplingId,bloom.bicubicUpsampling ? 1f : 0f);
        buffer.SetGlobalFloat(bloomIntensityId,bloom.intensity);
        //Draw(formId,BuiltinRenderTextureType.CameraTarget,Pass.BloomHorizontal);
        if (i>1)
        {
            
        
        buffer.ReleaseTemporaryRT(formId - 1);
        toId -= 5;
        for (i -= 1; i > 0; i--)
        {
            buffer.SetGlobalTexture(fxSource2Id,toId+1);
            Draw(formId,toId,Pass.BloomCombine);
            buffer.ReleaseTemporaryRT(formId);
            buffer.ReleaseTemporaryRT(toId + 1);
            formId = toId;
            toId -= 2;
        }
        }
        else
        {
            buffer.ReleaseTemporaryRT(bloomPyramidId);
        }
        buffer.SetGlobalTexture(fxSource2Id,sourceId);
        Draw(formId,BuiltinRenderTextureType.CameraTarget,Pass.BloomCombine);
        buffer.ReleaseTemporaryRT(formId);
        buffer.EndSample("Bloom");
    }
    
    
    /// 
    /// 用来替换 buff.Blit 的函数, 比Blit 更高效
    /// 
    /// 
    /// 
    /// 
    void Draw(RenderTargetIdentifier from,RenderTargetIdentifier to, Pass pass)
    {
        buffer.SetGlobalTexture(fxSourceId,from);
        buffer.SetRenderTarget(to,RenderBufferLoadAction.DontCare,RenderBufferStoreAction.Store);
        buffer.DrawProcedural(Matrix4x4.identity, settings.Material,(int)pass,MeshTopology.Triangles,3);
    }
    public void Setup(ScriptableRenderContext context, Camera camera, PostFXSettings settings)
    {
        this.context = context;
        this.camera = camera;
        this.settings = camera.cameraType <= CameraType.SceneView ? settings : null;
        ApplySceneViewState();
    }
    
    public void Render(int sourceId)
    {
        //Draw(sourceId,BuiltinRenderTextureType.CameraTarget,Pass.Copy);
        DoBloom(sourceId);
        //buffer.Blit(sourceId,BuiltinRenderTextureType.CameraTarget);
        context.ExecuteCommandBuffer(buffer);
        buffer.Clear();
    }

    // void ApplySceneViewState()
    // {
    //     if (camera.cameraType == CameraType.SceneView && !SceneView.currentDrawingSceneView.sceneViewState.showImageEffects )
    //     {
    //         settings = null;
    //     }
    // }
    
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;

[CreateAssetMenu(menuName = "Rendering/Custom Post FX Settings")]
public class PostFXSettings : ScriptableObject
{
    [SerializeField]
    private Shader shader = default;

    [System.Serializable]
    public struct BloomSettings
    {
        [Range(0f,16f)]
        public int maxIterations;
        [FormerlySerializedAs("downscaleLimit")] [Min(1f)]
        public int downscaleLimit;
        // 是否使用三线性插值滤波
        public bool bicubicUpsampling;

        [Min(0f)]
        public float threshold;
        [Range(0f,1f)]
        public float thresholdKnee;
        [Min(0f)]
        public float intensity;
    }
    [SerializeField]
    private BloomSettings bloom = default;
    
    public BloomSettings Bloom => bloom;

    [System.NonSerialized]
    private Material material;

    public Material Material
    {
        get
        {
            if (material==null && shader != null)
            {
                material = new Material(shader);
                material.hideFlags = HideFlags.HideAndDontSave;
            }
            return material;
        }
    }
}

Shader "Hidden/CustomRP/PostFXStack"
{
    SubShader
    {
    
        Cull Off
        ZTest Always
        Zwrite Off
                    
            HLSLINCLUDE
            #include "../ShaderLibrary/Common.hlsl"
            #include "PostFXStackPasses.hlsl"
            ENDHLSL

        
        
        Pass
        {
            Name "Bloom Vertical"        
            HLSLPROGRAM
            #pragma target 3.5
            #pragma vertex DefaultPassVertex
            #pragma fragment BloomVerticalPassFragment            
            ENDHLSL
        }    
//            
        Pass
        {
            Name "Bloom Horizontal"        
            HLSLPROGRAM
            #pragma target 3.5
            #pragma vertex DefaultPassVertex
            #pragma fragment BloomHorizontalPassFragment            
            ENDHLSL
        }
        
        Pass
        {
            Name "Bloom Combine"        
            HLSLPROGRAM
            #pragma target 3.5
            #pragma vertex DefaultPassVertex
            #pragma fragment BloomCombinePassFragment            
            ENDHLSL
        }
                    
        Pass
        {
            Name "Bloom Prefilter"        
            HLSLPROGRAM
            #pragma target 3.5
            #pragma vertex DefaultPassVertex
            #pragma fragment BloomprefilterPassFragment            
            ENDHLSL
        }
        
            
        Pass
        {
            Name "Copy"        
            HLSLPROGRAM
            #pragma target 3.5
            #pragma vertex DefaultPassVertex
            #pragma fragment CopyPassFragment            
            ENDHLSL
        }
       
        
         
        
    }
}

// unity  标准输入库
#ifndef CUSTOM_POST_FX_STACE_INCLUDE 
#define CUSTOM_POST_FX_STACE_INCLUDE
#include "../../../Library/PackageCache/[email protected]/ShaderLibrary/Filtering.hlsl"
TEXTURE2D(_PostFXSource);
TEXTURE2D(_PostFXSource2);

SAMPLER(sampler_linear_clamp);
float4 _PostFXSource_TexelSize;    

bool _BloomBicubicUpsampling;
float4 _BloomThreshold;
float _BloomIntensity;

float4 GetSourceTexelSize()
{
    return _PostFXSource_TexelSize;
}



float4 GetSource(float2 screenUV)
{
    return SAMPLE_TEXTURE2D_LOD(_PostFXSource,sampler_linear_clamp,screenUV,0);
}


float4 GetSource2(float2 screenUV)
{
    return SAMPLE_TEXTURE2D_LOD(_PostFXSource2,sampler_linear_clamp,screenUV,0);
}


float4 GetSourceBicubic(float2 screenUV)
{
    return SampleTexture2DBicubic(TEXTURE2D_ARGS(_PostFXSource,sampler_linear_clamp),screenUV,_PostFXSource_TexelSize.zwxy,1.0,1.0);
}



struct Varyings
{
    float4 positionCS : SV_POSITION;
    float2 screenUV : VAR_SCREEN_UV;
};

Varyings DefaultPassVertex(uint vertexID : SV_vertexID)
{
    Varyings output;
    output.positionCS = float4(vertexID <= 1 ? -1.0 : 3.0,vertexID == 1 ? 3.0 : -1.0,0.0,1.0);
    output.screenUV = float2(vertexID <= 1 ? 0.0 : 2.0, vertexID == 1 ? 2.0 : 0.0);
    // y 值上下反转
    if(_ProjectionParams.x < 0.0)
    {
        output.screenUV.y = 1.0 - output.screenUV.y;
    }
    return output;
}

float4 CopyPassFragment(Varyings input) : SV_TARGET
{
    // 用于调试
    //return float4(input.screenUV,0.0,1.0);
    return GetSource(input.screenUV);
}

//----------------
//----------------
//----------------
//----------------



// 水平方向的模糊
float4 BloomHorizontalPassFragment(Varyings input) : SV_TARGET
{
    float3 color = 0.0;
    float offsets[] = {-4.0,-3.0,-2.0,-1.0,0.0,
                        1.0,2.0,3.0,4.0 };
    float weights[] = { 0.01621622,0.05405405,0.12162162,0.19459459, 0.22702703,
                        0.19459459,0.12162162 ,0.05405405,0.01621622};
    
   for(int i= 0; i<9; i++)
   {
    float offset = offsets[i] *2.0 * GetSourceTexelSize().x;
    color += GetSource(input.screenUV + float2(offset,0.0)).rgb * weights[i];
   }
    return float4(color,1.0);
}


//  在vertical 中可以缩减到5次, 但是在 BloomHorizontal中不能,因为已经在该pass中使用了双线性过滤
float4 BloomVerticalPassFragment(Varyings input) : SV_TARGET
{
    float3 color = 0.0;
    float offsets[] = {-3.23076923,-1.38461538, 0.0,1.38461538 ,3.23076923};
    float weights[] = { 0.07027027,0.31621622, 0.22702703,
                        0.31621622,0.07027027 };
                            
   for(int i = 0;i<5; i++)
   {
        float offset = offsets[i] * GetSourceTexelSize().y;
        color += GetSource(input.screenUV + float2(0.0,offset)).rgb * weights[i];
   }
    return float4(color,1.0);
}

float4 BloomCombinePassFragment(Varyings input):SV_TARGET
{
    float3 lowRes;
    if (_BloomBicubicUpsampling) 
    {
        lowRes = GetSourceBicubic(input.screenUV).rgb;
    }
    else
    {
        lowRes = GetSource(input.screenUV).rgb;
    }
    
    float3 hightRes = GetSource2(input.screenUV).rgb;
    return float4(lowRes * _BloomIntensity + hightRes,1.0);
}


float3 ApplyBloomThreshold(float3 color)
{
    float brightness = Max3(color.r,color.g,color.b);
    float soft = brightness + _BloomThreshold.y;
    soft = clamp(soft,0.0, _BloomThreshold.z);
    soft = soft * soft * _BloomThreshold.w;
    float contribution = max(soft,brightness - _BloomThreshold.x);
    contribution /= max(brightness,0.00001);
    return color * contribution; 
}


float4 BloomprefilterPassFragment(Varyings input):SV_TARGET
{
    float3 color = ApplyBloomThreshold(GetSource(input.screenUV).rgb);
    return float4(color,1.0);
}




#endif

工程源码在我的git中:我的git工程网址

你可能感兴趣的:(URP中Bloom,高斯模糊,自定义后处理Bloom)