MotionBlur.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using System;
  2. namespace UnityEngine.Rendering.PostProcessing
  3. {
  4. /// <summary>
  5. /// This class holds settings for the Motion Blur effect.
  6. /// </summary>
  7. [Serializable]
  8. [PostProcess(typeof(MotionBlurRenderer), "Unity/Motion Blur", false)]
  9. public sealed class MotionBlur : PostProcessEffectSettings
  10. {
  11. /// <summary>
  12. /// The angle of the rotary shutter. Larger values give longer exposure therefore a stronger
  13. /// blur effect.
  14. /// </summary>
  15. [Range(0f, 360f), Tooltip("The angle of rotary shutter. Larger values give longer exposure.")]
  16. public FloatParameter shutterAngle = new FloatParameter { value = 270f };
  17. /// <summary>
  18. /// The amount of sample points, which affects quality and performances.
  19. /// </summary>
  20. [Range(4, 32), Tooltip("The amount of sample points. This affects quality and performance.")]
  21. public IntParameter sampleCount = new IntParameter { value = 10 };
  22. /// <inheritdoc />
  23. public override bool IsEnabledAndSupported(PostProcessRenderContext context)
  24. {
  25. return enabled.value
  26. && shutterAngle.value > 0f
  27. #if UNITY_EDITOR
  28. // Don't render motion blur preview when the editor is not playing as it can in some
  29. // cases results in ugly artifacts (i.e. when resizing the game view).
  30. && Application.isPlaying
  31. #endif
  32. && SystemInfo.supportsMotionVectors
  33. && RenderTextureFormat.RGHalf.IsSupported()
  34. && !RuntimeUtilities.isVREnabled;
  35. }
  36. }
  37. internal sealed class MotionBlurRenderer : PostProcessEffectRenderer<MotionBlur>
  38. {
  39. enum Pass
  40. {
  41. VelocitySetup,
  42. TileMax1,
  43. TileMax2,
  44. TileMaxV,
  45. NeighborMax,
  46. Reconstruction
  47. }
  48. public override DepthTextureMode GetCameraFlags()
  49. {
  50. return DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
  51. }
  52. public override void Render(PostProcessRenderContext context)
  53. {
  54. var cmd = context.command;
  55. if (m_ResetHistory)
  56. {
  57. cmd.BlitFullscreenTriangle(context.source, context.destination);
  58. m_ResetHistory = false;
  59. return;
  60. }
  61. const float kMaxBlurRadius = 5f;
  62. var vectorRTFormat = RenderTextureFormat.RGHalf;
  63. var packedRTFormat = RenderTextureFormat.ARGB2101010.IsSupported()
  64. ? RenderTextureFormat.ARGB2101010
  65. : RenderTextureFormat.ARGB32;
  66. var sheet = context.propertySheets.Get(context.resources.shaders.motionBlur);
  67. cmd.BeginSample("MotionBlur");
  68. // Calculate the maximum blur radius in pixels.
  69. int maxBlurPixels = (int)(kMaxBlurRadius * context.height / 100);
  70. // Calculate the TileMax size.
  71. // It should be a multiple of 8 and larger than maxBlur.
  72. int tileSize = ((maxBlurPixels - 1) / 8 + 1) * 8;
  73. // Pass 1 - Velocity/depth packing
  74. var velocityScale = settings.shutterAngle / 360f;
  75. sheet.properties.SetFloat(ShaderIDs.VelocityScale, velocityScale);
  76. sheet.properties.SetFloat(ShaderIDs.MaxBlurRadius, maxBlurPixels);
  77. sheet.properties.SetFloat(ShaderIDs.RcpMaxBlurRadius, 1f / maxBlurPixels);
  78. int vbuffer = ShaderIDs.VelocityTex;
  79. cmd.GetTemporaryRT(vbuffer, context.width, context.height, 0, FilterMode.Point,
  80. packedRTFormat, RenderTextureReadWrite.Linear);
  81. cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, vbuffer, sheet, (int)Pass.VelocitySetup);
  82. // Pass 2 - First TileMax filter (1/2 downsize)
  83. int tile2 = ShaderIDs.Tile2RT;
  84. cmd.GetTemporaryRT(tile2, context.width / 2, context.height / 2, 0, FilterMode.Point,
  85. vectorRTFormat, RenderTextureReadWrite.Linear);
  86. cmd.BlitFullscreenTriangle(vbuffer, tile2, sheet, (int)Pass.TileMax1);
  87. // Pass 3 - Second TileMax filter (1/2 downsize)
  88. int tile4 = ShaderIDs.Tile4RT;
  89. cmd.GetTemporaryRT(tile4, context.width / 4, context.height / 4, 0, FilterMode.Point,
  90. vectorRTFormat, RenderTextureReadWrite.Linear);
  91. cmd.BlitFullscreenTriangle(tile2, tile4, sheet, (int)Pass.TileMax2);
  92. cmd.ReleaseTemporaryRT(tile2);
  93. // Pass 4 - Third TileMax filter (1/2 downsize)
  94. int tile8 = ShaderIDs.Tile8RT;
  95. cmd.GetTemporaryRT(tile8, context.width / 8, context.height / 8, 0, FilterMode.Point,
  96. vectorRTFormat, RenderTextureReadWrite.Linear);
  97. cmd.BlitFullscreenTriangle(tile4, tile8, sheet, (int)Pass.TileMax2);
  98. cmd.ReleaseTemporaryRT(tile4);
  99. // Pass 5 - Fourth TileMax filter (reduce to tileSize)
  100. var tileMaxOffs = Vector2.one * (tileSize / 8f - 1f) * -0.5f;
  101. sheet.properties.SetVector(ShaderIDs.TileMaxOffs, tileMaxOffs);
  102. sheet.properties.SetFloat(ShaderIDs.TileMaxLoop, (int)(tileSize / 8f));
  103. int tile = ShaderIDs.TileVRT;
  104. cmd.GetTemporaryRT(tile, context.width / tileSize, context.height / tileSize, 0,
  105. FilterMode.Point, vectorRTFormat, RenderTextureReadWrite.Linear);
  106. cmd.BlitFullscreenTriangle(tile8, tile, sheet, (int)Pass.TileMaxV);
  107. cmd.ReleaseTemporaryRT(tile8);
  108. // Pass 6 - NeighborMax filter
  109. int neighborMax = ShaderIDs.NeighborMaxTex;
  110. int neighborMaxWidth = context.width / tileSize;
  111. int neighborMaxHeight = context.height / tileSize;
  112. cmd.GetTemporaryRT(neighborMax, neighborMaxWidth, neighborMaxHeight, 0,
  113. FilterMode.Point, vectorRTFormat, RenderTextureReadWrite.Linear);
  114. cmd.BlitFullscreenTriangle(tile, neighborMax, sheet, (int)Pass.NeighborMax);
  115. cmd.ReleaseTemporaryRT(tile);
  116. // Pass 7 - Reconstruction pass
  117. sheet.properties.SetFloat(ShaderIDs.LoopCount, Mathf.Clamp(settings.sampleCount / 2, 1, 64));
  118. cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Reconstruction);
  119. cmd.ReleaseTemporaryRT(vbuffer);
  120. cmd.ReleaseTemporaryRT(neighborMax);
  121. cmd.EndSample("MotionBlur");
  122. }
  123. }
  124. }