UnityShader_实现动画效果(1)

176 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路
请记住下面这张表,这几个时间参数是让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是水平的

在这里插入图片描述