本文已参与[新人创作礼]活动,一起开启掘金创作之路
请记住下面这张表,这几个时间参数是让shader动起来的“大功臣”
帧动画
小时候肯定都玩过 翻页动画 吧!帧动画的原理就和他一样!
以上面的火为例,我们需要准备足够多的动画帧,然后将其合到一张texture中(在shader中texture的数量越多越耗性能,因此合到一张上),如下图,接下来只要逐帧播放下面的每一帧就可以看到上面gif的效果
核心代码(关键计算已经在代码中作了注释):
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass {
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Cull Back
CGPROGRAM
.....
2f vert (a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target {
//计算出时间内走的总长
float len = floor(_Time.y * _Speed);
//在len内含有几行
float row = floor(len / _HorizontalAmount);
//扣除掉之前的行,剩下的就是列数
float column = len - row * _HorizontalAmount;
//Unity的UV是从左下方开始的,但是合成帧组图是左上方开始的,因此行数应取反
half2 uv = i.uv + half2(column, -row);
//均分到每个帧之后每个帧的uv,其实就是当前帧的uv
uv.x /= _HorizontalAmount;
uv.y /= _VerticalAmount;
//获取在该uv下的帧
fixed4 c = tex2D(_MainTex, uv);
c.rgb *= _Color;
return c;
}
ENDCG
}
关于行数取反的原因我们可以从下面两张gif看出(第一个gif为取反,第二个为不取反)
下图为该gif的帧组图
优化: 当我们在转动的时候出现下面的情况(及quad的前向与视角垂直会出现平面变成一条线或者超过90°的时候平面直接消失)
为此我们引入广告牌
我们只需要在顶点着色器中进行一番操作就可以让quad的朝向一直面向相机,原理会在代码后分析
v2f vert (a2v v) {
v2f o;
//确定一个旋转中心(模型空间下)
float3 center = float3(0, 0, 0);
//得到相机位置
float3 viewer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1));
// 计算出法线方向
float3 normalDir = center - viewer;
//确定朝上的方向,abs(normalDir.y) > 0.999这个条件是为了防止法线方向和朝上方向平行
//平行的话叉乘得到的结果是错的,不是朝右方向
float3 upDir = abs(normalDir.y) > 0.999 ? 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.texcoord, _MainTex);
return o;
}
原理分析: 因为差值存在正负,并且是关于原点对称的,这样就实现了绕原点旋转,如下图
观察右上角的坐标系可以看到镜头是不断地在围着quad转动的,但是quad是一直正面朝相机的。
强调一点: 我们使用的是quad,这是一个竖直摆放的多边形(这个东西在模型从3DSMax等软件导出之后就被固定了),只有竖直摆放的模型使用上述方法才会正确。因此当我们把模型从quad换成plane的时候就得不到预期的效果 , 我们从下面的截图(左边是quad,右边是plane)可以看出,在默认rotate=(0,0,0)的情况下,quad是竖直的,而plane是水平的