Chapter11-让画面动起来

纹理动画

1.序列帧动画

....

2.滚动背景

1
2
3
4
//frac函数返回标量或每个矢量中各分量的小数部分。return v - floor(v);
o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex) + frac(float2(_ScrollX,0.0)*_Time.y);
o.uv.zw = TRANSFORM_TEX(v.texcoord,_DetailTex) + frac(float2(_Scroll2X,0.0)*_Time.y);
//可以发现当x乘上一个小于1的值时,系数越小,呈现的图像结果会越稀疏

函数如下图

frac(float)等价上图

frac(float2())则等价于以圆心为原点,以这个点为起点的线为半径,每过v的长度,为一个周期。最后构成多重圆环。而横坐标

的倍率则影响密度。倍率大于1,噪声越大,间隔小,密度大。

如果渲染2d物体,可以将相机模式转换成正交模式

3.水波动画

由于本例中需要移动模型空间坐标,而批处理会使得相关模型合并,使得相关模型丢失原来模型空间;所以一般有顶点移动anime的shader要考虑关闭batch;

1
2
3
4
5
6
Tags{
"RenderType"="Transparent",
"IgnoreProjector" = "True",
"RenderType" = "Transparent",
"DisableBatching" = "True"
}

如何形成水波?顶点着色器中

1
2
3
4
5
6
7
8
float4 offset;
offset.yzw = float3(0.0,0.0,0.0);
offset.x = sin(_Frequency * _Time.y +v.vertex.x * _InWaveLength + v.vertex.y *
_InWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;

o.pos = mul(UNITY_MATRIX_MVP,v.vertex + offset);
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //将纹理进行uv映射
o.uv += float2(0.0,_Time.y * Speed); //将uv的v根据时间变化进行增长

等价于 \[ x = Magnitude * sin(_Frequency * t+w * vertex) \] 由此使得水波水平变化。

同时还用了纹理动画,产生水平的纹理动画。

4.广告牌技术

效果:星星始终面朝摄像机,向上的位置并未改变,当y轴转动,也会跟着转动

代码

1.获取模型空间的中心和相机点

2.将法线设为从中心点指向相机的方向

3.将法线y方向乘以_VerticalBillboarding,并归一化

4.一般来说,法线并不等于up向量,up向量为(0,1,0),但是随着视点的转变,法线也会变,如果法线等于up,

​ 那么后续叉乘的结果会出错。此时up会变成向前的向量。

5.然后是right向量,由前两个向量叉乘得到,需要归一化,至此三个正基向量得到。

6.float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;

​ 最后实现顶点坐标在模型空间,三个分量不同程度的形变,

结果是:错误_VerticalBillboarding=1,星星就像是跟踪屏幕;

​ _VerticalBillboarding= 0星星固定,有透视效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//顶点动画都是在模型空间变换
v2f vert (a2v v) {
v2f o;

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

//2.
float3 normalDir = viewer - center;

//3.
// If _VerticalBillboarding equals 1, we use the desired view dir as the normal dir
// Which means the normal dir is fixed
// Or if _VerticalBillboarding equals 0, the y of normal is 0
// Which means the up dir is fixed
normalDir.y =normalDir.y * _VerticalBillboarding;
normalDir = normalize(normalDir);

//4.
// Get the approximate up dir
// If normal dir is already towards up, then the up dir is towards front
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));

// Use the three vectors to rotate the quad
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;
}