庄懂着色器_L19_顶点动画

庄懂-BoyanTata的个人空间_哔哩哔哩_Bilibili


顶点平移/缩放/旋转/案例动画
顶点平移
在AlphaBlend基础上,追加Y轴向上周期性位移
代码部分
Translation
对一个顶点位置信息做一个处理,这个处理就是顶点动画
这个方法没用常规return返回方法,它的返回值是void
inout : 为这个参数给了一张出入的通行证,后面的参数可以进入Inout做一些操作,然后再跑出去,那这样一个参数它在方法内就可能会被改变,而不需要返回其它的值
顶点平移/核心代码分析
时间乘以一个时间流动的速度,这样我们可以控制动画的快慢,为了保证这个浮点的精度,我们对乘完的结果取余, 然后让时间的流动保持在0-1的区间,但是我们外面用的是一个sin的函数,所以0-1是不行的,我们要让里面的这个值是0-6.283185,所以要乘以一个2π(TWO_PI),乘完2π在用sin这个周期性的函数给括上,它就可以做这样一个周期性的波动,得到这个波动之后,我们还想控制它的波动的范围,所以我们乘以一个范围_MoveRange的变量,这样我们就会得到一个上下起伏的偏移值,我们要把这个偏移值加到原本的Y轴数值上去,这就是一个顶点动画的过程.
Shader "AP01/L19/Translation"
{
    Properties
    {
        _MainTex        ("RGB:颜色 A:透贴", 2d) = "gray"{}
        _Opacity        ("透明度", range(0, 1)) = 0.5
        _MoveRange      ("移动范围", range(0.0, 3.0)) = 1.0
        _MoveSpeed      ("移动速度", range(0.0, 3.0)) = 1.0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"               // 调整渲染顺序
            "RenderType"="Transparent"          // 对应改为Cutout
            "ForceNoShadowCasting"="True"       // 关闭阴影投射
            "IgnoreProjector"="True"            // 不响应投射器
        }

        Pass
        {
            Name "FORWARD"
            Tags { "LightMode"="ForwardBase" }
            Blend One OneMinusSrcAlpha          // 修改混合方式One/SrcAlpha OneMinusSrcAlpha
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

            // 输入参数
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform half _Opacity;
            uniform float _MoveRange;
            uniform float _MoveSpeed;

            // 输入结构
            struct VertexInput
            {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };

            // 输出结构
            struct VertexOutput
            {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };

            // 声明常量
            #define TWO_PI 6.283185
            // 顶点动画方法
            void Translation (inout float3 vertex)
            {
                vertex.y += _MoveRange * sin(frac(_Time.z * _MoveSpeed) * TWO_PI);
            }

            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v)
            {
                VertexOutput o = (VertexOutput)0;
                Translation(v.vertex.xyz);
                o.pos = UnityObjectToClipPos(v.vertex);    // 顶点位置 OS>CS
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);       // UV信息 支持TilingOffset
                return o;
            }

            // 输出结构>>>像素
            half4 frag(VertexOutput i) : COLOR
            {
                half4 var_MainTex = tex2D(_MainTex, i.uv);      // 采样贴图 RGB颜色 A透贴
                half3 finalRGB = var_MainTex.rgb;
                half opacity = var_MainTex.a * _Opacity;
                return half4(finalRGB * opacity, opacity);                // 返回值
            }
            ENDCG
        }
    }
}
顶点缩放
在AlphaBlend基础上,基于模型原点追加周期性缩放
Scaling 
缩放一般都是用乘法,算出它缩放的一个比例,去做一个周期性的变化,再去乘之(平移是加,缩放是乘)
顶点缩放/核心代码分析 
平移是用加法,缩放是用乘法,在一个不希望产生一个例如是-20%的结果,所以想要在原本100%比例大小的范围上去做一个浮动,所以前面要加一个1.0(1.0就是100%)
另外需要在面板上设置为Range,避免滑动过程中出现负向缩放
Shader "AP01/L19/Scaling"
{
    Properties
    {
        _MainTex        ("RGB:颜色 A:透贴", 2d) = "gray"{}
        _Opacity        ("透明度", range(0, 1)) = 0.5
        _ScaleRange     ("缩放范围", range(0.0, 0.5)) = 0.2
        _ScaleSpeed     ("缩放速度", range(0.0, 3.0)) = 1.0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"               // 调整渲染顺序
            "RenderType"="Transparent"          // 对应改为Cutout
            "ForceNoShadowCasting"="True"       // 关闭阴影投射
            "IgnoreProjector"="True"            // 不响应投射器
        }

        Pass
        {
            Name "FORWARD"
            Tags { "LightMode"="ForwardBase" }
            Blend One OneMinusSrcAlpha          // 修改混合方式One/SrcAlpha OneMinusSrcAlpha
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

            // 输入参数
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform half _Opacity;
            uniform float _ScaleRange;
            uniform float _ScaleSpeed;

            // 输入结构
            struct VertexInput
            {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };

            // 输出结构
            struct VertexOutput
            {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };

            // 声明常量
            #define TWO_PI 6.283185
           
            // 顶点动画方法
            void Scaling (inout float3 vertex)
            {
                vertex *= 1.0 + _ScaleRange * sin(frac(_Time.z * _ScaleSpeed) * TWO_PI);
            }

            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v)
            {
                VertexOutput o = (VertexOutput)0;
                Scaling(v.vertex.xyz);
                o.pos = UnityObjectToClipPos(v.vertex);    // 顶点位置 OS>CS
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);       // UV信息 支持TilingOffset
                return o;
            }

            // 输出结构>>>像素
            half4 frag(VertexOutput i) : COLOR
            {
                half4 var_MainTex = tex2D(_MainTex, i.uv);      // 采样贴图 RGB颜色 A透贴
                half3 finalRGB = var_MainTex.rgb;
                half opacity = var_MainTex.a * _Opacity;
                return half4(finalRGB * opacity, opacity);                // 返回值
            }
            ENDCG
        }
    }
}
顶点旋转
在AlphaBlend基础上,基于模型Y轴(竖向)追加周期性旋转
代码部分
以平移为例子,确定了平移的偏移量
我们将平移量作用到顶点数据上去
顶点旋转/核心代码分析
取到时间,对时间做一个速度上的缩放,然后再对其进行取一个余,然后乘一个2π,用这样一个值去驱动Sin函数,得到一个-1到1的波动的数值,然后用-1到1去乘以一个_RotateRange这样一个范围,就得到角度的偏移
对角度的应用,首先将角度转成弧度,方便后面三角函数的运算,因为三角函数取的参数是弧度而不是角度
Shader "AP01/L19/Rotation"
{
    Properties
    {
        _MainTex        ("RGB:颜色 A:透贴", 2d) = "gray"{}
        _Opacity        ("透明度", range(0, 1)) = 0.5
        _RotateRange    ("旋转范围", range(0.0, 45.0)) = 20.0
        _RotateSpeed    ("旋转速度", range(0.0, 3.0)) = 1.0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"               // 调整渲染顺序
            "RenderType"="Transparent"          // 对应改为Cutout
            "ForceNoShadowCasting"="True"       // 关闭阴影投射
            "IgnoreProjector"="True"            // 不响应投射器
        }

        Pass
        {
            Name "FORWARD"
            Tags { "LightMode"="ForwardBase"  }
            Blend One OneMinusSrcAlpha          // 修改混合方式One/SrcAlpha OneMinusSrcAlpha
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

            // 输入参数
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform half _Opacity;
            uniform float _RotateRange;
            uniform float _RotateSpeed;

            // 输入结构
            struct VertexInput
            {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };

            // 输出结构
            struct VertexOutput
            {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };

            // 声明常量
            #define TWO_PI 6.283185

            // 顶点动画方法
            void Rotation (inout float3 vertex)
            {
                float angleY = _RotateRange * sin(frac(_Time.z * _RotateSpeed) * TWO_PI);
                float radY = radians(angleY);
                float sinY, cosY = 0;
                sincos(radY, sinY, cosY);
                vertex.xz = float2
(
                vertex.x * cosY - vertex.z * sinY,
                vertex.x * sinY + vertex.z * cosY
                );
            }
           
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v)
            {
                VertexOutput o = (VertexOutput)0;
                Rotation(v.vertex.xyz);
                o.pos = UnityObjectToClipPos(v.vertex);    // 顶点位置 OS>CS
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);       // UV信息 支持TilingOffset
                return o;
            }

            // 输出结构>>>像素
            half4 frag(VertexOutput i) : COLOR
            {
                half4 var_MainTex = tex2D(_MainTex, i.uv);      // 采样贴图 RGB颜色 A透贴
                half3 finalRGB = var_MainTex.rgb;
                half opacity = var_MainTex.a * _Opacity;
                return half4(finalRGB * opacity, opacity);                // 返回值
            }
            ENDCG
        }
    }
}
假设有一个向量a和b,a是从A指向B的一个向量,b是从A指向D的一个向量,那a+b和a-b分别是?
加法相当于把向量a,AB平移到D的位置,得到一个DC,然后把AD平移到B的位置,得到一个BC,这样就围城了一个平行四边形,那a+b等于从A指向C的向量,就相当于两个向量求它的和,就是将其拼成一个平行四边形,平行四边形的这两个对角一连线就是它们的和,它们另外一个对角就是它们的差,向量的差是指向被减数的,a-b当然是a被减
现在我们的模型是沿Y轴旋转,就当于Y轴上是没有变化的,只有X和Z轴有变化,现在假设模型上有一个点,它的坐标值是(X,Z),然后旋转一个角度theta之后,这个黑色的点就旋转到红色的点上了,我们已知原始点坐标是(X,Z),旋转theta角度之后,红色的坐标值是多少?如果我们知道这个坐标值跟这个旋转角theta的对应关系,代码也就可以写了
先将黑色的点理解为一个向量,这个向量就是从原点指向黑点的一个向量,这个向量的值也就是它的坐标值,然后将这个向量值根据它的X轴坐标和Z轴坐标分成两个向量,原始的向量等于这两个向量相加,很显然是一个平行四边形,这两个向量也同样旋转theta角度之后,就变成了红色的这两个向量,两个红色的向量相加也等于红色的坐标点,可以视作整个坐标系旋转了一个theta角,之前是一个长方形,旋转之后仍然是一个长方形,求原点指向红点的向量,知道红色的两个向量就可以了,红色向量是从黑色向量转过来的,旋转是不改变向量长度的,黑色向量长度是X,那旋转后的红色向量长度仍然是X,红色向量投影到X轴上的长度是CosX,邻边比斜边是Cos,知道斜边的长度,那邻边长度是X乘以Cos_theta,另一条边是对边比斜边,那就是X乘以Sin_theta,那红色坐标就是(X*Cos_theta,X*Sin_theta)
同样的,这个黑色的向量,它的长度就是Z,它旋转之后红色向量长度还是Z,那红色向量投影到X轴上的长度是对边比斜边Sin_theta,它投的是负的象限,就是-Sin_theta,那就是斜边的长度是Z,要乘以一个负的Sin_theta等于这个分量,然后Z轴上的分量是邻边比斜边,就是Z*Cos_theta,最后是分量相加
综合案例_幽灵夜巡
代码部分
核心代码分析
Shader "AP01/L19/AnimGhost"
{
    Properties
    {
        _MainTex        ("RGB:颜色 A:透贴", 2d) = "gray"{}
        _Opacity        ("透明度", range(0, 1)) = 0.5
        _ScaleParams    ("天使圈缩放 X:强度 Y:速度 Z:校正", vector) = (0.2, 1.0, 4.5, 0.0)
        _SwingXParams   ("X轴扭动 X:强度 Y:速度 Z:波长", vector) = (1.0, 3.0, 1.0, 0.0)
        _SwingZParams   ("Z轴扭动 X:强度 Y:速度 Z:波长", vector) = (1.0, 3.0, 1.0, 0.0)
        _SwingYParams   ("Y轴起伏 X:强度 Y:速度 Z:滞后", vector) = (1.0, 3.0, 0.3, 0.0)
        _ShakeYParams   ("Y轴摇头 X:强度 Y:速度 Z:滞后", vector) = (20.0, 3.0, 0.3, 0.0)
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"               // 调整渲染顺序
            "RenderType"="Transparent"          // 对应改为Cutout
            "ForceNoShadowCasting"="True"       // 关闭阴影投射
            "IgnoreProjector"="True"            // 不响应投射器
        }

        Pass
        {
            Name "FORWARD"
            Tags { "LightMode"="ForwardBase" }
            Blend One OneMinusSrcAlpha          // 修改混合方式One/SrcAlpha OneMinusSrcAlpha
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

            // 输入参数
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform half _Opacity;
            uniform float4 _ScaleParams;
            uniform float3 _SwingXParams;
            uniform float3 _SwingZParams;
            uniform float3 _SwingYParams;
            uniform float3 _ShakeYParams;

            // 输入结构
            struct VertexInput
            {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
                float4 color : COLOR;           // 顶点色 遮罩用
            };

            // 输出结构
            struct VertexOutput
            {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
                float4 color : COLOR;
            };

            // 声明常量
            #define TWO_PI 6.283185

            // 顶点动画方法
            void AnimGhost (inout float3 vertex, inout float3 color)
            {
                // 缩放天使圈
                float scale = _ScaleParams.x * color.g * sin(frac(_Time.z * _ScaleParams.y) * TWO_PI);
                vertex.xyz *= 1.0 + scale;
                vertex.y -=  _ScaleParams.z * scale;
                // 幽灵摆动
                float swingX = _SwingXParams.x * sin(frac(_Time.z * _SwingXParams.y + vertex.y * _SwingXParams.z) * TWO_PI);
                float swingZ = _SwingZParams.x * sin(frac(_Time.z * _SwingZParams.y + vertex.y * _SwingZParams.z) * TWO_PI);
                vertex.xz += float2(swingX, swingZ) * color.r;
                // 幽灵摇头
                float radY = radians(_ShakeYParams.x) * (1.0 - color.r) * sin(frac(_Time.z * _ShakeYParams.y - color.g * _ShakeYParams.z) * TWO_PI);
                float sinY, cosY = 0;
                sincos(radY, sinY, cosY);
                vertex.xz = float2(
                vertex.x * cosY - vertex.z * sinY,
                vertex.x * sinY + vertex.z * cosY
                );
                // 幽灵起伏
                float swingY = _SwingYParams.x * sin(frac(_Time.z * _SwingYParams.y - color.g * _SwingYParams.z) * TWO_PI);
                vertex.y += swingY;
                // 处理顶点色
                float lightness = 1.0 + color.g * 1.0 + scale * 2.0;
                color = float3(lightness, lightness, lightness);
            }

            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v)
            {
                VertexOutput o = (VertexOutput)0;
                AnimGhost(v.vertex.xyz, v.color.rgb);
                o.pos = UnityObjectToClipPos(v.vertex);    // 顶点位置 OS>CS
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);       // UV信息 支持TilingOffset
                o.color = v.color;
                return o;
            }

            // 输出结构>>>像素
            half4 frag(VertexOutput i) : COLOR
            {
                half4 var_MainTex = tex2D(_MainTex, i.uv);      // 采样贴图 RGB颜色 A透贴
                half3 finalRGB = var_MainTex.rgb * i.color.rgb;
                half opacity = var_MainTex.a * _Opacity;
                return half4(finalRGB * opacity, opacity);                // 返回值
            }
            ENDCG
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值