看到人家这样的一个效果,于是想自己也复制一个
Mar-26-2021 17-16-26.gif
想了一下思路,应该是菲涅尔的做的一个透明效果(单纯的菲涅尔透明可以看这篇),再去做了一个线的效果,线应该可以用纹理做性能更好,但本篇用计算做了个线。最终效果如下
Mar-26-2021 17-21-35.gif
代码如下:
Shader "Class/简单应用/扫描线透明菲涅尔"
{
Properties{
_Speed("Speed", Float) = 1 //扫描线移动速度
//扫描线位置
_DiscardFactor("DiscardFactor",Range(-2,2)) = 0.0
//扫描线移动方向
[KeywordEnum(LeftRight, UpDown, Around)] _Dir("Dir", Float) = 0
//扫描线移动顺序-正反
[KeywordEnum(JUST, BACK)] _ORDER("ORDER", Float) = 0
//切口光的颜色
_LightColor("LightColor",Color) = (1,1,1,1)
//光的宽度
_LightWidth("LightWidth",Range(0.0,0.1))=0.05
_RimColor("RimColor", Color) = (1,1,1,1) //边缘光颜色
_RimPower("RimPower",Range(0,2)) =0 //边缘光强度
}
SubShader{
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass {
// 只有定义了正确的LightMode才能得到一些Unity的内置光照变量
Tags { "LightMode"="ForwardBase"}
LOD 200
Blend SrcAlpha One //开启Blend混合,设置源颜色和目标颜色混合因子,混合模式可以多尝试,会有不同的效果
CGPROGRAM
#include "UnityCG.cginc"
// 包含unity的内置的文件,才可以使用Unity内置的一些变量
#pragma vertex vert
#pragma fragment frag
//设定宏定义
#pragma multi_compile _DIR_LEFTRIGHT _DIR_UPDOWN _DIR_AROUND
#pragma multi_compile _ORDER_JUST _ORDER_BACK
float _Speed;
float _DiscardFactor;
float4 _LightColor;
float _LightWidth;
fixed4 _RimColor;
float _RimPower;
struct a2v
{
float4 vertex : POSITION; // 告诉Unity把模型空间下的顶点坐标填充给vertex属性
float3 normal : NORMAL; // 不再使用模型自带的法线。保留该变量是因为切线空间是通过(模型里的)法线和(模型里的)切线确定的。
};
struct v2f
{
float4 vertex : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
float3 normal : NORMAL;
float3 worldPos:TEXCOORD0;
float3 viewDir : TEXCOORD1;
};
// 计算顶点坐标从模型坐标系转换到裁剪面坐标系
v2f vert(a2v v)
{
v2f o;
//顶点坐标转换
// 该步骤用来把一个坐标从模型空间转换到剪裁空间
o.vertex = UnityObjectToClipPos(v.vertex);
//获取法线(把法线方向从模型空间转换到世界空间)。
o.normal = UnityObjectToWorldNormal(v.normal);
//顶点坐标转世界坐标
o.worldPos= mul(unity_ObjectToWorld, v.vertex).xyz;
//世界空间中从该点到摄像机的观察方向
o.viewDir = normalize(UnityWorldSpaceViewDir(o.worldPos));
return o;
}
fixed4 frag(v2f i) : SV_Target
{
/**************************根据时间移动线******************************/
float time = 2-fmod(_Time.z*_Speed , 4);
_DiscardFactor=time;
/********************************************************/
/**************************扫描线位置******************************/
float factor =0;
#if defined(_DIR_LEFTRIGHT)
factor = i.worldPos.x;
#elif defined(_DIR_UPDOWN)
factor = i.worldPos.y;
#elif defined(_DIR_AROUND)
factor = i.worldPos.z;
#endif
/********************************************************/
/**************************实现扫描线******************************/
fixed4 linecol=fixed4(0.0,0.0,0.0,0.0);
#if defined(_ORDER_JUST)
//factor<_DiscardFactor的部分已经被裁减,剩下的部分在加个边界做切面的描边
if (factor>_DiscardFactor&&factor < _DiscardFactor+_LightWidth)
//从边界逐渐过度
linecol= _LightColor*smoothstep(_DiscardFactor+_LightWidth,_DiscardFactor,factor);
#elif defined(_ORDER_BACK)
if (factor*-1>_DiscardFactor&&factor*-1< _DiscardFactor+_LightWidth)
linecol= _LightColor*(1-smoothstep(_DiscardFactor+_LightWidth,_DiscardFactor,factor*-1));
#endif
/********************************************************/
/**************************边缘光实现******************************/
//摄像机角度
float3 view = normalize(i.viewDir);
//摄像机入射角度和法线点乘,得出摄像机和法线的角度关系
float NdotV = dot(i.normal,view);
//菲涅尔 越接近边缘_RimPower - NdotV越大,然后筛除<0的数,乘以颜色
float3 fresnel = _RimColor * saturate(_RimPower - NdotV)+linecol;
/********************************************************/
float alpha=smoothstep(0.0,0.5,(fresnel.r+fresnel.g+fresnel.b)*0.333);
return fixed4(fresnel,alpha); //色彩叠加后与贴图颜色相乘
}
ENDCG
}
}
FallBack "Diffuse"
}