(一)内置时间变量

记一下好了,后面用到最多的是_Time.y

(二)序列帧动画

这一块感觉是李仕sense喜欢的内容,我就提一嘴就过了。

比较重要的是片元着色器,给了一个Unity里要记得注意点

half2 uv=i.uv+half2(column,-row)有个印象好了。

(三)滚动背景

这种效果做出来还是挺好的,用在过场动画里感觉不错。

代码内容并不复杂,主要工作在vert中,对两张纹理的采样坐标随时间做个水平位移就好了

然后在frag里利用secondLayer的透明度混合一下颜色就好了。

想要BaseLayer看上去更远的效果,就只要把他的速度调到比SecondLayer更慢一点就好了。

(四)顶点动画

这里本章毫无疑问最有用的。

首先来看一个流动的河流。这个例子里面就很明显应用了顶点位移。

先来看一些关键点,包括subpass的tags以及pass内的剔除。

这里的tags除了我们处理透明物体常用的三剑客以外,还加了一个DisableBatching=True,看完整本书后,就能够理解了,比较批处理的时候要把几个物体在揉合成一个新的网格结构,这就意味着自己本身的模型空间就不存在,对这些需要在模型空间进行顶点动画的物体来说变不能接受了。

之后是关闭了背面剔除,说是让水的每个面都能被看到,我忘了去从背面看看了,就是不知道为什么这里使用了Blend?。

SubShader
    {
        //使用新增tag DisableBatching 禁用批处理,防止模型各自的模型空间丢失
        Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" "DisableBatching"="True"}
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            Cull Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _Color;
            float _Magnitude;
            float _Frequency;
            float _InvWaveLength;
            float _Speed;

            v2f vert (appdata v)
            {
                v2f o;

                float4 offset;
                offset.yzw=float3(0.0,0.0,0.0);
                offset.x=sin(_Frequency*_Time.y+v.vertex.x*_InvWaveLength+v.vertex.y*_InvWaveLength+
                v.vertex.z*_InvWaveLength)*_Magnitude;
                
                o.pos = UnityObjectToClipPos(v.vertex+offset);

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv+=float2(0.0,_Time.y*_Speed);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                
                fixed4 c = tex2D(_MainTex, i.uv);
                c.rgb*=_Color.rgb;
                return c;
            }
            
            ENDCG
        }
    }
    FallBack "Transparent/VertexLit"

现在想想原来感觉很难得顶点动画感觉也就还行了。这里只是对了一个平面的x坐标下手,想必还有其他更复杂的顶点动画,还是要去拓展看看。

下面让我们来看看广告牌的技术吧。背后的原理都很重要,因为比较长,还是直接贴图吧。

这里我们可以看大广告牌技术的核心就是构建旋转矩阵,而这在代码中主要是由vert在模型空间实现的。

v2f vert (appdata v)
            {
                v2f o;

                float3 center=float3(0,0,0);
                float3 viewer=mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1));

                float3 normalDir=viewer-center;
                //这里如何靠在y方向约束的没怎么搞懂
                normalDir.y*=_VerticalBillboard;
                normalDir=normalize(normalDir);

                //get the approximate up dir
                float3 upDir=abs(normalDir.y)>0.999f?float3(0,0,1):float3(0,1,0);
                float3 rightDir=normalize(cross(upDir,normalDir));
                upDir=normalize(cross(normalDir,rightDir));

                float3 centerOffs=v.vertex.xyz-center;
                float3 localPos=center+rightDir*centerOffs.x+upDir*centerOffs.y+normalDir*centerOffs.z;

                o.pos = UnityObjectToClipPos(float4(localPos,1));
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

之前没搞懂normal怎么被约束的。现在总算知道了,约束要靠后面的的代码来实现。normal.y*1时normal不变,就相当于固定了normal,而normal.y*0时,相当于upDir被固定为(0,1,0)了。大概是这样吧,如此说来除了0、1的值感觉不太有意义。

其他代码里面注释的还行,第一个upDir是估摸着得到的,写这么长就是为了防止normal也是直接朝上的。这里可以看到一开始的upDir确实挺粗略的,怎么想都不会一开始就与normal垂直。

后面先叉积得到rightDir,再叉积得到准确的Updir就是挺奇妙的。

之后就是每一个点都根据中心,利用这三个向量做了旋转,就得到我们想要的广告牌效果了。

以后要是做纸片人敌人,可以写这么一个shader,让敌人都朝向你(doge)

(五)注意事项

总而言之就是默认的阴影时很难直接用默认的fallback实现了,这就需要我们为自己想要实现的效果去自定义一个shadowCaster了

这边是一个用来实现水波的阴影的例子。感觉就是使用了其他的内置函数,整体思路和传统的ShadowCAster Pass差不多。当然还是要根据实际看问题。

您必须 登录 才能发表评论