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 }


make sure to match this to MAX_RADIUS in shader ('k' in paper)

CameraMotion = 0, global screen blur based on cam motion

LocalBlur = 1, cheap blur, no dilation or scattering

Reconstruction = 2, advanced filter (simulates scattering) as in plausible motion blur paper

ReconstructionDX11 = 3, advanced filter (simulates scattering) as in plausible motion blur paper

ReconstructionDisc = 4, advanced filter using scaled poisson disc sampling

settings

public bool preview = false; show how blur would look like in action ...

public Vector3 previewScale = Vector3.one; ... given this movement vector

params

public float maxVelocity = 8.0f; maximum velocity in pixels

public float minVelocity = 0.1f; minimum velocity in pixels

public float velocityScale = 0.375f; global velocity scale

public float softZDistance = 0.005f; for z overlap check softness (reconstruction filter only)

public int velocityDownsample = 1; low resolution velocity buffer? (optimization)

resources

(internal) debug

camera transforms

shortcuts to calculate global blur direction when using 'CameraMotion'

wasActive = false; hack to fake positionrotation update and prevent bad blurs

CheckSupport (true, true); depth & hdr needed

use if possible new RG format ... fallback to half otherwise

get temp textures

float _maxVelocity = maxVelocity; calculate 'k'

note: 's' is hardcoded in shaders except for DX11 path

auto DX11 fallback!

calc correct viewprj matrix

just started up?

matrices

texture samplers

generate an artifical 'previous' matrix to simulate blur look

offset.SetTRS(previewScale * 0.3333f, Quaternion.identity, Vector3.one); using only translation

build blur vector to be used in shader to create a global blur direction

pitch (vertical)

blurVector.x = rotationScale * farHeur;Mathf.Clamp01((1.0ff-Vector3.Dot(transform.up, prevFrameUp)));

yaw #1 (horizontal, faded by pitch)

blurVector.y = rotationScale * lookUpDown * farHeur;Mathf.Clamp01((1.0ff-Vector3.Dot(transform.forward, prevFrameForward)));

yaw #2 (when looking down, faded by 1-pitch)

blurVector.z = rotationScale * (1.0f- lookUpDown) * farHeur;Mathf.Clamp01((1.0ff-Vector3.Dot(transform.forward, prevFrameForward)));

forward (probably most important)

jump (maybe scale down further)

strafe (maybe scale down further)

if (preview) crude approximation

generate velocity buffer

patch up velocity buffer:

exclude certain layers (e.g. skinned objects as we cant really support that atm)

if (excludeLayers.value != 0) || dynamicLayers.value)

remember current transformation data for next frame

debug vel buffer:

generate tile max and neighbour max

Graphics.Blit (velBuffer, tileMax, motionBlurMaterial, 2);

Graphics.Blit (tileMax, neighbourMax, motionBlurMaterial, 3);

need to reset some parameters for dx11 shader

texture samplers

generate tile max and neighbour max

final blur

'reconstructing' properly integrated color

generate tile max and neighbour max

final blur

orange box style motion blur

dof style motion blur defocuing and ellipse around the princical blur direction

'reconstructing' properly integrated color

generate tile max and neighbour max

simple & fast blur (low quality): just blurring along velocity

cleanup

if (null == go) couldn't find, recreate

take only x% of positional changes into account (camera motion)

TODO: possibly do the same for rotational part



Gõ tìm kiếm nhanh...