Unity3D - 如何向网格添加纹理

Unity3D - How to add textures to a mesh

我正在制作立方体素游戏。我已经完成了块、世界、块和网格生成,但是有一个问题 - 我无法进行纹理化。

我只需要在 3D 网格的一侧添加一个纹理(每个纹理都不一样!)。我见过一些实现,但很难阅读别人的代码(我曾尝试使用它们,但没有用)。我试过自己做,但没有结果。

谁能解释一下如何做到这一点?

这是我当前的代码:

[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class Chunk : MonoBehaviour
{
    private ushort[] _voxels = new ushort[16 * 16 * 16];
    private MeshFilter meshFilter;
    private Vector3[] cubeVertices = new[] {
        new Vector3 (0, 0, 0),
        new Vector3 (1, 0, 0),
        new Vector3 (1, 1, 0),
        new Vector3 (0, 1, 0),
        new Vector3 (0, 1, 1),
        new Vector3 (1, 1, 1),
        new Vector3 (1, 0, 1),
        new Vector3 (0, 0, 1),
    };
    private int[] cubeTriangles = new[] {
        // Front
        0, 2, 1,
        0, 3, 2,
        // Top
        2, 3, 4,
        2, 4, 5,
        // Right
        1, 2, 5,
        1, 5, 6,
        // Left
        0, 7, 4,
        0, 4, 3,
        // Back
        5, 4, 7,
        5, 7, 6,
        // Bottom
        0, 6, 7,
        0, 1, 6
    };

    public ushort this[int x, int y, int z]
    {
        get { return _voxels[x * 16 * 16 + y * 16 + z]; }
        set { _voxels[x * 16 * 16 + y * 16 + z] = value; }
    }

    void Start()
    {
        meshFilter = GetComponent<MeshFilter>();
    }

    private void Update()
    {
        GenerateMesh();
    }

    public void GenerateMesh()
    {
    Mesh mesh = new Mesh();
    List<Vector3> vertices = new List<Vector3>();
    List<int> triangles = new List<int>();

    for (var x = 0; x < 16; x++)
    {
        for (var y = 0; y < 16; y++)
        {
            for (var z = 0; z < 16; z++)
            {
                var voxelType = this[x, y, z];
                if (voxelType == 0)
                    continue;
                var pos = new Vector3(x, y, z);
                var verticesPos = vertices.Count;
                foreach (var vert in cubeVertices)
                    vertices.Add(pos + vert);
                foreach (var tri in cubeTriangles)
                    triangles.Add(verticesPos + tri);
            }
        }
    }

    mesh.SetVertices(vertices);
        mesh.SetTriangles(triangles.ToArray(), 0);
    meshFilter.mesh = mesh;
    }
}

注意:这是经过多次编辑的重新发布,因此它专注于一个问题并且有更好的解释。抱歉。

像您的 SetVertices()SetTriangles() 一样,您可以调用一个 SetUVs(),其中包含纹理上每个顶点的 UV 坐标列表。

UV 列表大小必须与顶点列表大小匹配!

UV坐标表示为Vector2,取值在0到1之间。 例如,要在立方体的正面应用整个纹理,您有前 4 个 uv,如下所示:

private Vector2[] cubeUVs = new[] {
    new Vector2 (0, 0),
    new Vector2 (1, 0),
    new Vector2 (1, 1),
    new Vector2 (0, 1),
    ...
}

...

mesh.SetUVs(0, cubeUVs);

如果您的纹理不是正方形,则会被拉伸。

您还应该在 GenerateMesh() 方法的末尾调用 RecalculateBounds()RecalculateNormals() 以避免以后出现一些问题。

编辑

如果你真的想要立方体的每一面都有不同的纹理文件,那么最干净和最高效的解决方案对我来说是为你的立方体的每一面设置不同的 VertexColor ,例如。 (1,0,0)、(0,1,0)、(0,0,1)、(1,1,0)、(1,0,1) 和 (0,1,1)。
但是,您必须将所有顶点复制 3 次。 (因为顶点颜色绑定了一个顶点,立方体的每个顶点属于3条边)
(你仍然需要像我之前说的那样设置 UV,但是每一面都有整个纹理而不是只有一部分纹理)

然后,您将必须创建一个自定义着色器,其中输入有 6 个纹理(每侧一个)。
在片段函数中,你select根据顶点颜色选择正确的纹理颜色。
为此,您可以对 select 纹理做一些 if,但它的性能不是很好:

float3 finalColor;
if(vertexColor.r > 0.5f && vertexColor.g < 0.5f && vertexColor.b < 0.5f)
{
    finalColor = text2D(_TopTexture, in.uv);
}
else if(...)
{
    ...
}
...

或者,如果您想要更高的性能(有很多立方体),您可以改为对 select 正确的纹理进行一些乘法运算:

float3 topTexColor = text2D(_TopTexture, in.uv) * vertexColor.r * (1.0f - vertexColor.g) * (1.0f - vertexColor.b);
float3 frontTexColor = ...;
...
float3 finalColor = topTexColor + frontTexColor + ...;