项目中使用的不少UI图片是轴对称的,包括:
图1:竖轴对称图片1)横轴对称或纵轴对称
2)同时满足横轴对称和纵轴对称
可以使用镜像效果来节省图片资源。第一种情况可以省下完整资源的一半,第二种情况则可以省略3/4。普通的方法则是一个Image GameObject下面挂载1个或3个Image。这些Image的scale的x或y分量值设置为-1, 就产生一个镜像了,然后开发者小心翼翼把他们对齐。这个过程太繁琐,而且产生了冗余的GameObject。
更好的办法是使用纹理采样的Wrap Mode来实现。先设置图片Wrap Mode:
图2:Wrap Mode的设置然后上代码:
public class MirrorImage : Image
{
[SerializeField]
public Vector2Int m_MirrorAttr = Vector2Int.one;
protected override void OnPopulateMesh(VertexHelper toFill)
{
if (type == Type.Simple)
{
GenerateSimpleSprite(toFill, preserveAspect);
return;
}
base.OnPopulateMesh(toFill);
}
void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
{
var activeSprite = overrideSprite;
Vector4 v = GetDrawingDimensions(lPreserveAspect);
var uv = (activeSprite != null) ? UnityEngine.Sprites.DataUtility.GetOuterUV(activeSprite) : Vector4.zero;
uv.z *= m_MirrorAttr.x;
uv.w *= m_MirrorAttr.y;
var color32 = color;
vh.Clear();
vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y));
vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w));
vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w));
vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y));
vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
}
private Vector4 GetDrawingDimensions(bool shouldPreserveAspect)
{
var activeSprite = overrideSprite;
var padding = activeSprite == null ? Vector4.zero : UnityEngine.Sprites.DataUtility.GetPadding(activeSprite);
var size = activeSprite == null ? Vector2.zero : new Vector2(activeSprite.rect.width, activeSprite.rect.height);
Rect r = GetPixelAdjustedRect();
// Debug.Log(string.Format("r:{2}, size:{0}, padding:{1}", size, padding, r));
int spriteW = Mathf.RoundToInt(size.x);
int spriteH = Mathf.RoundToInt(size.y);
var v = new Vector4(
padding.x / spriteW,
padding.y / spriteH,
(spriteW - padding.z) / spriteW,
(spriteH - padding.w) / spriteH);
if (shouldPreserveAspect && size.sqrMagnitude > 0.0f)
{
var spriteRatio = size.x / size.y;
var rectRatio = r.width / r.height;
if (spriteRatio > rectRatio)
{
var oldHeight = r.height;
r.height = r.width * (1.0f / spriteRatio);
r.y += (oldHeight - r.height) * rectTransform.pivot.y;
}
else
{
var oldWidth = r.width;
r.width = r.height * spriteRatio;
r.x += (oldWidth - r.width) * rectTransform.pivot.x;
}
}
v = new Vector4(
r.x + r.width * v.x,
r.y + r.height * v.y,
r.x + r.width * v.z,
r.y + r.height * v.w
);
return v;
}
}
[CustomEditor(typeof(MirrorImage), true)]
[CanEditMultipleObjects]
public class MirrorImageEditor : ImageEditor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var property = serializedObject.FindProperty("m_MirrorAttr");
EditorGUILayout.PropertyField(property);
serializedObject.ApplyModifiedProperties();
}
}
效果如下图:
图3:最终效果PS:如果需要的是重复模式,比如绳子的每两节完全一样的效果。Wrap Mode选择Repeat就可以。
网友评论