- CameraMotionBlur.cs
- Scripts /
- ImageEffects /
- Effects /
- Standard Assets /
- Assets /
- project /
1 using System;
2 using UnityEngine;
3
4 namespace UnityStandardAssets.ImageEffects
5 {
6 [ExecuteInEditMode]
7 [RequireComponent (typeof(Camera))]
8 [AddComponentMenu ("Image Effects/Camera/Camera Motion Blur") ]
9 public class CameraMotionBlur : PostEffectsBase
10 {
11 // make sure to match this to MAX_RADIUS in shader ('k' in paper)
12 static float MAX_RADIUS = 10.0f;
13
14 public enum MotionBlurFilter {
15 CameraMotion = 0, // global screen blur based on cam motion
16 LocalBlur = 1, // cheap blur, no dilation or scattering
17 Reconstruction = 2, // advanced filter (simulates scattering) as in plausible motion blur paper
18 ReconstructionDX11 = 3, // advanced filter (simulates scattering) as in plausible motion blur paper
19 ReconstructionDisc = 4, // advanced filter using scaled poisson disc sampling
20 }
21
22 // settings
23 public MotionBlurFilter filterType = MotionBlurFilter.Reconstruction;
24 public bool preview = false; // show how blur would look like in action ...
25 public Vector3 previewScale = Vector3.one; // ... given this movement vector
26
27 // params
28 public float movementScale = 0.0f;
29 public float rotationScale = 1.0f;
30 public float maxVelocity = 8.0f; // maximum velocity in pixels
31 public float minVelocity = 0.1f; // minimum velocity in pixels
32 public float velocityScale = 0.375f; // global velocity scale
33 public float softZDistance = 0.005f; // for z overlap check softness (reconstruction filter only)
34 public int velocityDownsample = 1; // low resolution velocity buffer? (optimization)
35 public LayerMask excludeLayers = 0;
36 private GameObject tmpCam = null;
37
38 // resources
39 public Shader shader;
40 public Shader dx11MotionBlurShader;
41 public Shader replacementClear;
42
43 private Material motionBlurMaterial = null;
44 private Material dx11MotionBlurMaterial = null;
45
46 public Texture2D noiseTexture = null;
47 public float jitter = 0.05f;
48
49 // (internal) debug
50 public bool showVelocity = false;
51 public float showVelocityScale = 1.0f;
52
53 // camera transforms
54 private Matrix4x4 currentViewProjMat;
55 private Matrix4x4 prevViewProjMat;
56 private int prevFrameCount;
57 private bool wasActive;
58 // shortcuts to calculate global blur direction when using 'CameraMotion'
59 private Vector3 prevFrameForward = Vector3.forward;
60 private Vector3 prevFrameUp = Vector3.up;
61 private Vector3 prevFramePos = Vector3.zero;
62 private Camera _camera;
63
64
65 private void CalculateViewProjection () {
66 Matrix4x4 viewMat = _camera.worldToCameraMatrix;
67 Matrix4x4 projMat = GL.GetGPUProjectionMatrix (_camera.projectionMatrix, true);
68 currentViewProjMat = projMat * viewMat;
69 }
70
71
72 new void Start () {
73 CheckResources ();
74
75 if (_camera == null)
76 _camera = GetComponent<Camera>();
77
78 wasActive = gameObject.activeInHierarchy;
79 CalculateViewProjection ();
80 Remember ();
81 wasActive = false; // hack to fake position/rotation update and prevent bad blurs
82 }
83
84 void OnEnable () {
85
86 if (_camera == null)
87 _camera = GetComponent<Camera>();
88
89 _camera.depthTextureMode |= DepthTextureMode.Depth;
90 }
91
92 void OnDisable () {
93 if (null != motionBlurMaterial) {
94 DestroyImmediate (motionBlurMaterial);
95 motionBlurMaterial = null;
96 }
97 if (null != dx11MotionBlurMaterial) {
98 DestroyImmediate (dx11MotionBlurMaterial);
99 dx11MotionBlurMaterial = null;
100 }
101 if (null != tmpCam) {
102 DestroyImmediate (tmpCam);
103 tmpCam = null;
104 }
105 }
106
107
108 public override bool CheckResources () {
109 CheckSupport (true, true); // depth & hdr needed
110 motionBlurMaterial = CheckShaderAndCreateMaterial (shader, motionBlurMaterial);
111
112 if (supportDX11 && filterType == MotionBlurFilter.ReconstructionDX11) {
113 dx11MotionBlurMaterial = CheckShaderAndCreateMaterial (dx11MotionBlurShader, dx11MotionBlurMaterial);
114 }
115
116 if (!isSupported)
117 ReportAutoDisable ();
118
119 return isSupported;
120 }
121
122 void OnRenderImage (RenderTexture source, RenderTexture destination) {
123 if (false == CheckResources ()) {
124 Graphics.Blit (source, destination);
125 return;
126 }
127
128 if (filterType == MotionBlurFilter.CameraMotion)
129 StartFrame ();
130
131 // use if possible new RG format ... fallback to half otherwise
132 var rtFormat= SystemInfo.SupportsRenderTextureFormat (RenderTextureFormat.RGHalf) ? RenderTextureFormat.RGHalf : RenderTextureFormat.ARGBHalf;
133
134 // get temp textures
135 RenderTexture velBuffer = RenderTexture.GetTemporary (divRoundUp (source.width, velocityDownsample), divRoundUp (source.height, velocityDownsample), 0, rtFormat);
136 int tileWidth = 1;
137 int tileHeight = 1;
138 maxVelocity = Mathf.Max (2.0f, maxVelocity);
139
140 float _maxVelocity = maxVelocity; // calculate 'k'
141 // note: 's' is hardcoded in shaders except for DX11 path
142
143 // auto DX11 fallback!
144 bool fallbackFromDX11 = filterType == MotionBlurFilter.ReconstructionDX11 && dx11MotionBlurMaterial == null;
145
146 if (filterType == MotionBlurFilter.Reconstruction || fallbackFromDX11 || filterType == MotionBlurFilter.ReconstructionDisc) {
147 maxVelocity = Mathf.Min (maxVelocity, MAX_RADIUS);
148 tileWidth = divRoundUp (velBuffer.width, (int) maxVelocity);
149 tileHeight = divRoundUp (velBuffer.height, (int) maxVelocity);
150 _maxVelocity = velBuffer.width/tileWidth;
151 }
152 else {
153 tileWidth = divRoundUp (velBuffer.width, (int) maxVelocity);
154 tileHeight = divRoundUp (velBuffer.height, (int) maxVelocity);
155 _maxVelocity = velBuffer.width/tileWidth;
156 }
157
158 RenderTexture tileMax = RenderTexture.GetTemporary (tileWidth, tileHeight, 0, rtFormat);
159 RenderTexture neighbourMax = RenderTexture.GetTemporary (tileWidth, tileHeight, 0, rtFormat);
160 velBuffer.filterMode = FilterMode.Point;
161 tileMax.filterMode = FilterMode.Point;
162 neighbourMax.filterMode = FilterMode.Point;
163 if (noiseTexture) noiseTexture.filterMode = FilterMode.Point;
164 source.wrapMode = TextureWrapMode.Clamp;
165 velBuffer.wrapMode = TextureWrapMode.Clamp;
166 neighbourMax.wrapMode = TextureWrapMode.Clamp;
167 tileMax.wrapMode = TextureWrapMode.Clamp;
168
169 // calc correct viewprj matrix
170 CalculateViewProjection ();
171
172 // just started up?
173 if (gameObject.activeInHierarchy && !wasActive) {
174 Remember ();
175 }
176 wasActive = gameObject.activeInHierarchy;
177
178 // matrices
179 Matrix4x4 invViewPrj = Matrix4x4.Inverse (currentViewProjMat);
180 motionBlurMaterial.SetMatrix ("_InvViewProj", invViewPrj);
181 motionBlurMaterial.SetMatrix ("_PrevViewProj", prevViewProjMat);
182 motionBlurMaterial.SetMatrix ("_ToPrevViewProjCombined", prevViewProjMat * invViewPrj);
183
184 motionBlurMaterial.SetFloat ("_MaxVelocity", _maxVelocity);
185 motionBlurMaterial.SetFloat ("_MaxRadiusOrKInPaper", _maxVelocity);
186 motionBlurMaterial.SetFloat ("_MinVelocity", minVelocity);
187 motionBlurMaterial.SetFloat ("_VelocityScale", velocityScale);
188 motionBlurMaterial.SetFloat ("_Jitter", jitter);
189
190 // texture samplers
191 motionBlurMaterial.SetTexture ("_NoiseTex", noiseTexture);
192 motionBlurMaterial.SetTexture ("_VelTex", velBuffer);
193 motionBlurMaterial.SetTexture ("_NeighbourMaxTex", neighbourMax);
194 motionBlurMaterial.SetTexture ("_TileTexDebug", tileMax);
195
196 if (preview) {
197 // generate an artifical 'previous' matrix to simulate blur look
198 Matrix4x4 viewMat = _camera.worldToCameraMatrix;
199 Matrix4x4 offset = Matrix4x4.identity;
200 offset.SetTRS(previewScale * 0.3333f, Quaternion.identity, Vector3.one); // using only translation
201 Matrix4x4 projMat = GL.GetGPUProjectionMatrix (_camera.projectionMatrix, true);
202 prevViewProjMat = projMat * offset * viewMat;
203 motionBlurMaterial.SetMatrix ("_PrevViewProj", prevViewProjMat);
204 motionBlurMaterial.SetMatrix ("_ToPrevViewProjCombined", prevViewProjMat * invViewPrj);
205 }
206
207 if (filterType == MotionBlurFilter.CameraMotion)
208 {
209 // build blur vector to be used in shader to create a global blur direction
210 Vector4 blurVector = Vector4.zero;
211
212 float lookUpDown = Vector3.Dot (transform.up, Vector3.up);
213 Vector3 distanceVector = prevFramePos-transform.position;
214
215 float distMag = distanceVector.magnitude;
216
217 float farHeur = 1.0f;
218
219 // pitch (vertical)
220 farHeur = (Vector3.Angle (transform.up, prevFrameUp) / _camera.fieldOfView) * (source.width * 0.75f);
221 blurVector.x = rotationScale * farHeur;//Mathf.Clamp01((1.0ff-Vector3.Dot(transform.up, prevFrameUp)));
222
223 // yaw #1 (horizontal, faded by pitch)
224 farHeur = (Vector3.Angle (transform.forward, prevFrameForward) / _camera.fieldOfView) * (source.width * 0.75f);
225 blurVector.y = rotationScale * lookUpDown * farHeur;//Mathf.Clamp01((1.0ff-Vector3.Dot(transform.forward, prevFrameForward)));
226
227 // yaw #2 (when looking down, faded by 1-pitch)
228 farHeur = (Vector3.Angle (transform.forward, prevFrameForward) / _camera.fieldOfView) * (source.width * 0.75f);
229 blurVector.z = rotationScale * (1.0f- lookUpDown) * farHeur;//Mathf.Clamp01((1.0ff-Vector3.Dot(transform.forward, prevFrameForward)));
230
231 if (distMag > Mathf.Epsilon && movementScale > Mathf.Epsilon) {
232 // forward (probably most important)
233 blurVector.w = movementScale * (Vector3.Dot (transform.forward, distanceVector) ) * (source.width * 0.5f);
234 // jump (maybe scale down further)
235 blurVector.x += movementScale * (Vector3.Dot (transform.up, distanceVector) ) * (source.width * 0.5f);
236 // strafe (maybe scale down further)
237 blurVector.y += movementScale * (Vector3.Dot (transform.right, distanceVector) ) * (source.width * 0.5f);
238 }
239
240 if (preview) // crude approximation
241 motionBlurMaterial.SetVector ("_BlurDirectionPacked", new Vector4 (previewScale.y, previewScale.x, 0.0f, previewScale.z) * 0.5f * _camera.fieldOfView);
242 else
243 motionBlurMaterial.SetVector ("_BlurDirectionPacked", blurVector);
244 }
245 else {
246 // generate velocity buffer
247 Graphics.Blit (source, velBuffer, motionBlurMaterial, 0);
248
249 // patch up velocity buffer:
250
251 // exclude certain layers (e.g. skinned objects as we cant really support that atm)
252
253 Camera cam = null;
254 if (excludeLayers.value != 0)// || dynamicLayers.value)
255 cam = GetTmpCam ();
256
257 if (cam && excludeLayers.value != 0 && replacementClear && replacementClear.isSupported) {
258 cam.targetTexture = velBuffer;
259 cam.cullingMask = excludeLayers;
260 cam.RenderWithShader (replacementClear, "");
261 }
262 }
263
264 if (!preview && Time.frameCount != prevFrameCount) {
265 // remember current transformation data for next frame
266 prevFrameCount = Time.frameCount;
267 Remember ();
268 }
269
270 source.filterMode = FilterMode.Bilinear;
271
272 // debug vel buffer:
273 if (showVelocity) {
274 // generate tile max and neighbour max
275 //Graphics.Blit (velBuffer, tileMax, motionBlurMaterial, 2);
276 //Graphics.Blit (tileMax, neighbourMax, motionBlurMaterial, 3);
277 motionBlurMaterial.SetFloat ("_DisplayVelocityScale", showVelocityScale);
278 Graphics.Blit (velBuffer, destination, motionBlurMaterial, 1);
279 }
280 else {
281 if (filterType == MotionBlurFilter.ReconstructionDX11 && !fallbackFromDX11) {
282 // need to reset some parameters for dx11 shader
283 dx11MotionBlurMaterial.SetFloat ("_MinVelocity", minVelocity);
284 dx11MotionBlurMaterial.SetFloat ("_VelocityScale", velocityScale);
285 dx11MotionBlurMaterial.SetFloat ("_Jitter", jitter);
286
287 // texture samplers
288 dx11MotionBlurMaterial.SetTexture ("_NoiseTex", noiseTexture);
289 dx11MotionBlurMaterial.SetTexture ("_VelTex", velBuffer);
290 dx11MotionBlurMaterial.SetTexture ("_NeighbourMaxTex", neighbourMax);
291
292 dx11MotionBlurMaterial.SetFloat ("_SoftZDistance", Mathf.Max(0.00025f, softZDistance) );
293 dx11MotionBlurMaterial.SetFloat ("_MaxRadiusOrKInPaper", _maxVelocity);
294
295 // generate tile max and neighbour max
296 Graphics.Blit (velBuffer, tileMax, dx11MotionBlurMaterial, 0);
297 Graphics.Blit (tileMax, neighbourMax, dx11MotionBlurMaterial, 1);
298
299 // final blur
300 Graphics.Blit (source, destination, dx11MotionBlurMaterial, 2);
301 }
302 else if (filterType == MotionBlurFilter.Reconstruction || fallbackFromDX11) {
303 // 'reconstructing' properly integrated color
304 motionBlurMaterial.SetFloat ("_SoftZDistance", Mathf.Max(0.00025f, softZDistance) );
305
306 // generate tile max and neighbour max
307 Graphics.Blit (velBuffer, tileMax, motionBlurMaterial, 2);
308 Graphics.Blit (tileMax, neighbourMax, motionBlurMaterial, 3);
309
310 // final blur
311 Graphics.Blit (source, destination, motionBlurMaterial, 4);
312 }
313 else if (filterType == MotionBlurFilter.CameraMotion) {
314 // orange box style motion blur
315 Graphics.Blit (source, destination, motionBlurMaterial, 6);
316 }
317 else if (filterType == MotionBlurFilter.ReconstructionDisc) {
318 // dof style motion blur defocuing and ellipse around the princical blur direction
319 // 'reconstructing' properly integrated color
320 motionBlurMaterial.SetFloat ("_SoftZDistance", Mathf.Max(0.00025f, softZDistance) );
321
322 // generate tile max and neighbour max
323 Graphics.Blit (velBuffer, tileMax, motionBlurMaterial, 2);
324 Graphics.Blit (tileMax, neighbourMax, motionBlurMaterial, 3);
325
326 Graphics.Blit (source, destination, motionBlurMaterial, 7);
327 }
328 else {
329 // simple & fast blur (low quality): just blurring along velocity
330 Graphics.Blit (source, destination, motionBlurMaterial, 5);
331 }
332 }
333
334 // cleanup
335 RenderTexture.ReleaseTemporary (velBuffer);
336 RenderTexture.ReleaseTemporary (tileMax);
337 RenderTexture.ReleaseTemporary (neighbourMax);
338 }
339
340 void Remember () {
341 prevViewProjMat = currentViewProjMat;
342 prevFrameForward = transform.forward;
343 prevFrameUp = transform.up;
344 prevFramePos = transform.position;
345 }
346
347 Camera GetTmpCam () {
348 if (tmpCam == null) {
349 string name = "_" + _camera.name + "_MotionBlurTmpCam";
350 GameObject go = GameObject.Find (name);
351 if (null == go) // couldn't find, recreate
352 tmpCam = new GameObject (name, typeof (Camera));
353 else
354 tmpCam = go;
355 }
356
357 tmpCam.hideFlags = HideFlags.DontSave;
358 tmpCam.transform.position = _camera.transform.position;
359 tmpCam.transform.rotation = _camera.transform.rotation;
360 tmpCam.transform.localScale = _camera.transform.localScale;
361 tmpCam.GetComponent<Camera>().CopyFrom(_camera);
362
363 tmpCam.GetComponent<Camera>().enabled = false;
364 tmpCam.GetComponent<Camera>().depthTextureMode = DepthTextureMode.None;
365 tmpCam.GetComponent<Camera>().clearFlags = CameraClearFlags.Nothing;
366
367 return tmpCam.GetComponent<Camera>();
368 }
369
370 void StartFrame () {
371 // take only x% of positional changes into account (camera motion)
372 // TODO: possibly do the same for rotational part
373 prevFramePos = Vector3.Slerp(prevFramePos, transform.position, 0.75f);
374 }
375
376 static int divRoundUp (int x, int d)
377 {
378 return (x + d - 1) / d;
379 }
380 }
381 }
2 using UnityEngine;
3
4 namespace UnityStandardAssets.ImageEffects
5 {
6 [ExecuteInEditMode]
7 [RequireComponent (typeof(Camera))]
8 [AddComponentMenu ("Image Effects/Camera/Camera Motion Blur") ]
9 public class CameraMotionBlur : PostEffectsBase
10 {
11 // make sure to match this to MAX_RADIUS in shader ('k' in paper)
12 static float MAX_RADIUS = 10.0f;
13
14 public enum MotionBlurFilter {
15 CameraMotion = 0, // global screen blur based on cam motion
16 LocalBlur = 1, // cheap blur, no dilation or scattering
17 Reconstruction = 2, // advanced filter (simulates scattering) as in plausible motion blur paper
18 ReconstructionDX11 = 3, // advanced filter (simulates scattering) as in plausible motion blur paper
19 ReconstructionDisc = 4, // advanced filter using scaled poisson disc sampling
20 }
21
22 // settings
23 public MotionBlurFilter filterType = MotionBlurFilter.Reconstruction;
24 public bool preview = false; // show how blur would look like in action ...
25 public Vector3 previewScale = Vector3.one; // ... given this movement vector
26
27 // params
28 public float movementScale = 0.0f;
29 public float rotationScale = 1.0f;
30 public float maxVelocity = 8.0f; // maximum velocity in pixels
31 public float minVelocity = 0.1f; // minimum velocity in pixels
32 public float velocityScale = 0.375f; // global velocity scale
33 public float softZDistance = 0.005f; // for z overlap check softness (reconstruction filter only)
34 public int velocityDownsample = 1; // low resolution velocity buffer? (optimization)
35 public LayerMask excludeLayers = 0;
36 private GameObject tmpCam = null;
37
38 // resources
39 public Shader shader;
40 public Shader dx11MotionBlurShader;
41 public Shader replacementClear;
42
43 private Material motionBlurMaterial = null;
44 private Material dx11MotionBlurMaterial = null;
45
46 public Texture2D noiseTexture = null;
47 public float jitter = 0.05f;
48
49 // (internal) debug
50 public bool showVelocity = false;
51 public float showVelocityScale = 1.0f;
52
53 // camera transforms
54 private Matrix4x4 currentViewProjMat;
55 private Matrix4x4 prevViewProjMat;
56 private int prevFrameCount;
57 private bool wasActive;
58 // shortcuts to calculate global blur direction when using 'CameraMotion'
59 private Vector3 prevFrameForward = Vector3.forward;
60 private Vector3 prevFrameUp = Vector3.up;
61 private Vector3 prevFramePos = Vector3.zero;
62 private Camera _camera;
63
64
65 private void CalculateViewProjection () {
66 Matrix4x4 viewMat = _camera.worldToCameraMatrix;
67 Matrix4x4 projMat = GL.GetGPUProjectionMatrix (_camera.projectionMatrix, true);
68 currentViewProjMat = projMat * viewMat;
69 }
70
71
72 new void Start () {
73 CheckResources ();
74
75 if (_camera == null)
76 _camera = GetComponent<Camera>();
77
78 wasActive = gameObject.activeInHierarchy;
79 CalculateViewProjection ();
80 Remember ();
81 wasActive = false; // hack to fake position/rotation update and prevent bad blurs
82 }
83
84 void OnEnable () {
85
86 if (_camera == null)
87 _camera = GetComponent<Camera>();
88
89 _camera.depthTextureMode |= DepthTextureMode.Depth;
90 }
91
92 void OnDisable () {
93 if (null != motionBlurMaterial) {
94 DestroyImmediate (motionBlurMaterial);
95 motionBlurMaterial = null;
96 }
97 if (null != dx11MotionBlurMaterial) {
98 DestroyImmediate (dx11MotionBlurMaterial);
99 dx11MotionBlurMaterial = null;
100 }
101 if (null != tmpCam) {
102 DestroyImmediate (tmpCam);
103 tmpCam = null;
104 }
105 }
106
107
108 public override bool CheckResources () {
109 CheckSupport (true, true); // depth & hdr needed
110 motionBlurMaterial = CheckShaderAndCreateMaterial (shader, motionBlurMaterial);
111
112 if (supportDX11 && filterType == MotionBlurFilter.ReconstructionDX11) {
113 dx11MotionBlurMaterial = CheckShaderAndCreateMaterial (dx11MotionBlurShader, dx11MotionBlurMaterial);
114 }
115
116 if (!isSupported)
117 ReportAutoDisable ();
118
119 return isSupported;
120 }
121
122 void OnRenderImage (RenderTexture source, RenderTexture destination) {
123 if (false == CheckResources ()) {
124 Graphics.Blit (source, destination);
125 return;
126 }
127
128 if (filterType == MotionBlurFilter.CameraMotion)
129 StartFrame ();
130
131 // use if possible new RG format ... fallback to half otherwise
132 var rtFormat= SystemInfo.SupportsRenderTextureFormat (RenderTextureFormat.RGHalf) ? RenderTextureFormat.RGHalf : RenderTextureFormat.ARGBHalf;
133
134 // get temp textures
135 RenderTexture velBuffer = RenderTexture.GetTemporary (divRoundUp (source.width, velocityDownsample), divRoundUp (source.height, velocityDownsample), 0, rtFormat);
136 int tileWidth = 1;
137 int tileHeight = 1;
138 maxVelocity = Mathf.Max (2.0f, maxVelocity);
139
140 float _maxVelocity = maxVelocity; // calculate 'k'
141 // note: 's' is hardcoded in shaders except for DX11 path
142
143 // auto DX11 fallback!
144 bool fallbackFromDX11 = filterType == MotionBlurFilter.ReconstructionDX11 && dx11MotionBlurMaterial == null;
145
146 if (filterType == MotionBlurFilter.Reconstruction || fallbackFromDX11 || filterType == MotionBlurFilter.ReconstructionDisc) {
147 maxVelocity = Mathf.Min (maxVelocity, MAX_RADIUS);
148 tileWidth = divRoundUp (velBuffer.width, (int) maxVelocity);
149 tileHeight = divRoundUp (velBuffer.height, (int) maxVelocity);
150 _maxVelocity = velBuffer.width/tileWidth;
151 }
152 else {
153 tileWidth = divRoundUp (velBuffer.width, (int) maxVelocity);
154 tileHeight = divRoundUp (velBuffer.height, (int) maxVelocity);
155 _maxVelocity = velBuffer.width/tileWidth;
156 }
157
158 RenderTexture tileMax = RenderTexture.GetTemporary (tileWidth, tileHeight, 0, rtFormat);
159 RenderTexture neighbourMax = RenderTexture.GetTemporary (tileWidth, tileHeight, 0, rtFormat);
160 velBuffer.filterMode = FilterMode.Point;
161 tileMax.filterMode = FilterMode.Point;
162 neighbourMax.filterMode = FilterMode.Point;
163 if (noiseTexture) noiseTexture.filterMode = FilterMode.Point;
164 source.wrapMode = TextureWrapMode.Clamp;
165 velBuffer.wrapMode = TextureWrapMode.Clamp;
166 neighbourMax.wrapMode = TextureWrapMode.Clamp;
167 tileMax.wrapMode = TextureWrapMode.Clamp;
168
169 // calc correct viewprj matrix
170 CalculateViewProjection ();
171
172 // just started up?
173 if (gameObject.activeInHierarchy && !wasActive) {
174 Remember ();
175 }
176 wasActive = gameObject.activeInHierarchy;
177
178 // matrices
179 Matrix4x4 invViewPrj = Matrix4x4.Inverse (currentViewProjMat);
180 motionBlurMaterial.SetMatrix ("_InvViewProj", invViewPrj);
181 motionBlurMaterial.SetMatrix ("_PrevViewProj", prevViewProjMat);
182 motionBlurMaterial.SetMatrix ("_ToPrevViewProjCombined", prevViewProjMat * invViewPrj);
183
184 motionBlurMaterial.SetFloat ("_MaxVelocity", _maxVelocity);
185 motionBlurMaterial.SetFloat ("_MaxRadiusOrKInPaper", _maxVelocity);
186 motionBlurMaterial.SetFloat ("_MinVelocity", minVelocity);
187 motionBlurMaterial.SetFloat ("_VelocityScale", velocityScale);
188 motionBlurMaterial.SetFloat ("_Jitter", jitter);
189
190 // texture samplers
191 motionBlurMaterial.SetTexture ("_NoiseTex", noiseTexture);
192 motionBlurMaterial.SetTexture ("_VelTex", velBuffer);
193 motionBlurMaterial.SetTexture ("_NeighbourMaxTex", neighbourMax);
194 motionBlurMaterial.SetTexture ("_TileTexDebug", tileMax);
195
196 if (preview) {
197 // generate an artifical 'previous' matrix to simulate blur look
198 Matrix4x4 viewMat = _camera.worldToCameraMatrix;
199 Matrix4x4 offset = Matrix4x4.identity;
200 offset.SetTRS(previewScale * 0.3333f, Quaternion.identity, Vector3.one); // using only translation
201 Matrix4x4 projMat = GL.GetGPUProjectionMatrix (_camera.projectionMatrix, true);
202 prevViewProjMat = projMat * offset * viewMat;
203 motionBlurMaterial.SetMatrix ("_PrevViewProj", prevViewProjMat);
204 motionBlurMaterial.SetMatrix ("_ToPrevViewProjCombined", prevViewProjMat * invViewPrj);
205 }
206
207 if (filterType == MotionBlurFilter.CameraMotion)
208 {
209 // build blur vector to be used in shader to create a global blur direction
210 Vector4 blurVector = Vector4.zero;
211
212 float lookUpDown = Vector3.Dot (transform.up, Vector3.up);
213 Vector3 distanceVector = prevFramePos-transform.position;
214
215 float distMag = distanceVector.magnitude;
216
217 float farHeur = 1.0f;
218
219 // pitch (vertical)
220 farHeur = (Vector3.Angle (transform.up, prevFrameUp) / _camera.fieldOfView) * (source.width * 0.75f);
221 blurVector.x = rotationScale * farHeur;//Mathf.Clamp01((1.0ff-Vector3.Dot(transform.up, prevFrameUp)));
222
223 // yaw #1 (horizontal, faded by pitch)
224 farHeur = (Vector3.Angle (transform.forward, prevFrameForward) / _camera.fieldOfView) * (source.width * 0.75f);
225 blurVector.y = rotationScale * lookUpDown * farHeur;//Mathf.Clamp01((1.0ff-Vector3.Dot(transform.forward, prevFrameForward)));
226
227 // yaw #2 (when looking down, faded by 1-pitch)
228 farHeur = (Vector3.Angle (transform.forward, prevFrameForward) / _camera.fieldOfView) * (source.width * 0.75f);
229 blurVector.z = rotationScale * (1.0f- lookUpDown) * farHeur;//Mathf.Clamp01((1.0ff-Vector3.Dot(transform.forward, prevFrameForward)));
230
231 if (distMag > Mathf.Epsilon && movementScale > Mathf.Epsilon) {
232 // forward (probably most important)
233 blurVector.w = movementScale * (Vector3.Dot (transform.forward, distanceVector) ) * (source.width * 0.5f);
234 // jump (maybe scale down further)
235 blurVector.x += movementScale * (Vector3.Dot (transform.up, distanceVector) ) * (source.width * 0.5f);
236 // strafe (maybe scale down further)
237 blurVector.y += movementScale * (Vector3.Dot (transform.right, distanceVector) ) * (source.width * 0.5f);
238 }
239
240 if (preview) // crude approximation
241 motionBlurMaterial.SetVector ("_BlurDirectionPacked", new Vector4 (previewScale.y, previewScale.x, 0.0f, previewScale.z) * 0.5f * _camera.fieldOfView);
242 else
243 motionBlurMaterial.SetVector ("_BlurDirectionPacked", blurVector);
244 }
245 else {
246 // generate velocity buffer
247 Graphics.Blit (source, velBuffer, motionBlurMaterial, 0);
248
249 // patch up velocity buffer:
250
251 // exclude certain layers (e.g. skinned objects as we cant really support that atm)
252
253 Camera cam = null;
254 if (excludeLayers.value != 0)// || dynamicLayers.value)
255 cam = GetTmpCam ();
256
257 if (cam && excludeLayers.value != 0 && replacementClear && replacementClear.isSupported) {
258 cam.targetTexture = velBuffer;
259 cam.cullingMask = excludeLayers;
260 cam.RenderWithShader (replacementClear, "");
261 }
262 }
263
264 if (!preview && Time.frameCount != prevFrameCount) {
265 // remember current transformation data for next frame
266 prevFrameCount = Time.frameCount;
267 Remember ();
268 }
269
270 source.filterMode = FilterMode.Bilinear;
271
272 // debug vel buffer:
273 if (showVelocity) {
274 // generate tile max and neighbour max
275 //Graphics.Blit (velBuffer, tileMax, motionBlurMaterial, 2);
276 //Graphics.Blit (tileMax, neighbourMax, motionBlurMaterial, 3);
277 motionBlurMaterial.SetFloat ("_DisplayVelocityScale", showVelocityScale);
278 Graphics.Blit (velBuffer, destination, motionBlurMaterial, 1);
279 }
280 else {
281 if (filterType == MotionBlurFilter.ReconstructionDX11 && !fallbackFromDX11) {
282 // need to reset some parameters for dx11 shader
283 dx11MotionBlurMaterial.SetFloat ("_MinVelocity", minVelocity);
284 dx11MotionBlurMaterial.SetFloat ("_VelocityScale", velocityScale);
285 dx11MotionBlurMaterial.SetFloat ("_Jitter", jitter);
286
287 // texture samplers
288 dx11MotionBlurMaterial.SetTexture ("_NoiseTex", noiseTexture);
289 dx11MotionBlurMaterial.SetTexture ("_VelTex", velBuffer);
290 dx11MotionBlurMaterial.SetTexture ("_NeighbourMaxTex", neighbourMax);
291
292 dx11MotionBlurMaterial.SetFloat ("_SoftZDistance", Mathf.Max(0.00025f, softZDistance) );
293 dx11MotionBlurMaterial.SetFloat ("_MaxRadiusOrKInPaper", _maxVelocity);
294
295 // generate tile max and neighbour max
296 Graphics.Blit (velBuffer, tileMax, dx11MotionBlurMaterial, 0);
297 Graphics.Blit (tileMax, neighbourMax, dx11MotionBlurMaterial, 1);
298
299 // final blur
300 Graphics.Blit (source, destination, dx11MotionBlurMaterial, 2);
301 }
302 else if (filterType == MotionBlurFilter.Reconstruction || fallbackFromDX11) {
303 // 'reconstructing' properly integrated color
304 motionBlurMaterial.SetFloat ("_SoftZDistance", Mathf.Max(0.00025f, softZDistance) );
305
306 // generate tile max and neighbour max
307 Graphics.Blit (velBuffer, tileMax, motionBlurMaterial, 2);
308 Graphics.Blit (tileMax, neighbourMax, motionBlurMaterial, 3);
309
310 // final blur
311 Graphics.Blit (source, destination, motionBlurMaterial, 4);
312 }
313 else if (filterType == MotionBlurFilter.CameraMotion) {
314 // orange box style motion blur
315 Graphics.Blit (source, destination, motionBlurMaterial, 6);
316 }
317 else if (filterType == MotionBlurFilter.ReconstructionDisc) {
318 // dof style motion blur defocuing and ellipse around the princical blur direction
319 // 'reconstructing' properly integrated color
320 motionBlurMaterial.SetFloat ("_SoftZDistance", Mathf.Max(0.00025f, softZDistance) );
321
322 // generate tile max and neighbour max
323 Graphics.Blit (velBuffer, tileMax, motionBlurMaterial, 2);
324 Graphics.Blit (tileMax, neighbourMax, motionBlurMaterial, 3);
325
326 Graphics.Blit (source, destination, motionBlurMaterial, 7);
327 }
328 else {
329 // simple & fast blur (low quality): just blurring along velocity
330 Graphics.Blit (source, destination, motionBlurMaterial, 5);
331 }
332 }
333
334 // cleanup
335 RenderTexture.ReleaseTemporary (velBuffer);
336 RenderTexture.ReleaseTemporary (tileMax);
337 RenderTexture.ReleaseTemporary (neighbourMax);
338 }
339
340 void Remember () {
341 prevViewProjMat = currentViewProjMat;
342 prevFrameForward = transform.forward;
343 prevFrameUp = transform.up;
344 prevFramePos = transform.position;
345 }
346
347 Camera GetTmpCam () {
348 if (tmpCam == null) {
349 string name = "_" + _camera.name + "_MotionBlurTmpCam";
350 GameObject go = GameObject.Find (name);
351 if (null == go) // couldn't find, recreate
352 tmpCam = new GameObject (name, typeof (Camera));
353 else
354 tmpCam = go;
355 }
356
357 tmpCam.hideFlags = HideFlags.DontSave;
358 tmpCam.transform.position = _camera.transform.position;
359 tmpCam.transform.rotation = _camera.transform.rotation;
360 tmpCam.transform.localScale = _camera.transform.localScale;
361 tmpCam.GetComponent<Camera>().CopyFrom(_camera);
362
363 tmpCam.GetComponent<Camera>().enabled = false;
364 tmpCam.GetComponent<Camera>().depthTextureMode = DepthTextureMode.None;
365 tmpCam.GetComponent<Camera>().clearFlags = CameraClearFlags.Nothing;
366
367 return tmpCam.GetComponent<Camera>();
368 }
369
370 void StartFrame () {
371 // take only x% of positional changes into account (camera motion)
372 // TODO: possibly do the same for rotational part
373 prevFramePos = Vector3.Slerp(prevFramePos, transform.position, 0.75f);
374 }
375
376 static int divRoundUp (int x, int d)
377 {
378 return (x + d - 1) / d;
379 }
380 }
381 }