屏幕后效果指的是,当前整个场景图已经渲染完成输出到屏幕后,再对输出的屏幕图像进行的操作。

 

在Unity中,一般过程通常是:

1.建立用于处理效果的shader和临时材质,给shader脚本传递需要控制的参数和变量

2.利用OnRenderImage函数抓取当前屏幕渲染纹理

OnRenderImage(RenderTexture source, RenderTexture destination){  }

第一个参数为处理前纹理,第二个为最终显示纹理

3.在OnRenderImage函数中调用Graphics.Blit方法对抓取的纹理进行具体的后期操作

Graphics.Blit(source, destination, material,-1);

material为需要处理的材质,-1为参数pass的默认值,表示对shader中所有的pass依次调用,这里也可以省略

 

为此,首先可以提前建立一个基类ScreenEffectBase,主要用于检查Shader并创建临时材质:

脚本如下:

  1. 1 using UnityEngine;
  2. 2
  3. 3 [ExecuteInEditMode]
  4. 4 //屏幕后处理效果主要是针对摄像机进行操作,需要绑定摄像机
  5. 5 [RequireComponent(typeof(Camera))]
  6. 6 public class ScreenEffectBase : MonoBehaviour
  7. 7 {
  8. 8 public Shader shader;
  9. 9 private Material material;
  10. 10 protected Material Material
  11. 11 {
  12. 12 get
  13. 13 {
  14. 14 material = CheckShaderAndCreatMat(shader, material);
  15. 15 return material;
  16. 16 }
  17. 17 }
  18. 18
  19. 19 //用于检查并创建临时材质
  20. 20 private Material CheckShaderAndCreatMat(Shader shader, Material material)
  21. 21 {
  22. 22 Material nullMat = null;
  23. 23 if (shader != null)
  24. 24 {
  25. 25 if (shader.isSupported)
  26. 26 {
  27. 27 if (material && material.shader == shader){ }
  28. 28 else
  29. 29 {
  30. 30 material = new Material(shader){ hideFlags = HideFlags.DontSave };
  31. 31 }
  32. 32 return material;
  33. 33 }
  34. 34 }
  35. 35 return nullMat;
  36. 36 }
  37. 37 }

之后创建的屏幕后处理效果的控制脚本都可以继承自该基类,例如我们创建关于基本颜色校正的控制脚本:

  1. 1 using UnityEngine;
  2. 2
  3. 3 public class ColorCorrectionCtrl : ScreenEffectBase
  4. 4 {
  5. 5 private const string _Brightness = "_Brightness";
  6. 6 private const string _Saturation = "_Saturation";
  7. 7 private const string _Contrast = "_Contrast";
  8. 8
  9. 9 [Range(0, 3)]
  10. 10 public float brightness = 1.0f;
  11. 11 [Range(0, 3)]
  12. 12 public float saturation = 1.0f;
  13. 13 [Range(0, 3)]
  14. 14 public float contrast = 1.0f;
  15. 15
  16. 16 private void OnRenderImage(RenderTexture source, RenderTexture destination)
  17. 17 {
  18. 18 if (Material!=null)
  19. 19 {
  20. 20 Material.SetFloat(_Brightness, brightness);
  21. 21 Material.SetFloat(_Saturation, saturation);
  22. 22 Material.SetFloat(_Contrast, contrast);
  23. 23
  24. 24 Graphics.Blit(source, destination, Material);
  25. 25 }
  26. 26 else
  27. 27 Graphics.Blit(source, destination);
  28. 28 }
  29. 29 }

其中,brightness,saturation,contrast分别为调整参数——亮度,饱和度和对比度,_Brightness,_Saturation,_Contrast为之后对应的shader中需要相应定义的属性参数。

这里利用构建的材质Material对shader的属性赋值并调用Graphics.Blit进行屏幕后效果的处理。

 

