Question

I wrote a couple of functions to generate some tube shaped mesh that I needed. When I apply a texture to it however, the texture stretches off down the Z axis.

So I wrote a simpler demo, which contains 6 vertices and 4 triangles. It is basically two sides of a cube, attached on one side. The texture attaches how I expect it on the side that exists in the X,Y plane, but on the side that is in the X,Z plane the texture stretches instead of tiling.

The results is this:

enter image description here

The square at the back has the correct texture (it's a white background with a coloured square at each corner). The left square has an odd purple strip at the top, and a green stripe at the bottom. Since purple isn't in the original texture, I assume its somehow averaging across the texture or something.

I'm sure the issue is something fairly basic, but I'm pretty new to Unity. Thanks in advance!

The code that generates this is:

void textureTest(){

    Vector3[] vertices = new Vector3[6];

    vertices [0] = new Vector3 (0,0,0);
    vertices [1] = new Vector3 (1,0,0);
    vertices [2] = new Vector3 (0,-1,0);
    vertices [3] = new Vector3 (1,-1,0);

    vertices [4] = new Vector3 (0,0,-1);
    vertices [5] = new Vector3 (0,-1,-1);

    GameObject newTunnel = new GameObject ("TextureTest");
    Mesh newMesh = new Mesh ();
    newTunnel.AddComponent<MeshFilter> ();
    newTunnel.AddComponent<MeshRenderer> ();

    newMesh.vertices = vertices;

    Vector2[] uvs = new Vector2[newMesh.vertices.Length];
    for (int i = 0; i < uvs.Length; i++) {
        uvs [i] = new Vector2 (newMesh.vertices [i].x, newMesh.vertices [i].y);
    }
    newMesh.uv = uvs;

    int[] triangles = new int[]{0,1,2,3,2,1,5,4,0,2,5,0};

    newMesh.triangles = triangles;

    newMesh.RecalculateNormals ();

    newTunnel.GetComponent<MeshFilter> ().mesh = newMesh;

    if (blockMaterial) {
        newTunnel.renderer.material = blockMaterial;
    }

    newTunnel.AddComponent<MeshCollider> ();

}

Edit: The texture I'm using is here. I'm adding it because the screen shot is a bit dark.

enter image description here

Was it helpful?

Solution

This code:

Vector2[] uvs = new Vector2[newMesh.vertices.Length];
for (int i = 0; i < uvs.Length; i++) {
    uvs [i] = new Vector2 (newMesh.vertices [i].x, newMesh.vertices [i].y);
}
newMesh.uv = uvs;

Is equivalent to this:

Vector2[] uvs = new Vector2[6];
uvs[0] = new Vector2(0,0);
uvs[1] = new Vector2(1,0);
uvs[2] = new Vector2(0,-1);
uvs[3] = new Vector2(1,-1);
uvs[4] = new Vector2(0,0);
uvs[5] = new Vector2(0,-1);
newMesh.uv = uvs;

The UV coordinates for the square on the left are (0,0), (0,-1), (0,0), (0,-1). So it's a 0-pixel wide vertical strip along the left and the right borders of the texture. Interpolation is yielding avg(red,blue) => (purple) and avg(green,yellow) => (greenish-yellow).

Try this instead:

Vector2[] uvs = new Vector2[6];
uvs[0] = new Vector2(0,0);
uvs[1] = new Vector2(1,0);
uvs[2] = new Vector2(0,-1);
uvs[3] = new Vector2(1,-1);
uvs[4] = new Vector2(-1,0);
uvs[5] = new Vector2(-1,-1);
newMesh.uv = uvs;

Your confusion is because you are associating UV coordinates with world location. Don't do that. Use the vertex index instead. For example, order the vertices in your triangle strip like this:

0 - 2 - 4 - 6 - 8
| / | / | / | / |
1 - 3 - 5 - 7 - 9

Set UV coordinates of vertex i to (i / 2, i % 2).

Set triangles to (0,1,2),(1,2,3),(2,3,4),(3,4,5),...

If you want to make a tube that wraps around, just make sure to make the last two triangles reference the first two vertices, like so:

0 - 2 - 4 - 6 - 0
| / | / | / | / |
1 - 3 - 5 - 7 - 1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top