雪千渔Blog

  • 首页
  • 写写代码
    • dotNet
    • C++
    • Lua
    • Visual Basic
    • Java
    • Android
    • Web
  • DCC
    • Maya
    • Maya-Plug
    • AfterEffect
    • AfterEffect-Plug
    • PhotoShop-Plug
  • 游戏制作
    • Unity3D
    • UnrealEngine
    • 经验杂谈
    • 游戏设计
    • 自研引擎
    • 效果实现
  • 其他
    • 乱七八糟
    • 软件工具
    • 留言板
    • 自制素材
    • 关于我
  • 世界的尽头
雪千渔blog
唯有热爱,能抵漫长岁月
  1. 首页
  2. GameDev
  3. Unity3D
  4. 正文

ugui多层Sprite的混合合并

2022年4月17日 353点热度 1人点赞 0条评论

Sprite是以Texture2d为基础的,所以我们应该首先获取Sprite的texture2d对象,合并,然后生成新的Sprite对象。

可以用画画的方式一层一层的混合,Unity3d新建的Texture2d对象并不是一张RGB为0的图,而是0.8的灰色缓冲区,所以我们需要清空这个颜色,只需要用最底层的texture去填充覆盖,上面的texture在绘制即可。

分别为两个指令,Fill和Draw。

public static void Fill(Texture2D src, Texture2D brush)
{
    src.SetPixels(brush.GetPixels());
}

Draw绘制函数

public static void Draw(Texture2D src, Texture2D brush, Vector2Int pos)
{
    int width = brush.width;
    int height = brush.height;

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            var destColor = brush.GetPixel(i, j);
            var srcColor = src.GetPixel(pos.x + i, pos.y + j);
            if (srcColor.a != 0)
            {
                float alpha = srcColor.a + destColor.a;
                destColor = Color.Lerp(srcColor, destColor, destColor.a);
                if (alpha >= 1)
                {
                    destColor.a = 1;
                }
            }
            src.SetPixel(pos.x + i, pos.y + j, destColor);
        }
    }
}

该函数对旧颜色进行判断,如果旧颜色的的透明度不为0,则使用新颜色的透明度对两个颜色插值,这是为了处理两层交界边缘的半透明区域。但是Lerp同时也会插值alpha,会在旧不透明与新半透明时混合错误,所以这里做了一个判断,如果两个颜色透明度相加大于等于1,那就将Lerp插值错误的alpha补偿回来。

现在已经可以合并多个Texture了,例:

Texture2D t1 = sprite1.texture as Texture2D;
Texture2D t2 = sprite2.texutre as Texture2D;
Texture2D tex = new Texture2D(t1.width, t1.height, t1.format, false);
Fill(tex, t1);
Draw(tex, t2, Vector2Int.zero);
tex.Apply();

到这里我们已经可以手动设置多张texture合成了。

public static Texture2D ComposeNew(Texture2D[] objs, Vector2Int[] offset)
{
    Texture2D t1 = objs[0];
    Texture2D tex = new Texture2D(t1.width, t1.height, t1.format, false);
    Fill(tex, t1);
    for (int i = 1; i < objs.Length; i++)
    {
        Draw(tex, objs[i], offset[i]);
    }
    tex.Apply();
    return tex;
}

但是对于sprite来说还需要计算它们的偏移。

在ugui中的sprite以Image显示,而在ugui的Canvas中一个单位即一个像素。在绘制的过程中我们要注意一点:Unity的颜色缓冲信息是从图像的左下角开始的,所以我们要算出Image在Canvas中的相对位置以及和填充层的相对位置。

一般情况下ugui的控件中心点pivot为(0.5,0.5),使用fillRect.sizeDelta * fillRect.pivot就可以求出填充层的中心位置,但是从填充层中心开始画就错了,因为是从左下角开始画的,所以这里还需要减掉需要绘制图像的一半:

fillRect.sizeDelta * fillRect.pivot - transRect.sizeDelta / 2

然后我们加上两个对象在Canvas上的相对距离,首先编写控件获取在Canvas上的位置:

private static Vector2 TransformToCanvasLocalPosition(Transform current, Canvas canvas)
{
    var screenPos = canvas.worldCamera.WorldToScreenPoint(current.transform.position);
    Vector2 localPos;
    RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.GetComponent<RectTransform>(), screenPos,
        canvas.worldCamera, out localPos);
    return localPos;
}

最后将上述表达式整合,编写Sprite合成函数:

public static Sprite ComposeNewSpriteFromUImage(Transform[] transforms, Canvas canvas)
{
    Texture2D[] texArr = new Texture2D[transforms.Length];
    Vector2Int[] offsetArr = new Vector2Int[transforms.Length];
    var first = transforms[0];
    for (int i = 0; i < transforms.Length; i++)
    {
        var transform = transforms[i];
        texArr[i] = transform.GetComponent<Image>().mainTexture as Texture2D;
        if (i == 0)
        {
            offsetArr[i] = new Vector2Int(0, 0);
        }
        else
        {
            var fillRect = first.GetComponent<RectTransform>();
            var transRect = transform.GetComponent<RectTransform>();

            var offset = fillRect.sizeDelta * fillRect.pivot - transRect.sizeDelta / 2;
            offset += TransformToCanvasLocalPosition(transform, canvas) - TransformToCanvasLocalPosition(first, canvas);

            offsetArr[i] = new Vector2Int((int)offset.x, (int)offset.y);
        }
    }
    var tex = ComposeNew(texArr, offsetArr);
    return Texture2DUtility.Texture2dToSprite(tex);
}

 

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: Sprite Texture Unity
最后更新:2022年4月19日

JomiXedYu

一名游戏玩家。

点赞
< 上一篇

文章评论

取消回复

*

code

JomiXedYu

一名游戏玩家。

分类
  • AfterEffect / 6篇
  • AfterEffect-Plug / 1篇
  • Android / 1篇
  • C++ / 13篇
  • dotNet / 12篇
  • Lua / 4篇
  • Maya / 2篇
  • Maya-Plug / 2篇
  • Office-VSTO&VBA / 2篇
  • Unity3D / 14篇
  • UnrealEngine / 4篇
  • Visual Basic / 8篇
  • Web / 2篇
  • 乱七八糟 / 2篇
  • 效果实现 / 2篇
  • 经验杂谈 / 2篇
  • 自制素材 / 3篇
  • 自研引擎 / 1篇
  • 计算机图形学 / 1篇
  • 软件工具 / 4篇
友情链接
  • DorinXL
  • 小博博客
  • 秋橘斋

COPYRIGHT © 2014-2021 雪千渔Blog. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

辽ICP备20006894号-1