Unity Shader 实现抖音摆钟摆动显示不同图片的效果

这个效果我也不太好描述,不知道叫什么,看效果图吧:

这个是前两天刷抖音时看到的效果,所以今天有空来实现一下。

 

实现思路:

1、先选取一个旋转点,然后选定一个一次函数方程.

2、对这个一次函数方程进行旋转,获取新的一次函数方程,计算结果

3、根据结果,在线左边的显示一张图片,在右边的显示另一张图片

4、设置一个周期时间,在这个周期内反复更改角度,即可

具体实现步骤:

1、我先选择一个UV坐标点,这里我选择(0.5,1)这个点,我们叫它旋转点,我们选择一个一次函数方程,y=ax+b,因为这条直线会经过旋转点,且在某一时间会经过(0,0)点,将两点代入,即可求得a和b的值,=>  a=2,b=0;

2、对一次函数绕点(m,n)进行旋转⊙角度,公式为:

顺时针旋转:

a' = (a - tan(⊙)) / (1 + a * tan(⊙));

b' = n - m * a'

逆时针旋转:

a' = (a + tan(⊙)) / (1 - a * tan(⊙));

b' = n - m * a'

 

根据旋转公式,我们可以求得新的a和b,即y = a'x + b'

3、根据新求出的一次函数方程,求出在某点y的坐标下,x的坐标值,然后如果图片的uv.x小于这个值,则显示第一张图片,大于这个值显示第二张图片

 

4、设置一个周期时间,比如1秒钟,然后计算出当前时间需要旋转的一个角度,即可

 

所有的步骤都已讲完,下面是所有的代码代码:

Shader "Unlit/Tiktok_RotChoiceShowTwoTexture"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" { }
        _SecondTex ("second Texture", 2D) = "white" { }
        _line_A_value ("a value", float) = 0.5
        _rot_angle ("rot angle", float) = 50.0
        _rot_center_pos ("旋转中心", vector) = (0.5, 1.0, 0, 0)
        _Cycle_Time ("循环时间", Range(0.1, 10)) = 3.0
        _Min_Angle_value ("最小角度", float) = 0
        _Max_Angle_value ("最大角度", float) = 50.0
    }
    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;
            };
            
            struct v2f
            {
                float2 uv: TEXCOORD0;
                float4 vertex: SV_POSITION;
            };
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _SecondTex;
            float _line_A_value;
            uniform float _rot_angle;
            float4 _rot_center_pos;
            float _Cycle_Time;
            float _Min_Angle_value, _Max_Angle_value;
            //求出是否是右边的像素,根据返回值显示第一张图片还是第二张图片
            bool IsRightPixed(float2 uv, float rotAngle)
            {
                float ang = (UNITY_PI / 180.0) * rotAngle;
                
                float tan_value = tan(ang);
                
                float k1 = (_line_A_value + tan_value) / (1 - _line_A_value * tan_value);
                
                float b1 = _rot_center_pos.y - _rot_center_pos.x * k1;
                
                float x = (uv.y - b1) / k1;
                
                if (x < uv.x)return false;
                
                return true;
            }
            
            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);
                
                fixed4 secondCol = tex2D(_SecondTex, i.uv);
                
                float total_angle = (_Max_Angle_value - _Min_Angle_value);//计算总角度
                float per_second_rot_angle = total_angle / _Cycle_Time;//计算每秒旋转角度
                float time = _Time.y % (_Cycle_Time * 2);
                _rot_angle = _Min_Angle_value + per_second_rot_angle * time;//计算当前角度
                
                if (_rot_angle >= _Max_Angle_value)//如果大于最大限制角度,则需要逆旋转,这样才可以周期摆动
                _rot_angle = _Max_Angle_value * 2 - _rot_angle;
                
                bool isRightPixed = IsRightPixed(i.uv, _rot_angle);
                
                if (isRightPixed)
                {
                    return secondCol;
                }
                
                return col;
            }
            ENDCG
            
        }
    }
}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值