前言
想在战棋demo中增加UI的血条效果,原本用的是之前所用的直接slider制作或直接修改UI中sizedelta.x的方法来实现,但是却发现会不可避免的造成Image中的sprite拉伸的情况,后来自己尝试的同时问了下同事得到了两种方案。
方案1:slider+Rect Mask蒙版
制作思路:
直接对UGUI中的slider结构进行一个小修改,新加入前景色和后景色作为血条颜色和背景色,同时在原Slider中的Fill加入了Rect Mask,对前景色进行蒙版处理,用于解决UGUI中Slider中Fill在修改value时会rect Transform定死为Stretch Left的情况,前景色和后景色的RectTransform都设置为 Middle Left。
实际效果:
方案2:通过shader进行蒙版剔除
制作思路:
通过UI Shader中的uv.x与参数_Clip做一个剔除,即Clip(i.uv.x-_Clip),来达到类似于slider的效果,感谢同事的思路,感觉挺方便的。
在明确了思路的情况下,直接找到builtin中UI-Default.shader并对其进行一些修改:
UIClip.shader:
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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
Shader "UI/UIClip" { Properties { [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} _Color ("Tint", Color) = (1,1,1,1)
_StencilComp ("Stencil Comparison", Float) = 8 _Stencil ("Stencil ID", Float) = 0 _StencilOp ("Stencil Operation", Float) = 0 _StencilWriteMask ("Stencil Write Mask", Float) = 255 _StencilReadMask ("Stencil Read Mask", Float) = 255 //MARKER:用于处理UI的剔除效果的参数 _Clip("Clip Mask",Range(0,1))=1
_ColorMask ("Color Mask", Float) = 15
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 }
SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True" }
Stencil { Ref [_Stencil] Comp [_StencilComp] Pass [_StencilOp] ReadMask [_StencilReadMask] WriteMask [_StencilWriteMask] }
Cull Off Lighting Off ZWrite Off ZTest [unity_GUIZTestMode] Blend SrcAlpha OneMinusSrcAlpha ColorMask [_ColorMask]
Pass { Name "Default" CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0
#include "UnityCG.cginc" #include "UnityUI.cginc"
#pragma multi_compile_local _ UNITY_UI_CLIP_RECT #pragma multi_compile_local _ UNITY_UI_ALPHACLIP
struct appdata_t { float4 vertex : POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID };
struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; float4 worldPosition : TEXCOORD1; float2 clipuv :TEXCOORD2; UNITY_VERTEX_OUTPUT_STEREO };
sampler2D _MainTex; fixed4 _Color; fixed4 _TextureSampleAdd; float4 _ClipRect; float4 _MainTex_ST; float _Clip;
v2f vert(appdata_t v) { v2f OUT; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); OUT.worldPosition = v.vertex; OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); OUT.clipuv=v.texcoord; //记录uv OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); OUT.color = v.color * _Color; return OUT; }
fixed4 frag(v2f IN) : SV_Target { clip (_Clip-IN.clipuv.x); //根据uv进行剔除 half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
#ifdef UNITY_UI_CLIP_RECT color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); #endif
#ifdef UNITY_UI_ALPHACLIP clip (color.a - 0.001); #endif
return color; } ENDCG } } }
|
实际效果:
方案2在使用时需要对每个slider新生成一个mat增加了dc,在问了大佬后发现其实有通过RawImageData绘制Texture后通过IParameterTexture来访问ParameterTexture对应像素点获取到任意通道(比如a)作为每个slider的_Clip的思路,后续优化再考虑吧。