?修改自这篇文章【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 Always
Tags { "RenderPipeline" = "UniversalPipeline"}
Pass
{
CGPROGRAM
#pragma vertex Vert
#pragma fragment Frag
sampler2D _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;
//根据屏幕坐标计算UV
float2 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文件夹
|