ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ShaderLab实现Vignette过场动画效果

2022-02-25 12:03:14  阅读:227  来源: 互联网

标签:return material vertex 过场 Vignette shader ScreenSize CenterPos ShaderLab


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

标签:return,material,vertex,过场,Vignette,shader,ScreenSize,CenterPos,ShaderLab
来源: https://www.cnblogs.com/littleperilla/p/15935404.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有