非HDR开启bloom的效果
主要是URP作者的教程
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");}/// <summary>/// 用来替换 buff.Blit 的函数, 比Blit 更高效/// </summary>/// <param name="from"></param>/// <param name="to"></param>/// <param name="pass"></param>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 OffZTest AlwaysZwrite OffHLSLINCLUDE#include "../ShaderLibrary/Common.hlsl"#include "PostFXStackPasses.hlsl"ENDHLSLPass{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/com.unity.render-pipelines.core@10.3.2/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工程网址