123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- 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();
- }
- }
- }
|