修改自这篇文章【Unity】UniversalRPでカスタムポストプロセスを作る【ZoomBlur】 - Qiita
1. VolumeEditor,用于在UnityVolume中控制自己写的后处理效果
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;[System.Serializable, VolumeComponentMenu("Dejavu/ZoomBlur")]
public class ZoomBlurVolume : VolumeComponent, IPostProcessComponent
{[Range(0f, 100f), Tooltip("强度")]public FloatParameter focusPower = new FloatParameter(0f);[Range(0, 10), Tooltip("模糊层数")]public IntParameter focusDetail = new IntParameter(5);[Tooltip("聚焦焦点")]public Vector2Parameter focusScreenPosition = new Vector2Parameter(Vector2.zero);public bool IsActive() => focusPower.value > 0f;public bool IsTileCompatible() => false;
}
2. RenderFeature和RenderPass
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;public class ZoomBlurRenderFeature : ScriptableRendererFeature
{ZoomBlurPass zoomBlurPass;public override void Create(){zoomBlurPass = new ZoomBlurPass(RenderPassEvent.BeforeRenderingPostProcessing);}public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){zoomBlurPass.Setup(renderer.cameraColorTarget);renderer.EnqueuePass(zoomBlurPass);}
}public class ZoomBlurPass : ScriptableRenderPass
{static readonly string k_RenderTag = "Render ZoomBlur Effects";static readonly int MainTexId = Shader.PropertyToID("_MainTex");static readonly int TempTargetId = Shader.PropertyToID("_TempTargetZoomBlur");static readonly int FocusPowerId = Shader.PropertyToID("_FocusPower");static readonly int FocusDetailId = Shader.PropertyToID("_FocusDetail");static readonly int FocusScreenPositionId = Shader.PropertyToID("_FocusScreenPosition");ZoomBlurVolume zoomBlur;Material zoomBlurMaterial;RenderTargetIdentifier currentTarget;public ZoomBlurPass(RenderPassEvent evt){renderPassEvent = evt;var shader = Shader.Find("PostEffect/ZoomBlur");if (shader == null){Debug.LogError("Shader not found.");return;}zoomBlurMaterial = CoreUtils.CreateEngineMaterial(shader);}public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){if (zoomBlurMaterial == null){Debug.LogError("Material not created.");return;}if (!renderingData.cameraData.postProcessEnabled) return;var stack = VolumeManager.instance.stack;zoomBlur = stack.GetComponent<ZoomBlurVolume >();if (zoomBlur == null) { return; }if (!zoomBlur.IsActive()) { return; }var cmd = CommandBufferPool.Get(k_RenderTag);Render(cmd, ref renderingData);context.ExecuteCommandBuffer(cmd);CommandBufferPool.Release(cmd);}public void Setup(in RenderTargetIdentifier currentTarget){this.currentTarget = currentTarget;}void Render(CommandBuffer cmd, ref RenderingData renderingData){ref var cameraData = ref renderingData.cameraData;var source = currentTarget;int destination = TempTargetId;var w = cameraData.camera.scaledPixelWidth;var h = cameraData.camera.scaledPixelHeight;zoomBlurMaterial.SetFloat(FocusPowerId, zoomBlur.focusPower.value);zoomBlurMaterial.SetInt(FocusDetailId, zoomBlur.focusDetail.value);zoomBlurMaterial.SetVector(FocusScreenPositionId, zoomBlur.focusScreenPosition.value);int shaderPass = 0;cmd.SetGlobalTexture(MainTexId, source);cmd.GetTemporaryRT(destination, w, h, 0, FilterMode.Point, RenderTextureFormat.Default);cmd.Blit(source, destination);cmd.Blit(destination, source, zoomBlurMaterial, shaderPass);}
}
3.Shader
Shader "PostEffect/ZoomBlur"
{Properties{_MainTex("Texture", 2D) = "white" {}}SubShader{Cull Off ZWrite Off ZTest AlwaysTags { "RenderPipeline" = "UniversalPipeline"}Pass{CGPROGRAM#pragma vertex Vert#pragma fragment Fragsampler2D _MainTex;float2 _FocusScreenPosition;float _FocusPower;int _FocusDetail;int _ReferenceResolutionX;struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};v2f Vert(appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}float4 Frag(v2f i) : SV_Target{//_FocusScreenPosition 范围是(-width/2,-height/2) 到( width/2, height/2) ,(0,0)变换到屏幕中心为(_ScreenParams.xy / 2)float2 focusPos = _FocusScreenPosition + _ScreenParams.xy / 2;float2 uv = i.uv;//根据屏幕坐标计算UVfloat2 focusPosUV = (focusPos / _ScreenParams.xy);//计算像素点距离中心焦点的UV差,以中心点乘系数外扩uv = uv - focusPosUV;float4 outColor = float4(0, 0, 0, 1);//多层模糊for (int i = 0; i < _FocusDetail; i++) {//计算模糊的强度,也就是UV的偏移强度float power = 1.0 - _FocusPower/1000 * float(i);//以中心点乘系数外扩outColor.rgb += tex2D(_MainTex , uv * power + focusPosUV).rgb;}outColor.rgb *= 1.0 / float(_FocusDetail);return outColor;}ENDCG}}
}
工程示例链接:git@github.com:Dejavu0709/StudyForShader.git 中的ZoomBlure文件夹