简体   繁体   中英

Unity3D - How to add textures to a mesh

I am making a cubic voxel game. I have chunks, world, blocks and mesh generation done, but there's one problem - I could not do the texturing.

Everything I need is just add a texture to a side of a 3D mesh (Texture of every is different.), I've seen some implementations but it's hard to read somebody else's code (I've tried to use them. but it didn't work), I've tried to do this by myself. but with no results.

Can anybody explain how to do this??

Here is my current code:

[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;
    }
}

NOTE: This is a repost with many edits so it is focused on one problem plus has better explanation. Sorry for that.

Like your SetVertices() and SetTriangles() , you can call a SetUVs() with a list of the UV coordinates of each vertex on your texture.

The UV list size must match the vertices list size!

The UV coordinate are expressed as Vector2 with values between 0 and 1. For example, to apply the whole texture on the front face of your cube, you have the first 4 uvs like this:

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

...

mesh.SetUVs(0, cubeUVs);

If your texture is not a square, then it will be stretched.

You should also call RecalculateBounds() and RecalculateNormals() at the end of your GenerateMesh() method to avoid some issues later.

EDIT

If you really want different texture files for each side of the cube, then the cleanest and most performant solution for me is to set a different VertexColor for each side of your cube, eg. (1,0,0), (0,1,0), (0,0,1), (1,1,0), (1,0,1) and (0,1,1).
However, you will have to duplicate all your vertices 3 times. (because the vertex color is bound to a vertex, and each vertex of a cube belongs to 3 sides)
(You still have to set the UVs like I said previously, but each side has the whole texture instead of only a part of the texture)

Then, you will have to create a custom shader with 6 textures in inputs (one for each side).
And in the fragment function, you select the right texture color according to the vertex color.
You can for that, do some if to select the texture, but it will be not very performant:

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

Or if you want more perf (with a lot of cubes), you can instead do some multiplications to select the right texture:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM