(七)时间动画_Time
1.前言
shaderlab中通过_Time可以获取时间变量,然后可以让图像跟随时间动起来。_Time含有x/y/z/w四个值,分别对应时间t/20、t、2t和3t。当然也可以通过 _SinTime和_CosTime来获取时间的正弦或者余弦值,只不过他们的w分量才是准确值,而xyz值则为w值的八分之一、四分之一和二分之一。
2.播放序列帧
之前有涉及到序列帧播放的问题,最开始是通过RawImage/Image组件实现,即在update中或者通过协程实现固定事件间隔去刷新通向。再次提供两种shader来实现,序列帧的图像在一张图上按顺序排列。此处通过增加时间变量可以通过shader实现。
2.1 顶点片元着色器实现
用到了_Time来获取时间行程。
2.2 序列帧播放
Shader "LL/Sequence" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Image", 2D) = "white" {}
_Horizontal ("Horizontal Count", Float) = 4
_Vertical ("Vertical Count", Float) = 4
_Speed ("Speed", Float) = 10
}
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 "UnityCG.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
float _Horizontal;
float _Vertical;
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 deltaCount=floor(_Time.y*_Speed);
float period=floor(deltaCount/_Horizontal /_Vertical );
float posCount=deltaCount-period*_Horizontal *_Vertical;
float row=floor(posCount/_Vertical);
float column=posCount-_Vertical*row;
half2 uv=half2(i.uv.x/_Vertical+column/_Vertical ,1-row/_Horizontal -i.uv.y/_Vertical);
fixed4 c = tex2D(_MainTex, uv);
c.rgb *= _Color;
return c;
}
ENDCG
}
}
FallBack "Transparent/VertexLit"
}
2.3 表面着色器实现
此方法搬运此处 ,此文通过表面着色器实现,相对来说更简洁。
Shader "Custom/Sequences" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_CellAmount("Cell Amount", float) = 1
_Speed("Speed", Range(0.01, 32)) = 12
}
SubShader {
Tags { "RenderType"="Opaque"}
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _CellAmount;
half _Speed;
void surf (Input IN, inout SurfaceOutput o) {
fixed2 texUV = IN.uv_MainTex;
half cellUVX = 1 / _CellAmount;
half timeVal = ceil(fmod(_Time.y * _Speed, _CellAmount));
fixed uvx = texUV.x;
uvx *= cellUVX;
uvx += timeVal * cellUVX;
texUV = fixed2(uvx, texUV.y);
fixed4 c = tex2D (_MainTex, texUV);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
3.滚动背景
曾遇到一个需求,即需要背景滚动播放,当时采用RawImage实时更改UIRect的w值实现,而且涉及到效果叠加时采用多层背景,且有的背景需要带透明通道。而现在通过shader则不用如此繁琐。注意Layer 2的图片不需要的显示的位置透明通道为0,这样在通过lerp(firstLayer, secondLayer, secondLayer.a)计算时可以筛选出相关颜色值。
Shader "LL/ScrollBackground" {
Properties {
_MainTex ("Layer 1", 2D) = "white" {}
_DetailTex ("Layer 2", 2D) = "white" {}
_ScrollX ("Layer 1 Speed", Float) = 1.0
_Scroll2X ("Layer 2 Speed", Float) = 1.0
_Multiplier ("Layer Multiplier", Float) = 1
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry"}
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _DetailTex;
float4 _MainTex_ST;
float4 _DetailTex_ST;
float _ScrollX;
float _Scroll2X;
float _Multiplier;
struct a2v {
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
};
v2f vert (a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
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);
return o;
}
fixed4 frag (v2f i) : SV_Target {
fixed4 firstLayer = tex2D(_MainTex, i.uv.xy);
fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw);
fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a);
c.rgb *= _Multiplier;
return c;
}
ENDCG
}
}
FallBack "VertexLit"
}
4.顶点动画
除了更改uv以外还可以更改顶点坐标。当时有一个工业需求,需要动态显示在固有频率下的模态展示。则需要实时根据频率改变模型的形态,且形态时正弦变化的。假设有一根方形横梁,长度方向为x方向,如果只需要y方向正弦运动,则需要根据x方向实时更改y值,如果有更复杂变化则可以更改其他坐标值。但是会存在相互干扰问题。
Shader "LL/Move" {
Properties {
_MainTex ("Main Tex", 2D) = "white" {}
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_Magnitude ("振幅", Float) = 1
_Frequency ("频率", Float) = 1
_Phase ("相位因子", Float) = 10
_Speed ("Speed", Float) = 0.5
}
SubShader {
// Need to disable batching because of the vertex animation
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
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;
fixed4 _Color;
float _Magnitude;
float _Frequency;
float _Phase;
float _Speed;
struct a2v {
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(a2v v) {
v2f o;
float4 offset;
offset.xzw = float3(0.0, 0.0, 0.0);
offset.y = sin(_Frequency * _Time.y+v.vertex.x * _Phase ) * _Magnitude;
o.pos = UnityObjectToClipPos(v.vertex + offset);
o.uv = TRANSFORM_TEX(v.texcoord, _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"
}
5.结论
强迫症晚期,没有结论。