【问题标题】:how to create quad area from sprite (texture2d)如何从精灵创建四边形区域(texture2d)
【发布时间】:2021-06-01 23:37:46
【问题描述】:

我有一个图像并将其作为可读/可写精灵添加到统一中。它是 32x32。但我不知道如何为顶点向量提供坐标,以便它给我一个与我的精灵形状相同的四边形区域。例如,如果我有一个 Heart.png 32x32 像素精灵,那么我想要一个四边形的心形区域

void Awake()
    {
        texture2D = sprite.texture;
        mesh = new Mesh();
        mf = GetComponent<MeshFilter>();
        

        for(int i=0; i< texture2D.width; i++)
        {
            for(int j=0; j< texture2D.height; j++)
            {

                Color color = texture2D.GetPixel(i, j);
                if(color.a == 0)
                {
                    continue;
                }

                vertices = new Vector3[] { new Vector3(), new Vector3(), new Vector3(), new Vector3() };
                indeces = new int[]{ 0, 1, 2, 2, 1, 3 };
                mesh.vertices = vertices;
                mesh.triangles = indeces;

            }
        }

        mf.sharedMesh = mesh;
    }

【问题讨论】:

  • 我对团结很陌生,并试图学习它:(

标签: unity3d 2d texture2d


【解决方案1】:

其实这有点棘手。

我会做的(因为它更容易实现 - 不是因为它更高效!)基本上是为每个像素创建一个具有相应颜色的小四边形(4 个顶点 -> 2 个三角形)。

[SerializeField] private Texture2D texture;
[SerializeField] private Mesh mesh;
[SerializeField] private MeshFilter mf;

[ContextMenu("TEST")]
private void Awake()
{
    // Just in case use the mesh format that allows more vertices
    
    if(!mf) mf = GetComponent<MeshFilter>();
    
    mesh = new Mesh {indexFormat = IndexFormat.UInt32};

    // Create these ONCE and fill them bit by bit
    var verticesList = new List<Vector3>();
    var trianglesList = new List<int>();
    var colors = new List<Color>();

    // Do this in ONE call -> more efficient
    var pixels = texture.GetPixels();

    // Place the pivot in the center of the texture
    var pivotOffset = -new Vector3(texture.width / 2f, texture.height / 2f);

    for (var i = 0; i < texture.width; i++)
    {
        for (var j = 0; j < texture.height; j++)
        {
            var color = pixels[i + j * texture.width];

            if (color.a == 0)
            {
                continue;
            }

            // Add the pixel color for the FOUR vertices we create
            colors.Add(color);
            colors.Add(color);
            colors.Add(color);
            colors.Add(color);

            // Create the four vertices around this pixel position
            var vertex0 = pivotOffset + new Vector3(i - 0.5f, j - 0.5f, 0);
            var vertex1 = pivotOffset + new Vector3(i + 0.5f, j - 0.5f, 0);
            var vertex2 = pivotOffset + new Vector3(i - 0.5f, j + 0.5f, 0);
            var vertex3 = pivotOffset + new Vector3(i + 0.5f, j + 0.5f, 0);

            // Store the current length of so far vertices => first new vertex index
            var currentIndex = verticesList.Count;

            // Add the vertices to the list
            verticesList.Add(vertex0);
            verticesList.Add(vertex1);
            verticesList.Add(vertex2);
            verticesList.Add(vertex3);

            // Two triangles for front side
            trianglesList.Add(currentIndex);
            trianglesList.Add(currentIndex + 2);
            trianglesList.Add(currentIndex + 3);

            trianglesList.Add(currentIndex);
            trianglesList.Add(currentIndex + 3);
            trianglesList.Add(currentIndex + 1);
            
            // For double sided add the inverted faces for the back as well
            trianglesList.Add(currentIndex);
            trianglesList.Add(currentIndex + 3);
            trianglesList.Add(currentIndex + 2);

            trianglesList.Add(currentIndex);
            trianglesList.Add(currentIndex + 1);
            trianglesList.Add(currentIndex + 3);
        }
    }

    // Finally apply them ONCE to the mesh
    mesh.vertices = verticesList.ToArray();
    mesh.triangles = trianglesList.ToArray();
    mesh.colors = colors.ToArray();

    mf.sharedMesh = mesh;
}

看起来

如您所见,您可以玩这些材料。通过将像素颜色存储到网格颜色中,您可以简单地使用支持顶点颜色的着色器。


进一步说明:

  1. GetPixels 返回一个扁平的一维数组。在该数组中,纹理的像素逐行水平排列。

    这意味着假设你有一个类似的网格

     7 8 9 |
     4 5 6 |-height=3
     1 2 3 |
     _____
       |
     width=3
    

    变成了

     1, 2, 3, 4, 5, 6, 7, 8, 9
    

    (Unity纹理坐标从左下角从0开始)

    所以为了访问某个条目,例如6 位于像素坐标 x=2, y=1 你必须去

     1, 2, 3, 4, 5, 6, 7, 8, 9
                   |
     x(=2) + y(=1) * width(=3)
    
  2. 如前所述,我的简单解决方案是不要像您尝试的那样为每个像素创建一个顶点,而是创建一个正方形。为此,我们需要像

    这样的顶点
     p-0.5x+0.5y        p+0.5x+0.5y
     V------------------V
     |                  |
     |                  |
     |        p         |
     | (actualPosition) |
     |                  |
     V------------------V
     p-0.5x-0.5y        p+0.5x-0.5y
    

    我希望令人敬畏的 ascii 艺术能以某种方式清楚地说明:D

  3. 最后,Unity 中网格的triangles 只是一个int[],其中每个元素都引用vertices 数组中的一个顶点索引,并且3 连续索引总是形成一个三角形。

    在一个三角形内,顶点的缠绕顺序决定了它所面对的方向。

    • 如果顶点按顺时针顺序排列,则法线朝向您。
    • 如果顶点按逆时针顺序排列,法线将背向您。

    参见例如Unity Manual - Creating a Quad 我希望这些图形能解释其余的内容

    在我的示例中,我为每个像素添加了一个由四个顶点组成的四边形

     2----3
     |  / |
     | /  |
     0----1
    

    然后我顺时针添加两个三角形

    • 023
    • 031

    逆时针(让它们双面)

    • 032
    • 013

    最后,因为我们不希望索引从 0 开始,而是在 currentIndex 成为之前的相同值

    • currentIndex+0currentIndex+2currentIndex+3
    • currentIndex+0currentIndex+3currentIndex+1

    • currentIndex+0currentIndex+3currentIndex+2
    • currentIndex+0currentIndex+1currentIndex+3

【讨论】:

  • 对不起我的低级问题,但是 1. 将 i 添加到 j* texture.width 有什么意义 -> var color = pixels[i + j * texture.width]; 2. 不协调顶点向量,你正在添加/减去 0.5f,这是什么意思,我的意思是为什么我们将向量向左或向右移动等等。3.trianglesList.Add(currentIndex + 2); 我们正在添加 2、3 或 1 ?我真的不明白那些事情的数学逻辑,比如为什么我们需要移动坐标?再次对不起我的问题:(
  • @anónimo 我在答案底部添加了解释;)
  • 你是如此完美的人类:) 谢谢你的时间
猜你喜欢
  • 2019-09-15
  • 2014-03-14
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 2015-05-19
  • 1970-01-01
  • 2011-03-05
  • 2015-05-31
相关资源
最近更新 更多