顶点动画
流动的河流
它的原理通常是使用正弦函数等来模拟水流的波动效果。主要是改变了模型空间点的位置。
Shader "Unlit/VertexAnimatorWater"
{
Properties{
_MainTex("Main Texture",2D)="white"{}
_Color("Color",Color)=(1,1,1,1)
_Magnitude("Distortion Magnitude",float)=1 //振幅
_Frequency("Distortion Frequency",float)=1 //频率
_InvWaveLength("Distortion Inverse Wave Length",float)=1 //用于控制波长
_Speed("Speed",float)=1
}
SubShader {
//需要关闭批处理,因为顶点动画改变了模型空间的点的坐标
Tags { "DisableBatching"="True"}
Pass{
Tags{"LightMode"="ForwardBase"}
Cull off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
float _Magnitude;
float _Frequency;
float _InvWaveLength;
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 = float4(0,0,0,0);
//这个就是正弦波长公式:y=Asin(ωx+φ)
//然后进行顶点动画
offset.x = _Magnitude * sin(_Frequency * _Time.y + _InvWaveLength*(v.vertex.x + v.vertex.y + v.vertex.z));
o.pos = UnityObjectToClipPos(v.vertex + offset);
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
//进行纹理动画
o.uv += float2(0,_Speed * _Time.y);
return o;
}
fixed4 frag(v2f i):SV_TARGET
{
fixed4 col = tex2D(_MainTex,i.uv);
col.rgb *= _Color.rgb;
return col;
}
ENDCG
}
//注意阴影的处理,写入深度纹理的点的位置需要同时改变
Pass{
Tags { "LightMode" = "ShadowCaster" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
float _Magnitude;
float _Frequency;
float _InvWaveLength;
float _Speed;
struct v2f
{
V2F_SHADOW_CASTER;
};
v2f vert(appdata_base v)
{
v2f o;
float4 offset = float4(0,0,0,0);
offset.x = _Magnitude * sin(_Frequency * _Time.y + _InvWaveLength*(v.vertex.x + v.vertex.y + v.vertex.z));
v.vertex = v.vertex + offset;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}
fixed4 frag(v2f i):SV_TARGET
{
SHADOW_CASTER_FRAGMENT(i);
}
ENDCG
}
}
// Fallback "VertexLit"
}
广告牌
广告牌技术(Billboarding),是常见的顶点动画,他根据视角方向来旋转一个被纹理作色的多边形,使得多边形看起来好像总是面对着摄像机。
广告牌技术的本质是构建旋转矩阵,而一个变换需要3个基向量(XYZ)。广告牌技术使用的基向量通常是表面法线(normal)、指向上的方向(up)、指向右的方向(right),除此之外还需要指定一个锚点(anchor location),这个锚点在旋转过程中位置是不变的,以此来确定多边形在空间的位置。
广告牌技术的难点在于构建3个相互正交的基向量,首先选择要固定的方向,要不然就是固定法线方向,也就是视角方向,要不然就固定向上的方向,假设我们固定了视角方向,然后就可以计算出向右的方向,这个方向一定是垂直于法线方向和向上方向组成的平面的,所以通过叉乘可以计算出向右的方向:
计算出向右的方向之后就可以计算出真正的向上的方向,这个向上的方向一定垂直于视角和向右的方向组成的平面(因为是3个正交基一定是相互垂直的):
image.png
三个正交基
Shader "Unlit/Billboard"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_VerticalBillboard("Vertical Restraints",Range(0,1))=1
}
SubShader
{
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"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _VerticalBillboard;
v2f vert (a2v v)
{
v2f o;
float3 center = float3(0,0,0);
float3 vivwer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1));
float3 normalDir = vivwer - center;
normalDir.y = normalDir.y * _VerticalBillboard;
normalDir = normalize(normalDir);
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 offsets = v.vertex.xyz - center;
float3 localPos = center + offsets.x * rightDir + offsets.y * upDir + offsets.z * normalDir;
float4 transPos = float4(localPos,1);
o.pos = UnityObjectToClipPos(transPos);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
网友评论