0%

Unity-实现Sprite剪裁效果的Shader

前言

效果要求,能够以进度条控制sprite裁剪比例,同时要能控制剪裁的方位。

实现

下列为shader代码。(Build-in)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Shader "Custom/SpriteObjectSpaceClip"
{
Properties
{
_MainTex ("Sprite Texture", 2D) = "white" {}
_CutY ("Cut Local Y", Float) = 0 // 在Sprite自身坐标系中的Y值
_Invert ("Invert (0:show top,1:show bottom)", Float) = 0
_Color ("Tint", Color) = (1,1,1,1)
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" "PreviewType"="Plane" }
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
ZWrite Off

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

struct appdata {
float4 vertex : POSITION; // 模型空间中的顶点坐标
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};

struct v2f {
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 localPos : TEXCOORD1; // 模型空间坐标传递给片元着色器
float4 color : COLOR;
};

sampler2D _MainTex;
float4 _MainTex_ST;
float _CutY;
float _Invert;
float4 _Color;

v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex); // 标准坐标变换
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.color = v.color * _Color;

// 关键:直接使用模型空间坐标(不做世界或观察空间变换)
o.localPos = v.vertex.xyz;

return o;
}

fixed4 frag(v2f i) : SV_Target
{
// 使用模型空间的Y坐标进行裁剪判断
float localY = i.localPos.y;

if (_Invert < 0.5) {
// 显示上半部分:丢弃Y坐标小于_CutY的片元
if (localY < _CutY) discard;
} else {
// 显示下半部分:丢弃Y坐标大于等于_CutY的片元
if (localY >= _CutY) discard;
}

fixed4 tex = tex2D(_MainTex, i.uv) * i.color;
clip(tex.a - 0.001);
return tex;
}
ENDCG
}
}
FallBack "Sprites/Default"
}

算法

分数算法:(暂且这么设计)

1
score = clamp01(1 - |cutY - idealY| / tolerance) * 100