| using UnityEngine.Rendering; | 
|   | 
| namespace UnityEngine.PostProcessing | 
| { | 
|     using Settings = MotionBlurModel.Settings; | 
|   | 
|     public sealed class MotionBlurComponent : PostProcessingComponentCommandBuffer<MotionBlurModel> | 
|     { | 
|         static class Uniforms | 
|         { | 
|             internal static readonly int _VelocityScale     = Shader.PropertyToID("_VelocityScale"); | 
|             internal static readonly int _MaxBlurRadius     = Shader.PropertyToID("_MaxBlurRadius"); | 
|             internal static readonly int _RcpMaxBlurRadius  = Shader.PropertyToID("_RcpMaxBlurRadius"); | 
|             internal static readonly int _VelocityTex       = Shader.PropertyToID("_VelocityTex"); | 
|             internal static readonly int _MainTex           = Shader.PropertyToID("_MainTex"); | 
|             internal static readonly int _Tile2RT           = Shader.PropertyToID("_Tile2RT"); | 
|             internal static readonly int _Tile4RT           = Shader.PropertyToID("_Tile4RT"); | 
|             internal static readonly int _Tile8RT           = Shader.PropertyToID("_Tile8RT"); | 
|             internal static readonly int _TileMaxOffs       = Shader.PropertyToID("_TileMaxOffs"); | 
|             internal static readonly int _TileMaxLoop       = Shader.PropertyToID("_TileMaxLoop"); | 
|             internal static readonly int _TileVRT           = Shader.PropertyToID("_TileVRT"); | 
|             internal static readonly int _NeighborMaxTex    = Shader.PropertyToID("_NeighborMaxTex"); | 
|             internal static readonly int _LoopCount         = Shader.PropertyToID("_LoopCount"); | 
|             internal static readonly int _TempRT            = Shader.PropertyToID("_TempRT"); | 
|   | 
|             internal static readonly int _History1LumaTex   = Shader.PropertyToID("_History1LumaTex"); | 
|             internal static readonly int _History2LumaTex   = Shader.PropertyToID("_History2LumaTex"); | 
|             internal static readonly int _History3LumaTex   = Shader.PropertyToID("_History3LumaTex"); | 
|             internal static readonly int _History4LumaTex   = Shader.PropertyToID("_History4LumaTex"); | 
|   | 
|             internal static readonly int _History1ChromaTex = Shader.PropertyToID("_History1ChromaTex"); | 
|             internal static readonly int _History2ChromaTex = Shader.PropertyToID("_History2ChromaTex"); | 
|             internal static readonly int _History3ChromaTex = Shader.PropertyToID("_History3ChromaTex"); | 
|             internal static readonly int _History4ChromaTex = Shader.PropertyToID("_History4ChromaTex"); | 
|   | 
|             internal static readonly int _History1Weight    = Shader.PropertyToID("_History1Weight"); | 
|             internal static readonly int _History2Weight    = Shader.PropertyToID("_History2Weight"); | 
|             internal static readonly int _History3Weight    = Shader.PropertyToID("_History3Weight"); | 
|             internal static readonly int _History4Weight    = Shader.PropertyToID("_History4Weight"); | 
|         } | 
|   | 
|         enum Pass | 
|         { | 
|             VelocitySetup, | 
|             TileMax1, | 
|             TileMax2, | 
|             TileMaxV, | 
|             NeighborMax, | 
|             Reconstruction, | 
|             FrameCompression, | 
|             FrameBlendingChroma, | 
|             FrameBlendingRaw | 
|         } | 
|   | 
|         public class ReconstructionFilter | 
|         { | 
|             // Texture format for storing 2D vectors. | 
|             RenderTextureFormat m_VectorRTFormat = RenderTextureFormat.RGHalf; | 
|   | 
|             // Texture format for storing packed velocity/depth. | 
|             RenderTextureFormat m_PackedRTFormat = RenderTextureFormat.ARGB2101010; | 
|   | 
|             public ReconstructionFilter() | 
|             { | 
|                 CheckTextureFormatSupport(); | 
|             } | 
|   | 
|             void CheckTextureFormatSupport() | 
|             { | 
|                 // If 2:10:10:10 isn't supported, use ARGB32 instead. | 
|                 if (!SystemInfo.SupportsRenderTextureFormat(m_PackedRTFormat)) | 
|                     m_PackedRTFormat = RenderTextureFormat.ARGB32; | 
|             } | 
|   | 
|             public bool IsSupported() | 
|             { | 
|                 return SystemInfo.supportsMotionVectors; | 
|             } | 
|   | 
|             public void ProcessImage(PostProcessingContext context, CommandBuffer cb, ref Settings settings, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material) | 
|             { | 
|                 const float kMaxBlurRadius = 5f; | 
|   | 
|                 // Calculate the maximum blur radius in pixels. | 
|                 int maxBlurPixels = (int)(kMaxBlurRadius * context.height / 100); | 
|   | 
|                 // Calculate the TileMax size. | 
|                 // It should be a multiple of 8 and larger than maxBlur. | 
|                 int tileSize = ((maxBlurPixels - 1) / 8 + 1) * 8; | 
|   | 
|                 // Pass 1 - Velocity/depth packing | 
|                 var velocityScale = settings.shutterAngle / 360f; | 
|                 cb.SetGlobalFloat(Uniforms._VelocityScale, velocityScale); | 
|                 cb.SetGlobalFloat(Uniforms._MaxBlurRadius, maxBlurPixels); | 
|                 cb.SetGlobalFloat(Uniforms._RcpMaxBlurRadius, 1f / maxBlurPixels); | 
|   | 
|                 int vbuffer = Uniforms._VelocityTex; | 
|                 cb.GetTemporaryRT(vbuffer, context.width, context.height, 0, FilterMode.Point, m_PackedRTFormat, RenderTextureReadWrite.Linear); | 
|                 cb.Blit((Texture)null, vbuffer, material, (int)Pass.VelocitySetup); | 
|   | 
|                 // Pass 2 - First TileMax filter (1/2 downsize) | 
|                 int tile2 = Uniforms._Tile2RT; | 
|                 cb.GetTemporaryRT(tile2, context.width / 2, context.height / 2, 0, FilterMode.Point, m_VectorRTFormat, RenderTextureReadWrite.Linear); | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, vbuffer); | 
|                 cb.Blit(vbuffer, tile2, material, (int)Pass.TileMax1); | 
|   | 
|                 // Pass 3 - Second TileMax filter (1/2 downsize) | 
|                 int tile4 = Uniforms._Tile4RT; | 
|                 cb.GetTemporaryRT(tile4, context.width / 4, context.height / 4, 0, FilterMode.Point, m_VectorRTFormat, RenderTextureReadWrite.Linear); | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, tile2); | 
|                 cb.Blit(tile2, tile4, material, (int)Pass.TileMax2); | 
|                 cb.ReleaseTemporaryRT(tile2); | 
|   | 
|                 // Pass 4 - Third TileMax filter (1/2 downsize) | 
|                 int tile8 = Uniforms._Tile8RT; | 
|                 cb.GetTemporaryRT(tile8, context.width / 8, context.height / 8, 0, FilterMode.Point, m_VectorRTFormat, RenderTextureReadWrite.Linear); | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, tile4); | 
|                 cb.Blit(tile4, tile8, material, (int)Pass.TileMax2); | 
|                 cb.ReleaseTemporaryRT(tile4); | 
|   | 
|                 // Pass 5 - Fourth TileMax filter (reduce to tileSize) | 
|                 var tileMaxOffs = Vector2.one * (tileSize / 8f - 1f) * -0.5f; | 
|                 cb.SetGlobalVector(Uniforms._TileMaxOffs, tileMaxOffs); | 
|                 cb.SetGlobalFloat(Uniforms._TileMaxLoop, (int)(tileSize / 8f)); | 
|   | 
|                 int tile = Uniforms._TileVRT; | 
|                 cb.GetTemporaryRT(tile, context.width / tileSize, context.height / tileSize, 0, FilterMode.Point, m_VectorRTFormat, RenderTextureReadWrite.Linear); | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, tile8); | 
|                 cb.Blit(tile8, tile, material, (int)Pass.TileMaxV); | 
|                 cb.ReleaseTemporaryRT(tile8); | 
|   | 
|                 // Pass 6 - NeighborMax filter | 
|                 int neighborMax = Uniforms._NeighborMaxTex; | 
|                 int neighborMaxWidth = context.width / tileSize; | 
|                 int neighborMaxHeight = context.height / tileSize; | 
|                 cb.GetTemporaryRT(neighborMax, neighborMaxWidth, neighborMaxHeight, 0, FilterMode.Point, m_VectorRTFormat, RenderTextureReadWrite.Linear); | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, tile); | 
|                 cb.Blit(tile, neighborMax, material, (int)Pass.NeighborMax); | 
|                 cb.ReleaseTemporaryRT(tile); | 
|   | 
|                 // Pass 7 - Reconstruction pass | 
|                 cb.SetGlobalFloat(Uniforms._LoopCount, Mathf.Clamp(settings.sampleCount / 2, 1, 64)); | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, source); | 
|   | 
|                 cb.Blit(source, destination, material, (int)Pass.Reconstruction); | 
|   | 
|                 cb.ReleaseTemporaryRT(vbuffer); | 
|                 cb.ReleaseTemporaryRT(neighborMax); | 
|             } | 
|         } | 
|   | 
|         public class FrameBlendingFilter | 
|         { | 
|             struct Frame | 
|             { | 
|                 public RenderTexture lumaTexture; | 
|                 public RenderTexture chromaTexture; | 
|   | 
|                 float m_Time; | 
|                 RenderTargetIdentifier[] m_MRT; | 
|   | 
|                 public float CalculateWeight(float strength, float currentTime) | 
|                 { | 
|                     if (Mathf.Approximately(m_Time, 0f)) | 
|                         return 0f; | 
|   | 
|                     var coeff = Mathf.Lerp(80f, 16f, strength); | 
|                     return Mathf.Exp((m_Time - currentTime) * coeff); | 
|                 } | 
|   | 
|                 public void Release() | 
|                 { | 
|                     if (lumaTexture != null) | 
|                         RenderTexture.ReleaseTemporary(lumaTexture); | 
|   | 
|                     if (chromaTexture != null) | 
|                         RenderTexture.ReleaseTemporary(chromaTexture); | 
|   | 
|                     lumaTexture = null; | 
|                     chromaTexture = null; | 
|                 } | 
|   | 
|                 public void MakeRecord(CommandBuffer cb, RenderTargetIdentifier source, int width, int height, Material material) | 
|                 { | 
|                     Release(); | 
|   | 
|                     lumaTexture = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.R8, RenderTextureReadWrite.Linear); | 
|                     chromaTexture = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.R8, RenderTextureReadWrite.Linear); | 
|   | 
|                     lumaTexture.filterMode = FilterMode.Point; | 
|                     chromaTexture.filterMode = FilterMode.Point; | 
|   | 
|                     if (m_MRT == null) | 
|                         m_MRT = new RenderTargetIdentifier[2]; | 
|   | 
|                     m_MRT[0] = lumaTexture; | 
|                     m_MRT[1] = chromaTexture; | 
|   | 
|                     cb.SetGlobalTexture(Uniforms._MainTex, source); | 
|                     cb.SetRenderTarget(m_MRT, lumaTexture); | 
|                     cb.DrawMesh(GraphicsUtils.quad, Matrix4x4.identity, material, 0, (int)Pass.FrameCompression); | 
|   | 
|                     m_Time = Time.time; | 
|                 } | 
|   | 
|                 public void MakeRecordRaw(CommandBuffer cb, RenderTargetIdentifier source, int width, int height, RenderTextureFormat format) | 
|                 { | 
|                     Release(); | 
|   | 
|                     lumaTexture = RenderTexture.GetTemporary(width, height, 0, format); | 
|                     lumaTexture.filterMode = FilterMode.Point; | 
|   | 
|                     cb.SetGlobalTexture(Uniforms._MainTex, source); | 
|                     cb.Blit(source, lumaTexture); | 
|   | 
|                     m_Time = Time.time; | 
|                 } | 
|             } | 
|   | 
|             bool m_UseCompression; | 
|             RenderTextureFormat m_RawTextureFormat; | 
|   | 
|             Frame[] m_FrameList; | 
|             int m_LastFrameCount; | 
|   | 
|             public FrameBlendingFilter() | 
|             { | 
|                 m_UseCompression = CheckSupportCompression(); | 
|                 m_RawTextureFormat = GetPreferredRenderTextureFormat(); | 
|                 m_FrameList = new Frame[4]; | 
|             } | 
|   | 
|             public void Dispose() | 
|             { | 
|                 foreach (var frame in m_FrameList) | 
|                     frame.Release(); | 
|             } | 
|   | 
|             public void PushFrame(CommandBuffer cb, RenderTargetIdentifier source, int width, int height, Material material) | 
|             { | 
|                 // Push only when actual update (do nothing while pausing) | 
|                 var frameCount = Time.frameCount; | 
|                 if (frameCount == m_LastFrameCount) return; | 
|   | 
|                 // Update the frame record. | 
|                 var index = frameCount % m_FrameList.Length; | 
|   | 
|                 if (m_UseCompression) | 
|                     m_FrameList[index].MakeRecord(cb, source, width, height, material); | 
|                 else | 
|                     m_FrameList[index].MakeRecordRaw(cb, source, width, height, m_RawTextureFormat); | 
|   | 
|                 m_LastFrameCount = frameCount; | 
|             } | 
|   | 
|             public void BlendFrames(CommandBuffer cb, float strength, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material) | 
|             { | 
|                 var t = Time.time; | 
|   | 
|                 var f1 = GetFrameRelative(-1); | 
|                 var f2 = GetFrameRelative(-2); | 
|                 var f3 = GetFrameRelative(-3); | 
|                 var f4 = GetFrameRelative(-4); | 
|   | 
|                 cb.SetGlobalTexture(Uniforms._History1LumaTex, f1.lumaTexture); | 
|                 cb.SetGlobalTexture(Uniforms._History2LumaTex, f2.lumaTexture); | 
|                 cb.SetGlobalTexture(Uniforms._History3LumaTex, f3.lumaTexture); | 
|                 cb.SetGlobalTexture(Uniforms._History4LumaTex, f4.lumaTexture); | 
|   | 
|                 cb.SetGlobalTexture(Uniforms._History1ChromaTex, f1.chromaTexture); | 
|                 cb.SetGlobalTexture(Uniforms._History2ChromaTex, f2.chromaTexture); | 
|                 cb.SetGlobalTexture(Uniforms._History3ChromaTex, f3.chromaTexture); | 
|                 cb.SetGlobalTexture(Uniforms._History4ChromaTex, f4.chromaTexture); | 
|   | 
|                 cb.SetGlobalFloat(Uniforms._History1Weight, f1.CalculateWeight(strength, t)); | 
|                 cb.SetGlobalFloat(Uniforms._History2Weight, f2.CalculateWeight(strength, t)); | 
|                 cb.SetGlobalFloat(Uniforms._History3Weight, f3.CalculateWeight(strength, t)); | 
|                 cb.SetGlobalFloat(Uniforms._History4Weight, f4.CalculateWeight(strength, t)); | 
|   | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, source); | 
|                 cb.Blit(source, destination, material, m_UseCompression ? (int)Pass.FrameBlendingChroma : (int)Pass.FrameBlendingRaw); | 
|             } | 
|   | 
|             // Check if the platform has the capability of compression. | 
|             static bool CheckSupportCompression() | 
|             { | 
|                 return | 
|                     SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8) && | 
|                     SystemInfo.supportedRenderTargetCount > 1; | 
|             } | 
|   | 
|             // Determine which 16-bit render texture format is available. | 
|             static RenderTextureFormat GetPreferredRenderTextureFormat() | 
|             { | 
|                 RenderTextureFormat[] formats = | 
|                 { | 
|                     RenderTextureFormat.RGB565, | 
|                     RenderTextureFormat.ARGB1555, | 
|                     RenderTextureFormat.ARGB4444 | 
|                 }; | 
|   | 
|                 foreach (var f in formats) | 
|                     if (SystemInfo.SupportsRenderTextureFormat(f)) return f; | 
|   | 
|                 return RenderTextureFormat.Default; | 
|             } | 
|   | 
|             // Retrieve a frame record with relative indexing. | 
|             // Use a negative index to refer to previous frames. | 
|             Frame GetFrameRelative(int offset) | 
|             { | 
|                 var index = (Time.frameCount + m_FrameList.Length + offset) % m_FrameList.Length; | 
|                 return m_FrameList[index]; | 
|             } | 
|         } | 
|   | 
|         ReconstructionFilter m_ReconstructionFilter; | 
|         public ReconstructionFilter reconstructionFilter | 
|         { | 
|             get | 
|             { | 
|                 if (m_ReconstructionFilter == null) | 
|                     m_ReconstructionFilter = new ReconstructionFilter(); | 
|   | 
|                 return m_ReconstructionFilter; | 
|             } | 
|         } | 
|   | 
|         FrameBlendingFilter m_FrameBlendingFilter; | 
|         public FrameBlendingFilter frameBlendingFilter | 
|         { | 
|             get | 
|             { | 
|                 if (m_FrameBlendingFilter == null) | 
|                     m_FrameBlendingFilter = new FrameBlendingFilter(); | 
|   | 
|                 return m_FrameBlendingFilter; | 
|             } | 
|         } | 
|   | 
|         bool m_FirstFrame = true; | 
|   | 
|         public override bool active | 
|         { | 
|             get | 
|             { | 
|                 var settings = model.settings; | 
|                 return model.enabled | 
|                        && ((settings.shutterAngle > 0f && reconstructionFilter.IsSupported()) || settings.frameBlending > 0f) | 
|                        && SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2 // No movecs on GLES2 platforms | 
|                        && !context.interrupted; | 
|             } | 
|         } | 
|   | 
|         public override string GetName() | 
|         { | 
|             return "Motion Blur"; | 
|         } | 
|   | 
|         public void ResetHistory() | 
|         { | 
|             if (m_FrameBlendingFilter != null) | 
|                 m_FrameBlendingFilter.Dispose(); | 
|   | 
|             m_FrameBlendingFilter = null; | 
|         } | 
|   | 
|         public override DepthTextureMode GetCameraFlags() | 
|         { | 
|             return DepthTextureMode.Depth | DepthTextureMode.MotionVectors; | 
|         } | 
|   | 
|         public override CameraEvent GetCameraEvent() | 
|         { | 
|             return CameraEvent.BeforeImageEffects; | 
|         } | 
|   | 
|         public override void OnEnable() | 
|         { | 
|             m_FirstFrame = true; | 
|         } | 
|   | 
|         public override void PopulateCommandBuffer(CommandBuffer cb) | 
|         { | 
| #if UNITY_EDITOR | 
|             // Don't render motion blur preview when the editor is not playing as it can in some | 
|             // cases results in ugly artifacts (i.e. when resizing the game view). | 
|             if (!Application.isPlaying) | 
|                 return; | 
| #endif | 
|   | 
|             // Skip rendering in the first frame as motion vectors won't be abvailable until the | 
|             // next one | 
|             if (m_FirstFrame) | 
|             { | 
|                 m_FirstFrame = false; | 
|                 return; | 
|             } | 
|   | 
|             var material = context.materialFactory.Get("Hidden/Post FX/Motion Blur"); | 
|             var blitMaterial = context.materialFactory.Get("Hidden/Post FX/Blit"); | 
|             var settings = model.settings; | 
|   | 
|             var fbFormat = context.isHdr | 
|                 ? RenderTextureFormat.DefaultHDR | 
|                 : RenderTextureFormat.Default; | 
|   | 
|             int tempRT = Uniforms._TempRT; | 
|             cb.GetTemporaryRT(tempRT, context.width, context.height, 0, FilterMode.Point, fbFormat); | 
|   | 
|             if (settings.shutterAngle > 0f && settings.frameBlending > 0f) | 
|             { | 
|                 // Motion blur + frame blending | 
|                 reconstructionFilter.ProcessImage(context, cb, ref settings, BuiltinRenderTextureType.CameraTarget, tempRT, material); | 
|                 frameBlendingFilter.BlendFrames(cb, settings.frameBlending, tempRT, BuiltinRenderTextureType.CameraTarget, material); | 
|                 frameBlendingFilter.PushFrame(cb, tempRT, context.width, context.height, material); | 
|             } | 
|             else if (settings.shutterAngle > 0f) | 
|             { | 
|                 // No frame blending | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, BuiltinRenderTextureType.CameraTarget); | 
|                 cb.Blit(BuiltinRenderTextureType.CameraTarget, tempRT, blitMaterial, 0); | 
|                 reconstructionFilter.ProcessImage(context, cb, ref settings, tempRT, BuiltinRenderTextureType.CameraTarget, material); | 
|             } | 
|             else if (settings.frameBlending > 0f) | 
|             { | 
|                 // Frame blending only | 
|                 cb.SetGlobalTexture(Uniforms._MainTex, BuiltinRenderTextureType.CameraTarget); | 
|                 cb.Blit(BuiltinRenderTextureType.CameraTarget, tempRT, blitMaterial, 0); | 
|                 frameBlendingFilter.BlendFrames(cb, settings.frameBlending, tempRT, BuiltinRenderTextureType.CameraTarget, material); | 
|                 frameBlendingFilter.PushFrame(cb, tempRT, context.width, context.height, material); | 
|             } | 
|   | 
|             // Cleaning up | 
|             cb.ReleaseTemporaryRT(tempRT); | 
|         } | 
|   | 
|         public override void OnDisable() | 
|         { | 
|             if (m_FrameBlendingFilter != null) | 
|                 m_FrameBlendingFilter.Dispose(); | 
|         } | 
|     } | 
| } |