UnityShader之屏幕特效基础
1、什么是屏幕特效
我们这里讲的屏幕特效技术,指的是在渲染完整个场景后得到的屏幕图象的基础上,再对这个屏幕图像做一系列处理,实现出屏幕特效,使用这种技术可以为屏幕画面增添各种风格的艺术效果,比如泛光、景深、模糊等等。
2、unity实现屏幕特效的原理
如上所述,要实现屏幕特效,首先要抓取渲染完整个场景得到的屏幕图像,在unity中,提供了OnRenderImage函数,方便我们进行这样的操作。它的声明如下:MonoBehaviour.OnRenderImage(RenderTexture src,RenderTexture dest);unity会把当前渲染得到的图像存储在第一个参数对应的渲染纹理中,通过自定义的一系列操作后,得到目标渲染纹理(第二个参数中的渲染纹理),目标渲染纹理会最终显示在屏幕上。在OnRenderImage函数中,使用Graphics.Blit函数来对渲染纹理进行处理。这里我们做一个可以改变画面亮度、饱和度、以及对比度的简单屏幕特效。
3、C#脚本实现
//////////////////////////////////////////////////////////////////// // _ooOoo_ // // o8888888o // // 88" . "88 // // (| ^_^ |) // // O\ = /O // // ____/`---'\____ // // .' \\| |// `. // // / \\||| : |||// \ // // / _||||| -:- |||||- \ // // | | \\\ - /// | | // // | \_| ''\---/'' | | // // \ .-\__ `-` ___/-. / // // ___`. .' /--.--\ `. . ___ // // ."" '< `.___\_<|>_/___.' >'"". // // | | : `- \`.;`\ _ /`;.`/ - ` : | | // // \ \ `-. \_ __\ /__ _/ .-` / / // // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // // 佛祖保佑 永无BUG // //////////////////////////////////////////////////////////////////// using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] [RequireComponent(typeof(Camera))] public class ScreenEffect : MonoBehaviour { public Shader effectShader; private Material effectMaterial; public Material EffectMaterial { get { effectMaterial = CreateMaterial(effectShader, effectMaterial); return effectMaterial; } } [Range(0.0f, 3.0f)] public float brightness = 1.0f; //亮度 [Range(0.0f, 3.0f)] public float saturation = 1.0f; //饱和度 [Range(0.0f, 3.0f)] public float contrast = 1.0f; //对比度 void OnRenderImage(RenderTexture src, RenderTexture dest) { if (EffectMaterial != null) { EffectMaterial.SetFloat("_Brightness", brightness); EffectMaterial.SetFloat("_Saturation", saturation); EffectMaterial.SetFloat("_Contrast", contrast); //对渲染纹理进行处理 Graphics.Blit(src, dest, EffectMaterial); } else { Graphics.Blit(src, dest); } } private void Start() { bool isSupported = CheckSupport(); if (isSupported == false) { this.enabled = false; } } // 检测当前平台是否支持屏幕特效 private bool CheckSupport() { if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false) { Debug.LogWarning("当前平台不支持!"); return false; } return true; } // 创建材质 private Material CreateMaterial(Shader shader, Material material) { if (shader == null) { return null; } if (shader.isSupported && material && material.shader == shader) return material; if (!shader.isSupported) { return null; } else { material = new Material(shader); material.hideFlags = HideFlags.DontSave; if (material) return material; else return null; } } }
4、Shader实现
Shader "yzpShader/ScreenEffect" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} //需要处理的渲染纹理 _Brightness ("Brightness", Float) = 1 //亮度 _Saturation("Saturation", Float) = 1 //饱和度 _Contrast("Contrast", Float) = 1 //对比度 } SubShader { Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; half _Brightness; half _Saturation; half _Contrast; struct v2f { float4 pos : SV_POSITION; half2 uv: TEXCOORD0; }; v2f vert(appdata_img v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; return o; } fixed4 frag(v2f i) : SV_Target { fixed4 renderTex = tex2D(_MainTex, i.uv); // 计算亮度改变后的颜色 fixed3 finalColor = renderTex.rgb * _Brightness; // 计算饱和度改变后的颜色 fixed luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b; fixed3 luminanceColor = fixed3(luminance, luminance, luminance); finalColor = lerp(luminanceColor, finalColor, _Saturation); // 计算对比度改变后的颜色 fixed3 avgColor = fixed3(0.5, 0.5, 0.5); finalColor = lerp(avgColor, finalColor, _Contrast); return fixed4(finalColor, renderTex.a); } ENDCG } } Fallback Off }
5、测试结果
首先将C#脚本挂在场景相机上,并将上面写好的shader拖拽到ScreenEffect脚本的effectShader上,修改该脚本的brightness、saturation、contrast值,可以得出下面这样的效果: