ShaderLab实现Vignette过场动画效果

博客 分享
0 186
优雅殿下
优雅殿下 2022-02-25 11:55:57
悬赏:0 积分 收藏

ShaderLab实现Vignette过场动画效果

实现Vignette过场动画效果

postprocessing中有渐晕效果(Vignette),镜头可以由边缘往中间慢慢变黑;

但是我打包WebGL的时候提示我postprocessing,GPU不支持...

so,用shaderlab实现了简单的效果,如果需要边缘模糊,就根据距离做透明度插值;

以下是效果展示:

PostEffectsBase

提供公共方法,所有的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;		}	}}

MyVignette

根据屏幕大小,在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);    }}

VignetteShader

_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的值,就可以实现圆镜头效果;

Life is too short for so much sorrow.  
posted @ 2022-02-25 11:50 小紫苏 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员