Unity Shader 实现透明护盾效果

在这里插入图片描述
这是大致的效果图,图片压得有点糊。我参考了本篇博客 Unity shader护盾特效.
这是原博客展示的图片:
Alt在这里插入图片描述
本例采用了特殊的模型与贴图,原博客里有视频链接的教程,从模型到贴图。
以下是代码

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Summer/Shield"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_ScanTex ("Scan Texture", 2D) = "white" {}
		_Color("Color",Color)=(0,0,0,1)
		_ScanColor("Scan Color",Color)=(0,0,0,1)
		_RimColor("rim color",Color) = (1,1,1,1)//边缘颜色
        _RimPower ("rim power",range(1,10)) = 2//边缘强度
        _FresnelScale("ScanFresnelScale",range(0,1))=0.5
        _ScanSpeed("ScanSpeed",range(0,2))=0.5
        _ScanScale("ScanScale",range(0,1))=0.1

	}
	SubShader
	{
		Tags { "Queue"="Transparent"
			"IgnoreProjector" = "True" //我们不希望任何投影类型材质或者贴图,影响我们的物体或者着色器
			"RenderType" = "Transparent" }
		LOD 100
		ZWrite Off
		Blend SrcAlpha OneMinusSrcAlpha

		CGINCLUDE
		#include "UnityCG.cginc"

		struct appdata
		{
			float4 vertex : POSITION;
			float2 uv : TEXCOORD0;//涉及到了两个UV通道
			float2 scanUV:TEXCOORD1;
			fixed4 color:COLOR;
			float3 normal:NORMAL;
		};

		struct v2f
		{
			float2 uv : TEXCOORD0;
			float4 vertex : SV_POSITION;
			fixed4 vertColor:TEXCOORD1;
			float2 scanUV:TEXCOORD2;
		};

		sampler2D _MainTex;
		float4 _MainTex_ST;
		fixed4 _Color;

		sampler2D _ScanTex;
		float4 _ScanTex_ST;
		fixed4 _ScanColor;
		float _ScanSpeed;

		fixed4 _RimColor;
		float _RimPower;
		fixed _FresnelScale;
		fixed _ScanScale;

		v2f vert (appdata v)
		{
			v2f o;
			o.vertex = UnityObjectToClipPos(v.vertex);
			o.uv = TRANSFORM_TEX(v.uv, _MainTex);
			o.scanUV=TRANSFORM_TEX(v.scanUV,_ScanTex);
			
			float3 V = WorldSpaceViewDir(v.vertex);
			V = mul(unity_WorldToObject,V);//视方向从世界到模型坐标系的转换
			o.vertColor=v.color;
			o.vertColor.r = dot(v.normal,normalize(V));
			o.vertColor.r*=sign(o.vertColor.r);//取正,sign返回其符号,使其计算的漫反射系数为正
			return o;
		}

		fixed4 frag (v2f i) : SV_Target
		{
			fixed4 col = tex2D(_MainTex, i.uv);
			i.scanUV.y+=_Time.y*_ScanSpeed;
			fixed scanF=tex2D(_ScanTex,i.scanUV).a;
			clip(-scanF);
			col=col*i.vertColor.a*_Color;
			fixed fresnel=_FresnelScale+(1-_FresnelScale)*pow((1-i.vertColor.r),_RimPower);
			fixed fresnleAlpha=lerp(0,1,fresnel);
			fixed4 backCol=fixed4(_RimColor.rgb,fresnleAlpha);
			fixed4 fianlColor=(col+backCol)+_ScanColor*scanF;
			return fianlColor;
		}

		v2f vert_Convex(appdata v)
		{

			v2f o;
			o.vertex = UnityObjectToClipPos(v.vertex);
			o.uv = TRANSFORM_TEX(v.uv, _MainTex);
			o.scanUV=TRANSFORM_TEX(v.scanUV,_ScanTex);
			
			float3 V = WorldSpaceViewDir(v.vertex);
			V = mul(unity_WorldToObject,V);//视方向从世界到模型坐标系的转换
			o.vertColor=v.color;
			o.vertColor.r = dot(v.normal,normalize(V));
			o.vertColor.r*=sign(o.vertColor.r);

			float4 pos=mul(UNITY_MATRIX_MV,v.vertex);
			float3 normal=mul((float3x3)UNITY_MATRIX_IT_MV,v.normal);
			normal.z-=0.2;
			pos+=float4(normalize(normal),0)*(_ScanScale);
			o.vertex=mul(UNITY_MATRIX_P,pos);

			return o;
		}

		fixed4 frag_Convex (v2f i) : SV_Target
		{
			fixed4 col = tex2D(_MainTex, i.uv);
			i.scanUV.y+=_Time.y*_ScanSpeed;
			fixed scanF=tex2D(_ScanTex,i.scanUV).a;
			if(scanF==0)
			{
				discard;
			}
			col=col*i.vertColor.a*_Color*(1-i.vertColor.a);
			fixed fresnel=_FresnelScale+(1-_FresnelScale)*pow((1-i.vertColor.r),_RimPower);
			fixed fresnleAlpha=lerp(0,1,fresnel);
			fixed4 backCol=fixed4(_ScanColor.rgb,fresnleAlpha);
			fixed4 fianlColor=col+backCol+fresnleAlpha*_ScanColor;
			return fianlColor;
		}
		ENDCG

		Pass
		{
			Cull Off
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase
			ENDCG
		}

		Pass
		{
			CGPROGRAM
			#pragma vertex vert_Convex
			#pragma fragment frag_Convex
			#pragma multi_compile_fwdbase
			ENDCG
		}
	}
}

