读一读

Shader "chicai/Circle"
{
    Properties {
        _Value("Value",float) = 0.5
        _Controll("Vector",vector) = (0,0,0,0)
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex:POSITION;
                fixed2 uv:TEXCOORD0;
            };

            struct v2f
            {
                float4 position:SV_POSITION;
                fixed2 uv:TEXCOORD0;
            };

            float _Value;
            half4 _Controll;

            v2f vert(appdata IN)
            {
                v2f o = (v2f)0; //初始化 有些平台要求
                o.position = UnityObjectToClipPos(IN.vertex);
                o.uv = IN.uv;
                return o;
            }

            float4 frag(v2f IN):SV_TARGET
            {
                //length(IN.uv.xy-0.5) 中心向四周变化
                //step 中心为1 以外为0 变成纯色圆形
                //return step(length(IN.uv.xy-0.5), _Value);

                //边缘平滑的中心圆计算
                return smoothstep(_Controll.x ,_Controll.y, length(IN.uv.xy - 0.5));
            }
            ENDCG
        }
    }
}



abs(-1.2) //1.2 绝对值
frac(2.5) //0.5  取小数
floor(0.5) //0 向下取整
ceil(0.5) //1 向上取整
max(0.1,0.3) //0.3 取最大值,用来提亮暗部
min(0.1,0.3) //0.1 取最小值,用来降低亮度
pow(0.1,2) //0.01 幂次方
rcp(0.1) //10 倒数
exp(2) //e的2次方
exp2(2) //4 2的2次方
fmod(0.1,0.2) //0 取余 同0.1%0.2
saturate(x) //限制在0到1范围
clamp(x,min,max) //x限制在min到max范围
sqrt(0.01) //0.1 去平方根
rsqrt(0.01) //10 去平方根的倒数
lerp(a,b,t) //a到b的插值 t(0,1)
sin(x) //正弦
cos(x) //余弦
distance(a,b) //a和b之间的距离
length(a) //向量a的长度
step(a,b) //a<=b 返回1,否则0
smoothstep(min,max,x) //平滑过渡 x小于mix为0 x大于max则为1,之间为平滑在0到1



//Properties
[Toggle]_DissolveEnable("Dissolve Enable",int) = 0
[MaterialToggle(MASKENABLE)]_MaskEnable("Mask Enable",int) = 0
//Pass
#pragma multi_compile _ _DISSOLVEENABLE_ON  //对应_DissolveEnable 无论如何都会编译
//#pragma shader_feature _ _DISSOLVEENABLE_ON ////对应_DissolveEnable 根据使用情况编译
#pragma shader_feature _ MASKENABLE////对应MASKENABLE 根据使用情况编译
#if _DISSOLVEENABLE_ON
#endif




Unity中相机的捕获宽高会随着目标视口的宽高比率保持一致,所以不会变形。

可以调整Game视图的比例,观察相机的视锥的改变。


Shader "Unlit/Matcap"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Matcap("Mapcap",2D) = "white"{}
        _MatcapPower("MatcapPower", Float) = 2
        _MatcapAdd("MapcapAdd",2D) = "white"{}
        _MatcapAddPower("MatcapAddPower", Float) = 2
        _RampTex("RampTex",2D) = "white"{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM 
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal :NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 normal_world:TEXCOORD1;
                float3 pos_world:TEXCOORD2;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _Matcap;
            float _MatcapPower;
            sampler2D _MatcapAdd;
            float _MatcapAddPower;
            sampler2D _RampTex;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.normal_world = mul(float4(v.normal,0), unity_WorldToObject);
                o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //主贴图
                float4 tex_color = tex2D(_MainTex,i.uv);

                //Matcap 计算采样的uv  使用
                float3 normal_world = normalize(i.normal_world);
                float3 normal_view = mul(UNITY_MATRIX_V, float4(normal_world,0));
                float2 map_cap_uv = (normal_view.xy + float2(1,1)) * 0.5;
                float4 mapcap_color = tex2D(_Matcap, map_cap_uv) * _MatcapPower;

                //叠加的 Matcap
                float4 matcap_add = tex2D(_MatcapAdd, map_cap_uv) * _MatcapAddPower; 

                //用菲涅尔来采样渐变图 1-0
                float3 view_world = normalize(_WorldSpaceCameraPos.xyz - i.pos_world);
                half NdotV = saturate(dot(normal_world,view_world));
                half sample = 1 - NdotV;
                float4 ramp_color = tex2D(_RampTex, float2(sample,sample));

                float4 final_color = mapcap_color * tex_color * ramp_color + matcap_add;
                return final_color;
            }
            ENDCG
        }
    }
}



image.png


