105 lines
3.5 KiB
Plaintext

/*
Created by jiadong chen
https://jiadong-chen.medium.com/
*/
// Atlas VAT shader.
// 支持 1 张大图存多个 clip,clip 段沿 Y 轴堆叠。
// 通过 MaterialPropertyBlock 设置 _AnimYStart / _AnimYSpan / _AnimLen / _AnimTimeOffset 可切换 clip,
// 无需切换 material → 不破坏 SRP Batcher / GPU Instancing。
// 单 clip 模式向后兼容: _AnimYStart=0, _AnimYSpan=1, 行为与原 shader 一致。
Shader "chenjd/BuiltIn/AnimMapShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_AnimMap ("AnimMap", 2D) ="white" {}
_AnimLen("Anim Length", Float) = 1
_AnimYStart("Anim Y Start [0,1]", Float) = 0
_AnimYSpan ("Anim Y Span [0,1]", Float) = 1
_AnimTimeOffset("Anim Time Offset", Float) = 0
[Toggle] _AnimLoop("Loop Anim", Float) = 1
}
SubShader
{
Tags { "RenderType" = "Opaque" }
Cull off
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//开启gpu instancing
#pragma multi_compile_instancing
#include "UnityCG.cginc"
struct appdata
{
float2 uv : TEXCOORD0;
float4 pos : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _AnimMap;
float4 _AnimMap_TexelSize; // x == 1/width, y == 1/height
// Per-instance friendly props (set via MaterialPropertyBlock to keep SRP Batcher / instancing)
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(float, _AnimLen)
UNITY_DEFINE_INSTANCED_PROP(float, _AnimYStart)
UNITY_DEFINE_INSTANCED_PROP(float, _AnimYSpan)
UNITY_DEFINE_INSTANCED_PROP(float, _AnimTimeOffset)
UNITY_DEFINE_INSTANCED_PROP(float, _AnimLoop)
UNITY_INSTANCING_BUFFER_END(Props)
v2f vert (appdata v, uint vid : SV_VertexID)
{
UNITY_SETUP_INSTANCE_ID(v);
float animLen = UNITY_ACCESS_INSTANCED_PROP(Props, _AnimLen);
float yStart = UNITY_ACCESS_INSTANCED_PROP(Props, _AnimYStart);
float ySpan = UNITY_ACCESS_INSTANCED_PROP(Props, _AnimYSpan);
float timeOff = UNITY_ACCESS_INSTANCED_PROP(Props, _AnimTimeOffset);
float loopFlag = UNITY_ACCESS_INSTANCED_PROP(Props, _AnimLoop);
// 时间 → 段内归一化 t [0,1]
float playTime = _Time.y - timeOff;
float t = playTime / max(animLen, 0.0001);
// 循环 or 停在最后一帧
t = lerp(saturate(t), frac(t), step(0.5, loopFlag));
float animMap_x = (vid + 0.5) * _AnimMap_TexelSize.x;
float animMap_y = yStart + t * ySpan;
float4 pos = tex2Dlod(_AnimMap, float4(animMap_x, animMap_y, 0, 0));
v2f o;
o.vertex = UnityObjectToClipPos(pos);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}