实现运动模糊的方法:累计缓存和速度缓存。
accumulation buffer:物体快速移动产生多张连续图像,取他们平均值作为最后的运动模糊图像。
cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveBlurCS : PostEffectsBase
{
public Shader motionBlurShader;
private Material motionBlurMaterial;
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);
}
private 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;
//将当前帧导入到纹理中
//Blit 将 accumulationTexture 设置为渲染目标,在材质上设置 source _MainTex 属性, 并绘制全屏四边形
Graphics.Blit(source, accumulationTexture);
}
//混合图像参与混合后又会重新恢复
accumulationTexture.MarkRestoreExpected();
//将混合参数传入shader中
//上一帧的比例为blurAmount
//这一帧的比例就时1-blurAmount了
material.SetFloat("_BlurAmount", 1.0f - blurAmount);
//当前帧进行pass处理,混合进混合图像后,将结果输出进混合图像
//如果继续进行运动,上一帧就是我们上一帧的混合图像。
//所以运动越持久,混合越多
//上上上帧的比例会不断减少
Graphics.Blit(source, accumulationTexture, material);
//导出混合图像
Graphics.Blit(accumulationTexture, destination);
}
else
{
Graphics.Blit(source, destination);
}
}
}
shader:
Shader "Custom/MoveBlurShader"
{
Properties
{
_MainTex("Main Tex",2D) = "white"{}
_BlurAmount("Blur Amount",Float) = 1.0
}
SubShader
{
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed _BlurAmount;
struct v2f
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
};
v2f vert(appdata_img v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
//RGB就是RGB的值,A通道是_BlurAmount
//混合时通过A通道混合
fixed4 fragRGB(v2f i) : SV_Target
{
return fixed4(tex2D(_MainTex,i.uv).rgb,_BlurAmount);
}
//事实上只输出透明度Alpha值
half4 fragA(v2f i) : SV_Target
{
return tex2D(_MainTex, i.uv);
}
ENDCG
ZTest Always Cull Off ZWrite Off
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
对此通道启用仅写入 RGB 通道,这会禁用向 Alpha 通道写入
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
}