Matcap贴图

matcap_glass02.png

matcap_glass.png


Shader "Unlit/Scan"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _RimMin("RimMin", Range(-1,1)) = 0.0
        _RimMax("RimMax",Range(0,2)) = 0.0
        _InnerColor("Inner Color",Color) = (0.0,0.0,0.0,0.0)
        _RimColor("Rim Color",Color) = (0.0,0.0,0.0,0.0)
        _RimIntensity("Rim Intensity",Float) = 1.0
        _FlowSpeed("Flow Speed",Float) = 1
        _Alaph("Alaph", Float) = 0.75
        _EmissPower("Emiss Power", Float) = 2 

        _FlowTex("Flow Texture",2D) = "white"{}//扫光贴图
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" }
        LOD 100

        Pass
        {
            ZWrite On
            ColorMask 0
        }

        Pass
        {
            ZWrite Off
            Blend SrcAlpha One

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                float3 normal:TEXCOORD1;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normal_world :TEXCOORD1;
                float3 pos_world:TEXCOORD2;
                float3 pivot_world:TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _RimMin;
            float _RimMax;
            float4 _InnerColor;
            float4 _RimColor;
            float _RimIntensity;
            float _FlowSpeed;
            sampler2D _FlowTex;
            float _Alaph;
            float _EmissPower;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.normal_world = mul(float4(v.normal,0.0), unity_WorldToObject);//世界法线
                o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.pivot_world = mul(unity_ObjectToWorld, float4(0,0,0,1));//模型中心点的世界坐标
                o.uv = v.texcoord;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //边缘光
                half3 normal_world = normalize(i.normal_world);
                half3 view_world = normalize(_WorldSpaceCameraPos.xyz - i.pos_world);
                half  NdotV = saturate(dot(normal_world, view_world));
                half fresnel = 1 - NdotV;
                fresnel = smoothstep(_RimMin,_RimMax, fresnel);
                half emiss = tex2D(_MainTex, i.uv).r;//模型贴图的R通道作自发光
                emiss = pow(emiss, _EmissPower);

                half final_fresnel = saturate(fresnel + emiss);
                half3 final_rim_color = lerp(_InnerColor, _RimColor * _RimIntensity, fresnel);
                half final_rim_alpha = final_fresnel;

                //扫光 用xy坐标来取值贴图 减去模型中心点不受自身位置影响
                half2 uv_flow = (i.pos_world.xy - i.pivot_world.xy);
                uv_flow = uv_flow + _Time.y * _FlowSpeed;
                float4 flow_rgba = tex2D(_FlowTex, uv_flow);

                float3 final_col = final_rim_color + flow_rgba.xyz;
                float final_alpha = final_rim_alpha + _Alaph;
                return fixed4(final_col,final_alpha);
            }
            ENDCG
        }
    }
}



录制_2023_10_31_14_10_27_15120231031142071.gif



可以用一张渐变图和一张噪声图,一个圆形的模型,通过透明测试制作效果。

