摄影常用的一招就是延时摄影,以使运动的物体产生运动模糊。
摄影技巧为:1,三角架固定相机;2,调长曝光时间;3,对象有运动物体和静止物体参照
用了延时摄影,照片会产生艺术感,见下图(2015年1月 拍摄于上海陆家嘴)
游戏方面可喜的是Unity3d也可以实现类似效果,先看效果图
第一张为无运动模糊
第二张为有运动模糊:主体人物清晰,场景运动
第三张为第二张gif中的一帧
第四张为有运动模糊:摄像机不动,人物动的效果(凌波微步)
原理:
累积缓冲区:允许在渲染到颜色缓冲区之后,不是把结果显示到窗口上,而是把内容复制到累积缓冲区,这样就可以把颜色缓冲区与累积缓冲区中的内容反复进行混合,可以用来进行模糊处理和抗锯齿。
我们代码的实现是利用了一块累积缓存来混合多张连续的图像。我们不断的不当前图像叠加到之前渲染好的图像中。
shader代码
Shader "mgo/motion_blur"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_BlurSize("_BlurSize", range(0.001, 0.999)) = 0.9
}
SubShader
{
Tags{ "RenderType" = "Opaque" }
ZTest Off
cull Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
Name "Main"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex:POSITION;
float2 uv:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
uniform sampler2D _MainTex;
uniform half _BlurSize;
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 color = tex2D(_MainTex,i.uv);
//降低中心人物的运动模糊start
float r = sqrt(pow(i.uv.x-0.5,2) + pow(i.uv.y-0.6,2));
float a = _BlurSize * pow((1 - r + 0.01), 5);
if (a < 1 - _BlurSize)
{
a = 1 - _BlurSize;
}
color.a = a;
//降低中心人物的运动模糊end
//color.a = 1 - _BlurSize;
return color;
}
ENDCG
}
}
}
c#代码
using UnityEngine;
namespace GameBase.Effect
{
public class MotionBlurEffect : ImageEffectBase
{
[SerializeField]
[Range(0.001f, 0.999f)]
private float _blurSize = 0.9f;
private void OnEnable()
{
material.SetFloat("_BlurSize", _blurSize);
}
protected override void OnDisable()
{
base.OnDisable();
RenderTexture.ReleaseTemporary(_accumulationRT);
_accumulationRT = null;
}
private RenderTexture _accumulationRT;
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if(_accumulationRT == null || _accumulationRT.width != source.width || _accumulationRT.height != source.height)
{
if(_accumulationRT != null)
RenderTexture.ReleaseTemporary(_accumulationRT);
_accumulationRT = RenderTexture.GetTemporary(source.width, source.height, 0, source.format);
_accumulationRT.hideFlags = HideFlags.HideAndDontSave;
Graphics.Blit(source, _accumulationRT);
}
_accumulationRT.MarkRestoreExpected();//性能开销很大,看下官方文档
Graphics.Blit(source, _accumulationRT, material);
Graphics.Blit(_accumulationRT, destination);
}
}
}