主要思路是两个Pass,一个渲染主体,该部分要剔除掉扫描到的部分;第二个Pass渲染扫描部分,即顶点经过偏移(向法线方向突出),该部分剔除未扫描的部分,从而实现一个动态扫描顶点偏移的效果。一开始我想的是一个Pass,在vert里进行扫描图片(扫描图片:一张模拟扫描效果的贴图,类似流光贴图)的采样,然后将该顶点偏移,但后来发现tex2D获取的值不能在vert里使用(我也不知道为什么,一用就报错),最后只能用这种最简单的方式。

第一个Pass部分

			float3 V = WorldSpaceViewDir(v.vertex);
			V = mul(unity_WorldToObject,V);//视方向从世界到模型坐标系的转换
			o.vertColor=v.color;
			o.vertColor.r = dot(v.normal,normalize(V));
			o.vertColor.r*=sign(o.vertColor.r);//取正,sign返回其符号,使其计算的漫反射系数为正
			不用saturate的原因是saturate将小于0的取为,而我关了剔除,这样看到背面就是纯色而没有透明效果
			i.scanUV.y+=_Time.y*_ScanSpeed;
			fixed scanF=tex2D(_ScanTex,i.scanUV).a;//该图是PNG,所以通过a通道便可区分
			clip(-scanF);//剔除alpha大于0的像素
			//菲涅尔效果
			fixed fresnel=_FresnelScale+(1-_FresnelScale)*pow((1-i.vertColor.r),_RimPower);
			fixed fresnleAlpha=lerp(0,1,fresnel);
			fixed4 backCol=fixed4(_RimColor.rgb,fresnleAlpha);

第二个Pass部分

			进行顶点变换,在视角空间下进行沿法线方向的顶点偏移
			float4 pos=mul(UNITY_MATRIX_MV,v.vertex);
			float3 normal=mul((float3x3)UNITY_MATRIX_IT_MV,v.normal);
			normal.z-=0.2;
			pos+=float4(normalize(normal),0)*(_ScanScale);
			o.vertex=mul(UNITY_MATRIX_P,pos);
			剔除Alpha值为零,即未扫描到的像素
			i.scanUV.y+=_Time.y*_ScanSpeed;
			fixed scanF=tex2D(_ScanTex,i.scanUV).a;
			if(scanF==0)
			{
				discard;
			}

好了,这大概就是全部了,感谢你的阅读,如有错误,欢迎举正。

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值