Shader "Clip/Bo" 
{
	
	Properties 
	{
		_MainTex ("Texture", 2D) = "" {}
		_MainColor("Main Color",Color) = (1,1,1,1)
		_NoiseMap("NoiseMap", 2D) = "" {}
		_Cutout("Cutout", Range(0.0,1.1)) = 0.0
		_Speed("Speed", Vector) = (.34, .85, .92, 1)
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" "DisableBatching"="True"} 
		Pass 
		{
			CGPROGRAM 
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc" 
			struct appdata 
			{
				float4 vertex : POSITION; 
				half2 texcoord0 : TEXCOORD0; 
			};

			struct v2f  
			{
				float4 pos : SV_POSITION;
				float4 uv : TEXCOORD0; 
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float _Cutout;
			float4 _Speed;
			sampler2D _NoiseMap;
			float4 _NoiseMap_ST;
			float4 _MainColor;
			
			//顶点Shader
			v2f vert (appdata v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv.xy = TRANSFORM_TEX(v.texcoord0, _MainTex);
				o.uv.zw = TRANSFORM_TEX(v.texcoord0, _NoiseMap);
				return o;
			}
			//片元Shader
			half4 frag (v2f i) : SV_Target 
			{
				half gradient = tex2D(_MainTex, i.uv.xy + _Time.y * 0.1f * _Speed.xy).r * (1.0 - i.uv.y);
				half noise = 1.0 - tex2D(_NoiseMap, i.uv.zw + _Time.y * 0.1f * _Speed.zw).r;
				clip(gradient - noise -  _Cutout);
				return _MainColor;
			}
			ENDCG
		}
	}
}



look.gif



Gradient03Repeat.png


NoiseClassic01.png




// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "Custom/FlowLightShader"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)

        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255

        _ColorMask ("Color Mask", Float) = 15
        
        //ADD---------
        lightTime("Light Time", Float) = 0.6
        thick("Light Thick", Float) = 0.3
        nextTime("Next Light Time", Float) = 2
        angle("Light Angle", int) = 45
        //ADD---------

        [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Stencil
        {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend SrcAlpha OneMinusSrcAlpha
        ColorMask [_ColorMask]

        Pass
        {
            Name "Default"
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"
            #include "UnityUI.cginc"

            #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
            #pragma multi_compile_local _ UNITY_UI_ALPHACLIP

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                float2 texcoord  : TEXCOORD0;
                float4 worldPosition : TEXCOORD1;
                float4  mask : TEXCOORD2;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            fixed4 _Color;
            fixed4 _TextureSampleAdd;
            float4 _ClipRect;
            float4 _MainTex_ST;
            float _UIMaskSoftnessX;
            float _UIMaskSoftnessY;
            
            //ADD---------
            half lightTime;
            int  angle;
            float thick;
            float nextTime;
            //ADD---------

            v2f vert(appdata_t v)
            {
                v2f OUT;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
                float4 vPosition = UnityObjectToClipPos(v.vertex);
                OUT.worldPosition = v.vertex;
                OUT.vertex = vPosition;

                float2 pixelSize = vPosition.w;
                pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));

                float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
                float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);
                OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
                OUT.mask = float4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy)));

                OUT.color = v.color * _Color;
                return OUT;
            }

            fixed4 frag(v2f IN) : SV_Target
            {
                half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);

            //ADD---------
            fixed currentTimePassed = fmod(_Time.y, lightTime + nextTime);
            fixed x = currentTimePassed / lightTime;//0-1为扫光时间 >1为等待时间
            fixed tanx = tan(0.0174*angle);// uv-y/uv-x  0.0174为3.14/180
            x += (x-1)/tanx;//保证能从头扫到尾
            fixed x1 = IN.texcoord.y /tanx + x;//用uv-y来计算倾斜的uv-x
            fixed x2 = x1 + thick;//范围
            if(IN.texcoord.x > x1 && IN.texcoord.x < x2)
            {
               fixed dis = abs(IN.texcoord.x-(x1+x2)/2);//距离扫光当前x中心点的距离
               dis = 1-dis*2/thick;//越中心越大
               half ca = color.a;
               color += color*(1.4*dis);//颜色加强
               color.a = ca;
            }
            //ADD---------

                #ifdef UNITY_UI_CLIP_RECT
                half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw);
                color.a *= m.x * m.y;
                #endif

                #ifdef UNITY_UI_ALPHACLIP
                clip (color.a - 0.001);
                #endif

                return color;
            }
        ENDCG
        }
    }
}


在官网对应的unity版本下下载build in shaders,找到UI-Default.shader,添加标志了ADD---------的代码,创建新的材质,赋值给Image的材质就可以了。


