如何统一检测精灵的透明部分

问题描述 投票:0回答:2

我有一个部分透明的精灵。

enter image description here

我的目标是用一些方形预制件填充图像。

我已经编写了这段代码,运行良好。

while (newY < endVertical)
{
        while (newX < endHorizontal)
        {
                Instantiate(filler, new Vector3(newX, newY, 0), Quaternion.identity);
                newX += fillerWidth + 0.1f;
        }

        newY += fillerHeight + 0.1f;
        newX = startHorizontal;
}

结果是

enter image description here

然而,我的目标是只在图像的可见部分绘制白色预制件。 我希望我的结果是这样的

enter image description here

为了实现此目的,我添加了一些更改来检查每个像素的颜色,并且仅在颜色不清晰时实例化预制件。

 var colorSelected = player.GetComponent<SpriteRenderer>().sprite.texture.GetPixel((int) newX, (int) newY);
                if (colorSelected != Color.clear)
                {
                    Instantiate(filler, new Vector3(newX, newY, 0), Quaternion.identity);
                }

但这不起作用。

我也试过这个 https://support.unity.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures-

这也失败了。

我已经弄清楚,如果我能够以编程方式知道图像的特定像素是否透明,那么我就可以弄清楚其余的部分。

有人帮忙。

c# unity-game-engine
2个回答
1
投票

事先声明:这不会便宜^^

您将需要在要生成图块的矩形处获取相应的像素,并且需要检查所有像素是否其中任何完全透明。

由于您没有提供有关您的设置的太多信息,我只能尝试根据一些假设给出解决方案:

  • 您的 SpriteRenderer 使用完整纹理
  • filler
    的枢轴位于左下角
  • 填充物将在世界空间中生成(与屏幕空间覆盖画布的像素空间相反)
  • 您不考虑旋转 -> 一切都发生在 2D x-y 平面中

这是我使用的脚本

using System;
using System.Linq;
using UnityEngine;

public class Example : MonoBehaviour
{
    public GameObject filler;

    public Vector2 fillerSize = Vector2.one * 0.5f;
    public Vector2 spacing = Vector2.one * 0.1f;

    public SpriteRenderer spriteRenderer;

    [ContextMenu(nameof(Test))]
    private void Test()
    {
        var sprite = spriteRenderer.sprite;
        var texture = sprite.texture;
        // get the world space dimensions
        var worldBounds = spriteRenderer.bounds;
        // get the pixel space dimensions
        var pixelRect = sprite.rect;

        // Multiply by this factor to convert world space size to pixels
        var fillerSizeFactor = Vector2.one / worldBounds.size * pixelRect.size;
        var fillerSizeInPixels = Vector2Int.RoundToInt(fillerSize * fillerSizeFactor);

        var start = worldBounds.min;
        var end = worldBounds.max;

        // Use proper for loops instead of ugly and error prone while ;)
        for (var worldY = start.y; worldY < end.y; worldY += fillerSize.y + spacing.y)
        {
            // convert the worldY to pixel coordinate
            var pixelY = Mathf.RoundToInt((worldY - worldBounds.center.y + worldBounds.size.y / 2f) * fillerSizeFactor.y);

            // quick safety check if this fits into the texture pixel space
            if (pixelY + fillerSizeInPixels.y >= texture.height)
            {
                continue;
            }

            for (var worldX = start.x; worldX < end.x; worldX += fillerSize.x + spacing.x)
            {
                // convert worldX to pixel coordinate
                var pixelX = Mathf.RoundToInt((worldX - worldBounds.center.x + worldBounds.size.x / 2f) * fillerSizeFactor.x);

                // again the check if this fits into the texture pixel space
                if (pixelX + fillerSizeInPixels.x >= texture.width)
                {
                    continue;
                }

                // Cut out a rectangle from the texture at given pixel coordinates
                var pixels = texture.GetPixels(pixelX, pixelY, fillerSizeInPixels.x, fillerSizeInPixels.y);

                // Using Linq to check if all pixels are transparent
                if (pixels.All(p => Mathf.Approximately(p.a, 0f)))
                {
                    continue;
                }

                // otherwise spawn a filler here
                Instantiate(filler, new Vector3(worldX, worldY, 0), Quaternion.identity, transform);
            }
        }
    }
}

结果:

enter image description here


0
投票

您可以将正方形实例化为图像的子级,并在图像上添加遮罩组件,然后检查正方形上的可遮罩选项

© www.soinside.com 2019 - 2024. All rights reserved.