Advertisement
Guest User

Untitled

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