屏幕后效果指的是, 当前整个场景图已经渲染完成输出到屏幕后, 再对输出的屏幕图像进行的操作.
在 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 并创建临时材质:
脚本如下:
- using UnityEngine;
- [ExecuteInEditMode]
- // 屏幕后处理效果主要是针对摄像机进行操作, 需要绑定摄像机
- [RequireComponent(typeof(Camera))]
- public class ScreenEffectBase : MonoBehaviour
- {
- public Shader shader;
- private Material material;
- protected Material Material
- {
- get
- {
- material = CheckShaderAndCreatMat(shader, material);
- return material;
- }
- }
- // 用于检查并创建临时材质
- private Material CheckShaderAndCreatMat(Shader shader, Material material)
- {
- Material nullMat = null;
- if (shader != null)
- {
- if (shader.isSupported)
- {
- if (material && material.shader == shader){ }
- else
- {
- material = new Material(shader){ hideFlags = HideFlags.DontSave };
- }
- return material;
- }
- }
- return nullMat;
- }
- }
之后创建的屏幕后处理效果的控制脚本都可以继承自该基类, 例如我们创建关于基本颜色校正的控制脚本:
- using UnityEngine;
- public class ColorCorrectionCtrl : ScreenEffectBase
- {
- private const string _Brightness = "_Brightness";
- private const string _Saturation = "_Saturation";
- private const string _Contrast = "_Contrast";
- [Range(0, 3)]
- public float brightness = 1.0f;
- [Range(0, 3)]
- public float saturation = 1.0f;
- [Range(0, 3)]
- public float contrast = 1.0f;
- private void OnRenderImage(RenderTexture source, RenderTexture destination)
- {
- if (Material!=null)
- {
- Material.SetFloat(_Brightness, brightness);
- Material.SetFloat(_Saturation, saturation);
- Material.SetFloat(_Contrast, contrast);
- Graphics.Blit(source, destination, Material);
- }
- else
- Graphics.Blit(source, destination);
- }
- }
其中, brightness,saturation,contrast 分别为调整参数 -- 亮度, 饱和度和对比度,_Brightness,_Saturation,_Contrast 为之后对应的 shader 中需要相应定义的属性参数.
这里利用构建的材质 Material 对 shader 的属性赋值并调用 Graphics.Blit 进行屏幕后效果的处理.
具体实现颜色校正的 shader 如下:
- Shader "MyUnlit/ColorCorrection"
- {
- Properties
- {
- // 这里的参数主要用于展示在材质面板中进行调节, 但因为这次是临时创建的材质, 参数都已经放在了 C# 脚本中调整, 因此相对应的参数都可以省略
- _MainTex ("Texture", 2D) = "white" {}
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- Pass
- {
- //OnRenderImage 的调用可能会发生在渲染透明物体之前, 为了不影响之后透明物体的渲染, 需要: 开启深度测试 + 双面渲染 + 关闭深度写入
- ZTest always
- Cull off
- ZWrite off
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- #pragma multi_compile_fog
- #include "UnityCG.cginc"
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv : TEXCOORD0;
- };
- struct v2f
- {
- float2 uv : TEXCOORD0;
- UNITY_FOG_COORDS(1)
- float4 vertex : SV_POSITION;
- };
- sampler2D _MainTex;
- half _Brightness;
- half _Saturation;
- half _Contrast;
- v2f vert (appdata v)
- {
- v2f o;
- o.vertex = UnityObjectToClipPos(v.vertex);
- // 因为是临时创建的材质, 这里不需要对纹理进行任何变换操作 (无可操作的材质面板), 直接传递即可,_MainTex_ST 也不需要定义
- o.uv = v.uv;
- UNITY_TRANSFER_FOG(o,o.vertex);
- return o;
- }
- fixed4 frag (v2f i) : SV_Target
- {
- fixed4 col = tex2D(_MainTex, i.uv);
- // 亮度计算直接叠加
- fixed3 color = col.rgb*_Brightness;
- // 饱和度和灰度有关, 先计算最低灰度系数下的图像, 随后对原始的图像进行插值操作
- fixed3 gray = fixed3(0.2125, 0.7154, 0.0721);
- // 点积得到最低灰度值, 构成最低灰度图像
- fixed minGray = dot(gray, col.rgb);
- fixed3 grayColor = fixed3(minGray, minGray, minGray);
- // 对灰度图像和原始图像插值操作以得到最终系数的显示图像
- color = lerp(grayColor, color, _Saturation);
- // 对比度效果类似, 先计算最低对比度图像, 即 (0.5,0.5,0.5), 随后插值操作
- fixed3 minContrast = fixed3(0.5, 0.5, 0.5);
- color = lerp(minContrast, color, _Contrast);
- // 得到所有处理完成后的图像颜色, 但 alpha 保持不变
- fixed4 finColor = fixed4(color, col.a);
- UNITY_APPLY_FOG(i.fogCoord, finColor);
- return finColor;
- }
- ENDCG
- }
- }
- // 关闭回调
- fallback off
- }
效果如下 (随便调的不用在意~):
来源: https://www.cnblogs.com/koshio0219/p/11131619.html