/* 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 } } }