1.序列帧动画
//纹理动画之序列帧动画
//序列帧动画的原理非常简单,它像放电影一样,依次播放一系列关键帧图像,当播放速度达到一定数值时,看起来就是一个连续的动画。
Shader "MyShader/ImageSequenceAnimation"
{
Properties
{
_Color("Color Tint",Color) = (1,1,1,1)
_MainTex("Image Sequence", 2D) = "white" {}//包含关键帧图像的纹理
_HorizontalAmount("Horizontal Amount",Float) = 8//纹理水平方向关键帧个数
_VerticalAmount("Vertical Amount",Float) = 8//竖直方向
_Speed("Speed",Range(1,150)) = 30//播放速度
}
SubShader
{
Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}// 序列帧图像通常包含透明通道
Pass
{
Tags{"LightMode" = "ForwardBase"}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
// 关闭深度写入,开启混合模式
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
float _HorizontalAmount;
float _VerticalAmount;
float _Speed;
struct a2v
{
float4 vertex:POSITION;
float2 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
v2f 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 time = floor(_Time.y * _Speed); // floor()取整。CG的函数。用_Time.y和速度属性_Speed相乘得到模拟的时间。
float row = floor(time / _HorizontalAmount); // 行索引,随时间变化
float column = time % _HorizontalAmount; //余数则是列索引。
//纹理坐标从上到下,所以是-row。下面两种计算方法.这种容易理解。
half2 uv = float2(i.uv.x /_HorizontalAmount, i.uv.y / _VerticalAmount);//以关键帧帧图像纹理坐标
uv.x += column / _HorizontalAmount;//列索引/列数(每行个数)
uv.y -= row / _VerticalAmount; //同上
//简化如下
//half2 uv = i.uv + half2(column, -row);
//uv.x /= _HorizontalAmount;
//uv.y /= _VerticalAmount;
fixed4 c = tex2D(_MainTex, uv);
c.rgb *= _Color;
return c;
}
ENDCG
}
}
Fallback "Transparent/VertexLit"
}
2.背景动画
//纹理动画之运动的背景
Shader "MyShader/ImageSequenceAnimation"
{
Properties {
_MainTex ("Base Layer (RGB)", 2D) = "white" {} // 第一层背景(较远背景)
_DetailTex ("2nd Layer (RGB)", 2D) = "white" {} // 较近背景
_ScrollX ("Base layer Scroll Speed", Float) = 1.0 // 第一层背景滚动速度
_Scroll2X ("2nd layer Scroll Speed", Float) = 0.5 // 第二层速度
_Multiplier ("Layer Multiplier", Float) = 1 // 纹理亮度
}
SubShader
{
Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}// 序列帧图像通常包含透明通道
Pass
{
Tags{"LightMode" = "ForwardBase"}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
// 关闭深度写入,开启混合模式
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _DetailTex;
float4 _DetailTex_ST;
float _ScrollX;
float _Scroll2X;
float _Multiplier;
struct a2v
{
float4 vertex:POSITION;
float2 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float4 uv:TEXCOORD0;
};
v2f vert (a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
// TRANSFORM_TEX 得到初始纹理坐标,加上偏移坐标。frac为获取小数部分的值。
//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);
o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex);
return o;
}
fixed4 frag (v2f i) : SV_Target {
float2 uv1 =i.uv.xy + frac(_ScrollX* _Time.y);//frac函数返回数的小数部分。因为uv值在(0,1)内
float2 uv2 =i.uv.zw + frac(_Scroll2X * _Time.y);
fixed4 firstLayer = tex2D(_MainTex, uv1);
fixed4 secondLayer = tex2D(_DetailTex, uv2);
fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a);
c.rgb *= _Multiplier;
return c;
}
ENDCG
}
}
Fallback "Transparent/VertexLit"
}
3.波纹顶点动画
//水流
Shader "Custom/Wave" {
Properties {
_MainTex("Texture", 2D) = "white"{} //纹理
_Arange("Amplitute", float) = 1//极值
_Frequency("Frequency", float) = 2//波动频率
_Speed("Speed",float) = 0.5//控制纹理移动的速度
}
SubShader
{
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" "DisableBatching" = "True"}
// "DisableBatching" = "True"是为了防止unity批处理出现问题(顶点动画一般都添加此句)
Pass
{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
float _Frequency;
float _Arange;
float _Speed;
struct a2v
{
float4 vertex:POSITION;
float2 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
v2f vert(a2v v)
{
v2f o;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
//o.uv = v.texcoord;在没声明_MainTex_ST时可用
float timer = _Time.y *_Speed;
//变化之前做一个波动 y= Asin(ωx+φ)
float waver = _Arange*sin(timer + v.vertex.x *_Frequency);// timer随时间变化
v.vertex.y = v.vertex.y + waver;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) :SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
4.广告牌效果
//广告牌效果指的是,一个二维平面的法线方向始终与视线(摄像机的观察方向)相同.它的本质在于构建旋转矩阵,此时我们可以选择三个基向量来构建此矩阵。 //1.根据当前摄像机的方向确定法线方向(广告牌效果的本质),并归一 //normal=normalize(viewDir); //2.根据得到的法线方向和初始的向上方向(在本地空间中即为float3(0,1,0))计算向右的方向,并归一化 //right=normalize(cross(up,normal));(使用向量的叉乘计算) //3.用计算后的向右方向和法线方向重新校正向上的方向,得到精确值 //up'=normalize(cross(right,normal));
//广告牌效果指的是,一个二维平面的法线方向始终与视线(摄像机的观察方向)相同.它的本质在于构建旋转矩阵,此时我们可以选择三个基向量来构建此矩阵。
//1.根据当前摄像机的方向确定法线方向(广告牌效果的本质),并归一
//normal=normalize(viewDir);
//2.根据得到的法线方向和初始的向上方向(在本地空间中即为float3(0,1,0))计算向右的方向,并归一化
//right=normalize(cross(up,normal));(使用向量的叉乘计算)
//3.用计算后的向右方向和法线方向重新校正向上的方向,得到精确值
//up'=normalize(cross(right,normal));
Shader "MyUnlit/Billboarding"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Color Tint",color)=(1,1,1,1)
}
SubShader
{
//对顶点进行变换需禁用合P
Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "true" "DisableBatching" = "True" }
Pass
{
//透明度混合
Tags{ "lightmode" = "forwardbase" }
ZWrite off
Blend SrcAlpha OneMinusSrcAlpha
Cull off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
v2f vert (appdata v)
{
v2f o;
//计算模型空间中的视线方向
float3 objViewDir = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1));
//计算旋转矩阵的各个基向量
float3 normalDir =normalize(objViewDir);
float3 upDir =float3(0, 1, 0);
float3 rightDir = normalize(cross(normalDir, upDir));
upDir = normalize(cross(normalDir, rightDir));
//用旋转矩阵对顶点进行偏移
float3 localPos =rightDir * v.vertex.x + upDir * v.vertex.y + normalDir * v.vertex.z;
//将偏移之后的值作为新的顶点传递计算
o.vertex = UnityObjectToClipPos(float4(localPos,1));
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.rgb *= _Color.rgb;
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
fallback "Transparent/VertexLit"
}
|