443 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			443 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
| //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 _VelocityTex       = Shader.PropertyToID("_VelocityTex");
 | |
| //            internal static readonly int _Tile4RT           = Shader.PropertyToID("_Tile4RT");
 | |
| //            internal static readonly int _MainTex           = Shader.PropertyToID("_MainTex");
 | |
| //            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,
 | |
| //            TileMax4,
 | |
| //            TileMax2,
 | |
| //            TileMaxV,
 | |
| //            NeighborMax,
 | |
| //            Reconstruction,
 | |
| //            ReconstructionUnroll,
 | |
| //            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;
 | |
| 
 | |
| //            bool m_UseUnrolledShader;
 | |
| 
 | |
| //            public ReconstructionFilter()
 | |
| //            {
 | |
| //                CheckTextureFormatSupport();
 | |
| 
 | |
| //                // Use loop unrolling on Adreno GPUs to avoid shader issues.
 | |
| //                m_UseUnrolledShader = SystemInfo.graphicsDeviceName.Contains("Adreno");
 | |
| //            }
 | |
| 
 | |
| //            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
 | |
| //                // Motion vectors are scaled by an empirical factor of 1.45.
 | |
| //                var velocityScale = settings.shutterAngle / 360f * 1.45f;
 | |
| //                cb.SetGlobalFloat(Uniforms._VelocityScale, velocityScale);
 | |
| //                cb.SetGlobalFloat(Uniforms._MaxBlurRadius, maxBlurPixels);
 | |
| 
 | |
| //                int vbuffer = Uniforms._VelocityTex;
 | |
| //                cb.GetTemporaryRT(vbuffer, context.width, context.height, 0, FilterMode.Point, m_PackedRTFormat);
 | |
| //                cb.Blit((Texture)null, vbuffer, material, (int)Pass.VelocitySetup);
 | |
| 
 | |
| //                // Pass 2 - First TileMax filter (1/4 downsize)
 | |
| //                int tile4 = Uniforms._Tile4RT;
 | |
| //                cb.GetTemporaryRT(tile4, context.width / 4, context.height / 4, 0, FilterMode.Point, m_VectorRTFormat);
 | |
| //                cb.SetGlobalTexture(Uniforms._MainTex, vbuffer);
 | |
| //                cb.Blit(vbuffer, tile4, material, (int)Pass.TileMax4);
 | |
| 
 | |
| //                // Pass 3 - Second TileMax filter (1/2 downsize)
 | |
| //                int tile8 = Uniforms._Tile8RT;
 | |
| //                cb.GetTemporaryRT(tile8, context.width / 8, context.height / 8, 0, FilterMode.Point, m_VectorRTFormat);
 | |
| //                cb.SetGlobalTexture(Uniforms._MainTex, tile4);
 | |
| //                cb.Blit(tile4, tile8, material, (int)Pass.TileMax2);
 | |
| //                cb.ReleaseTemporaryRT(tile4);
 | |
| 
 | |
| //                // Pass 4 - Third 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);
 | |
| //                cb.SetGlobalTexture(Uniforms._MainTex, tile8);
 | |
| //                cb.Blit(tile8, tile, material, (int)Pass.TileMaxV);
 | |
| //                cb.ReleaseTemporaryRT(tile8);
 | |
| 
 | |
| //                // Pass 5 - 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);
 | |
| //                cb.SetGlobalTexture(Uniforms._MainTex, tile);
 | |
| //                cb.Blit(tile, neighborMax, material, (int)Pass.NeighborMax);
 | |
| //                cb.ReleaseTemporaryRT(tile);
 | |
| 
 | |
| //                // Pass 6 - Reconstruction pass
 | |
| //                cb.SetGlobalFloat(Uniforms._LoopCount, Mathf.Clamp(settings.sampleCount / 2, 1, 64));
 | |
| //                cb.SetGlobalFloat(Uniforms._MaxBlurRadius, maxBlurPixels);
 | |
| //                cb.SetGlobalTexture(Uniforms._MainTex, source);
 | |
| 
 | |
| //                cb.Blit(source, destination, material, m_UseUnrolledShader ? (int)Pass.ReconstructionUnroll : (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);
 | |
| //                    chromaTexture = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.R8);
 | |
| 
 | |
| //                    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();
 | |
| //        }
 | |
| //    }
 | |
| //}
 |