Shader学习21——基于菲涅尔透明的扫描线

看到人家这样的一个效果,于是想自己也复制一个

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"
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值