运动模糊的实现有很多种方法。
一种方法是利用一块累积缓存(accumulation buffer)来混和多张连续的图像,当物体快速移动产生多张图像后,我们取最后的平均值作为最后的运动模糊图像,但是这种做法意味着在同一帧渲染多次场景,会造成很大的消耗。
另一种方法是创建和使用速度缓存(velocity buffer)这个缓存存储了各个像素当前的运动速度,利用该值决定模糊的方向和大小
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MotionBlur : PostEffectsBase
{
public Shader motionBlurShader;
private Material motionBlurMaterial = null;
public Material material
{
get
{
motionBlurMaterial = CheckShaderAndCreateMaterial(motionBlurShader, motionBlurMaterial);
return motionBlurMaterial;
}
}
//运动模糊在混合图像时使用的模糊参数
[Range(0.0f, 0.9f)]
public float blurAmount = 0.5f;
//保存之前图像叠加的效果
private RenderTexture accumulationTexture;
private void OnDisable()
{
DestroyImmediate(accumulationTexture);
}
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (material != null)
{
if (accumulationTexture == null ||
accumulationTexture.width != source.width ||
accumulationTexture.height != source.height)
{
DestroyImmediate(accumulationTexture);
accumulationTexture = new RenderTexture(source.width, source.height, 0);
//即这个变量不会显示在Hierarchy,也不会保存
accumulationTexture.hideFlags = HideFlags.HideAndDontSave;
Graphics.Blit(source, accumulationTexture);
}
//恢复操作
accumulationTexture.MarkRestoreExpected();
material.SetFloat("_BlurAmount", 1.0f - blurAmount);
Graphics.Blit(source, accumulationTexture, material);
Graphics.Blit(accumulationTexture, destination);
}
else
{
Graphics.Blit(source,destination);
}
}
}
Shader "Hidden/MotionBlur"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_BlurAmount("Blur Amount",float) = 1.0
}
SubShader
{
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed _BlurAmount;
struct v2f
{
half2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
v2f vert(appdata_img v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
fixed4 fragRGB(v2f i) : SV_Target
{
return fixed4(tex2D(_MainTex,i.uv).rgb,_BlurAmount);
}
half4 fragA(v2f i) : SV_Target
{
return tex2D(_MainTex,i.uv);
}
ENDCG
ZTest Always Cull Off ZWrite Off
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB
CGPROGRAM
#pragma vertex vert
#pragma fragment fragRGB
ENDCG
}
Pass
{
Blend One Zero
ColorMask A
CGPROGRAM
#pragma vertex vert
#pragma fragment fragA
ENDCG
}
}
Fallback Off
}