运动模糊(一)

作者:追风剑情 发布于:2017-5-9 11:47 分类:Shader

一、创建Shader

  1. Shader "Custom/MotionBlur"
  2. {
  3. Properties
  4. {
  5. _MainTex ("Texture", 2D) = "white" {}
  6. //混合图像时使用的混合系数
  7. _BlurAmount ("Blur Amount", Float) = 1.0
  8. }
  9. SubShader
  10. {
  11. Tags { "RenderType"="Opaque" }
  12. LOD 100
  13.  
  14. ZTest Always Cull Off ZWrite Off
  15.  
  16. CGINCLUDE
  17. #include "UnityCG.cginc"
  18.  
  19. sampler2D _MainTex;
  20. float4 _MainTex_ST;
  21. float _BlurAmount;
  22.  
  23. struct v2f {
  24. float4 pos : SV_POSITION;
  25. half2 uv : TEXCOORD0;
  26. };
  27.  
  28. v2f vert(appdata_img v){
  29. v2f o;
  30. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
  31. o.uv = v.texcoord;
  32. return o;
  33. }
  34.  
  35. //RGB通道版本的Shader对当前图像进行采样,并将其A通道的值设置为_BlurAmount,以便在后
  36. //面混合时可以使用它的透明通道进行混合。
  37. fixed4 fragRGB (v2f i) : SV_Target
  38. {
  39. return fixed4(tex2D(_MainTex, i.uv).rgb, _BlurAmount);
  40. }
  41.  
  42. //A通道版本的代码就更简单了,直接返回采样结果。
  43. //实际上,这个版本只是为了维护渲染纹理的透明通道值,不让其受混合时使用的透明度值的影响。
  44. half4 fragA (v2f i) : SV_Target
  45. {
  46. return tex2D(_MainTex, i.uv);
  47. }
  48. ENDCG
  49.  
  50. //之所以要把A通道和RGB通道分开,是因为在更新RGB时我们需要设置它的A通道来混合图像,
  51. //但又不希望A通道的值写入渲染纹理中。
  52.  
  53. Pass
  54. {
  55. //用于更新渲染纹理的RGB通道
  56.  
  57. Blend SrcAlpha OneMinusSrcAlpha
  58.  
  59. ColorMask RGB //只输出RGB通道
  60.  
  61. CGPROGRAM
  62. #pragma vertex vert
  63. #pragma fragment fragRGB
  64. ENDCG
  65. }
  66.  
  67. Pass
  68. {
  69. //用于更新渲染纹理的A通道
  70.  
  71. Blend One Zero
  72.  
  73. ColorMask A //只输出A通道
  74.  
  75. CGPROGRAM
  76. #pragma vertex vert
  77. #pragma fragment fragA
  78. ENDCG
  79. }
  80. }
  81. FallBack Off
  82. }

二、创建脚本,并挂到摄像机上

  1. using UnityEngine;
  2. /// <summary>
  3. /// 运动模糊
  4. /// 原理: 不断把当前的渲染图像叠加到之前的渲染图像中,从而产生一种运动轨迹的视觉效果。
  5. /// </summary>
  6. public class MotionBlur : PostEffectsBase
  7. {
  8. //模糊参数:值越大拖尾效果越明显
  9. //为了防止拖尾效果完全替代当前帧的渲染结果,我们把它的值截取在0.0~0.9范围内
  10. [Range(0.0f, 0.9f)]
  11. public float blurAmount = 0.5f;
  12. public Shader motionBlurShader;
  13. private Material motionBlurMaterial = null;
  14. public Material material
  15. {
  16. get
  17. {
  18. motionBlurMaterial = CheckShaderAndCreateMaterial(motionBlurShader, motionBlurMaterial);
  19. return motionBlurMaterial;
  20. }
  21. }
  22.  
  23. //保存之前图片叠加结果
  24. private RenderTexture accumulationTexture;
  25.  
  26. void OnDisable()
  27. {
  28. //该脚本不运行时立即销毁,因为我们不希望在下一次应用运动模糊时重新叠加图像。
  29. DestroyImmediate(accumulationTexture);
  30. }
  31.  
  32. void OnRenderImage(RenderTexture src, RenderTexture dest)
  33. {
  34. if (material != null)
  35. {
  36. if(accumulationTexture == null || accumulationTexture.width != src.width || accumulationTexture.height != src.height)
  37. {
  38. DestroyImmediate(accumulationTexture);
  39. accumulationTexture = new RenderTexture(src.width, src.height, 0);
  40. accumulationTexture.hideFlags = HideFlags.HideAndDontSave;//不显示在Hierarchy中,也不保存在场景中。
  41. Graphics.Blit(src, accumulationTexture);
  42. }
  43. //渲染纹理恢复操作
  44. //恢复操作:发生在渲染到纹理,纹理又没有被提前清空或销毁的情况下。
  45. accumulationTexture.MarkRestoreExpected();
  46. material.SetFloat("_BlurAmount", 1.0f - blurAmount);
  47.  
  48. Graphics.Blit(src, accumulationTexture, material);//叠加图像
  49. Graphics.Blit(accumulationTexture, dest);//渲染到屏幕上
  50. }
  51. else
  52. {
  53. Graphics.Blit(src, dest);
  54. }
  55. }
  56. }

2222.png

运行效果

11111.png

标签: Shader

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号