Shader "Custom/RubCard" {
Properties {
   _Color ("Main Color", Color) = (1,1,1,1)//Tint Color
   _MainTex ("Base (RGB)", 2D) = "white" {}
   _MainTex_2 ("Base (RGB)", 2D) = "white" {}
   ratioY ("ratioY", Float) = 0
   radius ("radius", Float) = 0
   height ("height", Float) = 0
   anchorY ("anchorY", Float) = 0
   rubOffset ("rubOffset", Float) = 0
   maxRubAngle ("maxRubAngle", Float) = 0
   _ZOffsetOne("ZOffsetOne",Float)=0
   _ZOffsetTwo("ZOffsetTwo",Float)=0
   _Move("Move",Float)=0
}
 
SubShader {
   Tags {"Queue"="Geometry"  "RenderType"="Opaque" }
   LOD 100
   
   Pass {
      Name "ONE"
      Tags{"LightMode" = "UniversalForward"}
      Cull Front
      Lighting Off

        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
         
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _Color;
            float ratioY;
            float radius;
            float height;
            float anchorY;
            float rubOffset;
            float maxRubAngle;
            float _ZOffsetOne;
            float _Move;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            
            v2f vert (appdata v)
            {
                v2f o;
                float4 tmp_pos = v.vertex;
                float tempAngle = 1.0;

        
                tmp_pos.xyz = mul(unity_ObjectToWorld,float4(tmp_pos.xyz,0)).xyz;
                float pi = 3.14159;
                float halfPeri = radius * pi * maxRubAngle; 
                float rubLenght = height * (ratioY - anchorY);
                tmp_pos.y += height*rubOffset;
                float tempPosY = tmp_pos.y;
                if(tmp_pos.y < rubLenght)
                {
                        float dy = (rubLenght - tmp_pos.y);
                    if(rubLenght - halfPeri < tmp_pos.y)
                    {
                        float angle = dy/radius;
                        tmp_pos.y = rubLenght -  sin(angle)*radius;
                        tmp_pos.z = radius * (1.0- cos(angle)); 
                    }
                    else
                    {
                        float tempY = rubLenght  - halfPeri - tmp_pos.y;
                        float tempAngle = pi * (1.0-maxRubAngle);
                        tmp_pos.y = rubLenght - radius*sin(tempAngle) + tempY * cos(tempAngle);
                        tmp_pos.z = radius + radius*cos(tempAngle) + tempY * sin(tempAngle);

                    }

                }
                tmp_pos.x += unity_ObjectToWorld[3][0];
                tmp_pos.y += unity_ObjectToWorld[3][1];
                tmp_pos.z += unity_ObjectToWorld[3][2];

                
                float4 pos = mul(UNITY_MATRIX_VP, tmp_pos);


                float tempOffset = _ZOffsetOne * pos.w;
                if (tempPosY < rubLenght )
                {
                    float dy = (rubLenght - tempPosY);
                    if( dy > pi * radius)
                    {
                        tempOffset = -tempOffset*2.0;
                    }
                }

                pos.z = pos.z + tempOffset;
                pos.x += _Move;

                o.vertex = pos;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv.x = 1 - o.uv.x;//对uv的x取反
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {

                fixed4 col = tex2D(_MainTex, i.uv);
                clip (col.a - 0.5);
                return col * _Color;
            }
            ENDCG
   }

     Pass
        {
            Name "TWO"
          Cull Back
          Lighting Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

         

            sampler2D _MainTex_2;
            float4 _MainTex_2_ST;
            fixed4 _Color;
            float ratioY;
            float radius;
            float height;
            float anchorY;
            float rubOffset;
            float maxRubAngle;
            float _ZOffsetTwo;
            float _Move;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            
            v2f vert (appdata v)
            {
                v2f o;
                float4 tmp_pos = v.vertex;
                float tempAngle = 1.0;

        
                tmp_pos.xyz = mul(unity_ObjectToWorld,float4(tmp_pos.xyz,0)).xyz;
                //tmp_pos.xyz = (modelMatrix * vec4(tmp_pos.xyz, 0.0)).xyz;
                float pi = 3.14159;
                float halfPeri = radius * pi * maxRubAngle; 
                float rubLenght = height * (ratioY - anchorY);
                tmp_pos.y += height*rubOffset;
                float tempPosY = tmp_pos.y;
                if(tmp_pos.y < rubLenght)
                {
                        float dy = (rubLenght - tmp_pos.y);
                    if(rubLenght - halfPeri < tmp_pos.y)
                    {
                        float angle = dy/radius;
                        tmp_pos.y = rubLenght -  sin(angle)*radius;
                        tmp_pos.z = radius * (1.0- cos(angle)); 
                    }
                    else
                    {
                        float tempY = rubLenght  - halfPeri - tmp_pos.y;
                        float tempAngle = pi * (1.0-maxRubAngle);
                        tmp_pos.y = rubLenght - radius*sin(tempAngle) + tempY * cos(tempAngle);
                        tmp_pos.z = radius + radius*cos(tempAngle) + tempY * sin(tempAngle);

                    }

                }
                tmp_pos.x += unity_ObjectToWorld[3][0];
                tmp_pos.y += unity_ObjectToWorld[3][1];
                tmp_pos.z += unity_ObjectToWorld[3][2];

                
                float4 pos = mul(UNITY_MATRIX_VP, tmp_pos);


                float tempOffset = _ZOffsetTwo * pos.w;
                if (tempPosY < rubLenght )
                {
                    float dy = (rubLenght - tempPosY);
                    if( dy > pi* radius)
                    {
                        tempOffset = -tempOffset * 2.0;
                    }
                }
                pos.z = pos.z + tempOffset;
                pos.x += _Move;

                o.vertex = pos;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex_2);
                o.uv.x = 1 - o.uv.x;//对uv的x取反
                o.uv.y = 1 - o.uv.y;//对uv的y取反
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex_2, i.uv);
                clip (col.a - 0.5);
                return col * _Color;
            }
            ENDCG
        }

    
}
}


注意:URP要渲染多通道的shader,需要确保有个pass打上UniversalForward的tag,其余pass有SRPDefaultUnlit的tag也行,没有也行

shader将模型坐标转换为世界坐标,所以普通的移动不会影响位置,需要调节shader的参数做偏移,调节参数把牌摆好,设置好角度和相机角度。