具体实现颜色校正的shader如下:

  1. 1 Shader "MyUnlit/ColorCorrection"
  2. 2 {
  3. 3 Properties
  4. 4 {
  5. 5 //这里的参数主要用于展示在材质面板中进行调节,但因为这次是临时创建的材质,参数都已经放在了C#脚本中调整,因此相对应的参数都可以省略
  6. 6 _MainTex ("Texture", 2D) = "white" {}
  7. 7 }
  8. 8 SubShader
  9. 9 {
  10. 10 Tags { "RenderType"="Opaque" }
  11. 11
  12. 12 Pass
  13. 13 {
  14. 14 //OnRenderImage的调用可能会发生在渲染透明物体之前,为了不影响之后透明物体的渲染,需要:开启深度测试+双面渲染+关闭深度写入
  15. 15 ZTest always
  16. 16 Cull off
  17. 17 ZWrite off
  18. 18
  19. 19 CGPROGRAM
  20. 20 #pragma vertex vert
  21. 21 #pragma fragment frag
  22. 22 #pragma multi_compile_fog
  23. 23
  24. 24 #include "UnityCG.cginc"
  25. 25
  26. 26 struct appdata
  27. 27 {
  28. 28 float4 vertex : POSITION;
  29. 29 float2 uv : TEXCOORD0;
  30. 30 };
  31. 31
  32. 32 struct v2f
  33. 33 {
  34. 34 float2 uv : TEXCOORD0;
  35. 35 UNITY_FOG_COORDS(1)
  36. 36 float4 vertex : SV_POSITION;
  37. 37 };
  38. 38
  39. 39 sampler2D _MainTex;
  40. 40 half _Brightness;
  41. 41 half _Saturation;
  42. 42 half _Contrast;
  43. 43
  44. 44 v2f vert (appdata v)
  45. 45 {
  46. 46 v2f o;
  47. 47 o.vertex = UnityObjectToClipPos(v.vertex);
  48. 48 //因为是临时创建的材质,这里不需要对纹理进行任何变换操作(无可操作的材质面板),直接传递即可,_MainTex_ST也不需要定义
  49. 49 o.uv = v.uv;
  50. 50 UNITY_TRANSFER_FOG(o,o.vertex);
  51. 51 return o;
  52. 52 }
  53. 53
  54. 54 fixed4 frag (v2f i) : SV_Target
  55. 55 {
  56. 56 fixed4 col = tex2D(_MainTex, i.uv);
  57. 57
  58. 58 //亮度计算直接叠加
  59. 59 fixed3 color = col.rgb*_Brightness;
  60. 60
  61. 61 //饱和度和灰度有关,先计算最低灰度系数下的图像,随后对原始的图像进行插值操作
  62. 62 fixed3 gray = fixed3(0.2125, 0.7154, 0.0721);
  63. 63 //点积得到最低灰度值,构成最低灰度图像
  64. 64 fixed minGray = dot(gray, col.rgb);
  65. 65 fixed3 grayColor = fixed3(minGray, minGray, minGray);
  66. 66 //对灰度图像和原始图像插值操作以得到最终系数的显示图像
  67. 67 color = lerp(grayColor, color, _Saturation);
  68. 68
  69. 69 //对比度效果类似,先计算最低对比度图像,即(0.5,0.5,0.5),随后插值操作
  70. 70 fixed3 minContrast = fixed3(0.5, 0.5, 0.5);
  71. 71 color = lerp(minContrast, color, _Contrast);
  72. 72
  73. 73 //得到所有处理完成后的图像颜色,但alpha保持不变
  74. 74 fixed4 finColor = fixed4(color, col.a);
  75. 75
  76. 76 UNITY_APPLY_FOG(i.fogCoord, finColor);
  77. 77 return finColor;
  78. 78 }
  79. 79 ENDCG
  80. 80 }
  81. 81 }
  82. 82 //关闭回调
  83. 83 fallback off
  84. 84 }

效果如下(随便调的不用在意~):

  1.  

版权声明:本文为koshio0219原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/koshio0219/p/11131619.html