postprocessing中有渐晕效果(Vignette),镜头可以由边缘往中间慢慢变黑;
但是我打包WebGL的时候提示我postprocessing,GPU不支持...
so,用shaderlab实现了简单的效果,如果需要边缘模糊,就根据距离做透明度插值;

提供公共方法,所有的postprocess后期效果都继承该类;
Start方法中检查设备是否支持后期效果;
CheckShaderAndCreateMaterial方法检测是否支持shader,支持则创建并返回该shader的对应材质;
[ExecuteInEditMode][RequireComponent (typeof(Camera))]public class PostEffectsBase : MonoBehaviour { // Called when start protected void CheckResources() { bool isSupported = CheckSupport(); if (isSupported == false) { NotSupported(); } } // Called in CheckResources to check support on this platform protected bool CheckSupport() { if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false) { Debug.LogWarning("This platform does not support image effects or render textures."); return false; } return true; } // Called when the platform doesn't support this effect protected void NotSupported() { enabled = false; } protected virtual void Start() { CheckResources(); } // Called when need to create the material used by this effect protected Material CheckShaderAndCreateMaterial(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; } }}根据屏幕大小,在shader的着色阶段,判断片元离屏幕中心距离和预设的半径比较,超过的全部设置成黑色(或其他);
预设半径最大值为屏幕对角线的一半;
Unity屏幕(0,0)点左下角;
温馨提示:如果要同时覆盖UI,canvas的模式不能是overlay,必须改成Camera,同时UI相机要为该脚本挂载的相机;
OnRenderImage(RenderTexture source, RenderTexture destination)
该方法为MonoBehaviour生命周期,会将屏幕渲染结果source返回,函数结束会将destination显示在屏幕上;
Graphics.Blit(source, destination, material,pass)
将source经过材质material处理后,返回destination;
pass默认为-1,计算所有pass;否则只调用索引值;
public class MyVignette : PostEffectsBase{ public Shader vignetteShader; private Material vignetteMaterial; [Range(0, 1)] public float radio = 1; public Color circleColor = Color.black; public Vector2 screenSize; protected override void Start() { base.Start(); screenSize = FindObjectOfType<CanvasScaler>().referenceResolution; material.SetColor("_Color", circleColor); //计算屏幕对角线一半的长度 float temp = Mathf.Sqrt(screenSize.x * screenSize.x + screenSize.y * screenSize.y)/2; material.SetFloat("_ScreenSize", temp); material.SetVector("_CenterPos", screenSize/2); } public Material material { get { vignetteMaterial = CheckShaderAndCreateMaterial(vignetteShader, vignetteMaterial); return vignetteMaterial; } } private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (material != null) { material.SetFloat("_Radio", radio); Graphics.Blit(source, destination, material); } else Graphics.Blit(source, destination); }}_MainTex 接收屏幕纹理
_Radio 接收半径变动
在MyVignette类中给Shader属性赋值,所以其实Properties中可以不用写(不用在材质中看这些值),直接pass中声明;
Shader "VignetteShader"{ Properties { _MainTex ("Texture", 2D) = "white" {} _Radio("Radio",Range(0,1.0)) = 1.0 _ScreenSize("ScreenSize",Float) = 735 _CenterPos("CenterPos",vector) = (640,360,1) _Color("CircleColor",Color) = (0,0,0,1) } SubShader { Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; fixed _Radio; fixed _ScreenSize; float4 _CenterPos; float4 _Color; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); //减少开方操作 float temp = (i.vertex.x - _CenterPos.x)* (i.vertex.x - _CenterPos.x)+(i.vertex.y-_CenterPos.y)*(i.vertex.y-_CenterPos.y); _ScreenSize = _ScreenSize*_Radio; if(temp>_ScreenSize*_ScreenSize) col = _Color; return col; } ENDCG } }}主相机上挂在MyVigentte脚本,给MyVigentte参数赋值,将VignetteShader拖到MyVigentte中shader变量;
通过CanvasScaler获取屏幕宽高,Canvas的RenderMode设置成Screen Space-Camera;


代码修改MyVignette中Radio的值,就可以实现圆镜头效果;