一、运动模糊
运动模糊是一种真实世界的效果,摄像机曝光时场景发生变化,就会产生模糊的效果。
这个效果可以使物体运动看起来更平滑,,在一些赛车等等的快速运动的游戏中,这个效果的添加很常见。
运动模糊实现方法有很多种:
一种是使用累积缓存,来混和多张连续的图像,我们取得他们的平均值作为最后的运动模糊图像。但这种会很消耗性能,取得多张图像意味着我们需要在同一帧里渲染很多次场景。
另外一种是采用速度缓存,这个缓存存储了各个像素当前的运动速度,然后使用该值决定模糊的方向和大小。
摄像机代码:
using UnityEngine;
using System.Collections;
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;
//定义运动模糊参数,这个值越大运动拖尾效果越明显。为了防止拖尾效果完全替代当前帧的渲染,我们取值在0-0.9。
private RenderTexture accumulationTexture; //定义一个RenderTexture,用来保存之前图像叠加的效果
void OnDisable() { //当脚本不运行时,立即销毁,因为我们希望下一次开始应用运动模糊时重新叠加图像。
DestroyImmediate(accumulationTexture); //可能是因为在编辑器模式下可以运行,所以每当我们
}
void OnRenderImage (RenderTexture src, RenderTexture dest) {
if (material != null) {
if (accumulationTexture == null || accumulationTexture.width != src.width || accumulationTexture.height != src.height)
{
//这个 if 应该是第一次运行时才调用,之后,有相同的就不需要创建和src大小一样的了
DestroyImmediate(accumulationTexture); //判断材质是否可用
accumulationTexture = new RenderTexture(src.width, src.height, 0); //不可用重创建
accumulationTexture.hideFlags = HideFlags.HideAndDontSave; //这里设置其不会显示不会保存。
Graphics.Blit(src, accumulationTexture); //将当前帧图像初始化给accumulationTexture
}
accumulationTexture.MarkRestoreExpected(); //表明我们需要进行一个渲染纹理的恢复操作,
//恢复操作发生在渲染到纹理而该纹理又没有被提前清空或销毁的情况下。
//我们每次调用OnRenderImage时,都需要把当前帧图像和accumulationTexture混合,accumulationTexture纹理不清空因为保留着之前的混合结果。
material.SetFloat("_BlurAmount", 1.0f - blurAmount); //进行赋值
Graphics.Blit (src, accumulationTexture, material); //把每次渲染得图像都混入accumulationTexture中,
Graphics.Blit (accumulationTexture, dest);
} else {
Graphics.Blit(src, dest);
}
}
}
Shader代码:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Unity Shaders Book/Chapter 12/Motion Blur" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_BlurAmount ("Blur Amount", Float) = 1.0
//定义运动模糊参数,这个值越大运动拖尾效果越明显。为了防止拖尾效果完全替代当前帧的渲染,我们取值在0-0.9。
}
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;
}
fixed4 fragRGB (v2f i) : SV_Target { //第一个片元着色器,更新渲染纹理RGB通道
return fixed4(tex2D(_MainTex, i.uv).rgb, _BlurAmount); //将A通道的值设为_BlurAmount,意思是我们这里使用_BlurAmount,是为了后面混合时使用的。
}
half4 fragA (v2f i) : SV_Target { //第二个片元着色器,更新渲染纹理A通道
return tex2D(_MainTex, i.uv);
}
ENDCG
ZTest Always Cull Off ZWrite Off
//我们使用两个Pass是因为在更新RGB时我们需要设置它的A通道来混和图像,但又不希望A通道的值写入渲染纹理
Pass { //同样两个Pass,分别更新RGB和A
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB //只渲染RGB
CGPROGRAM
#pragma vertex vert
#pragma fragment fragRGB
ENDCG
}
Pass {
Blend One Zero
ColorMask A //只渲染A
CGPROGRAM
#pragma vertex vert
#pragma fragment fragA
ENDCG
}
}
FallBack Off
}