Fixing Uvs on a mesh by code cylinder

So I’ve just constructed a Cylinder by code (I know its sloppy) but when I apply a texture and compare it to a normal unity cylinder the texture seems backwards I think. If anyone knows what I did wrong and can help me fix this I’d appreciate it A LOT. Also if you could educate me on how a for loop is made for the vertices and triangles that would be cool too.

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class BuildMesh : MonoBehaviour
{
//Litterally just for me to remember where locations are (They have no purpose)
public Vector3 verticesLoc;
public Vector3 verticesLocBack;

// Use this for initialization
void Start()
{
    MeshFilter mf = GetComponent<MeshFilter>();
    Mesh mesh = mf.mesh;

    //Vertices
    Vector3[] vertices = new Vector3[]
    {
        //Constructed Clockwise (So is visible from  outside)
        #region Front Face
        //Top
        new Vector3(0.0f, 0.5f, 1),             //0

        new Vector3(-0.15f, 0.475f, 1),         //1
        new Vector3(-0.295f, 0.405f, 1),        //2
        new Vector3(-0.405f, 0.295f, 1),        //3
        new Vector3(-0.475f, 0.15f, 1),         //4
        //Right
        new Vector3(-0.5f, 0.0f, 1),            //5

        new Vector3(-0.475f, -0.15f, 1),        //6
        new Vector3(-0.405f, -0.295f, 1),       //7
        new Vector3(-0.295f, -0.405f, 1),       //8
        new Vector3(-0.15f, -0.475f, 1),        //9
        //Bottom
        new Vector3(0.0f, -0.5f, 1),            //10

        new Vector3(0.15f, -0.475f, 1),         //11
        new Vector3(0.295f, -0.405f, 1),        //12
        new Vector3(0.405f, -0.295f, 1),        //13
        new Vector3(0.475f, -0.15f, 1),         //14
        //Left
        new Vector3(0.5f, 0f, 1),               //15

        new Vector3(0.475f, 0.15f, 1),          //16
        new Vector3(0.405f, 0.295f, 1),         //17
        new Vector3(0.295f, 0.405f, 1),         //18
        new Vector3(0.15f, 0.475f, 1),          //19
        //Center
        new Vector3(0.0f, 0.0f, 1),             //20
        #endregion

        //Constructed Counter Clockwise (So is visible from  outside)
        #region Back Face
        //Top
        new Vector3(0.0f, 0.5f, -1),             //21

        new Vector3(0.15f, 0.475f, -1),          //22
        new Vector3(0.295f, 0.405f, -1),         //23
        new Vector3(0.405f, 0.295f, -1),         //24
        new Vector3(0.475f, 0.15f, -1),          //25
        //Left
        new Vector3(0.5f, 0f, -1),               //26
        new Vector3(0.475f, -0.15f, -1),         //27
        new Vector3(0.405f, -0.295f, -1),        //28
        new Vector3(0.295f, -0.405f, -1),        //29
        new Vector3(0.15f, -0.475f, -1),         //30
        //Bottom
        new Vector3(0.0f, -0.5f, -1),            //31

        new Vector3(-0.15f, -0.475f, -1),        //32
        new Vector3(-0.295f, -0.405f, -1),       //33
        new Vector3(-0.405f, -0.295f, -1),       //34
        new Vector3(-0.475f, -0.15f, -1),        //35
        //Right
        new Vector3(-0.5f, 0.0f, -1),            //36

        new Vector3(-0.475f, 0.15f, -1),         //37
        new Vector3(-0.405f, 0.295f, -1),        //38
        new Vector3(-0.295f, 0.405f, -1),        //39
        new Vector3(-0.15f, 0.475f, -1),         //40
        //Center
        new Vector3(0.0f, 0.0f, -1)              //41
        #endregion
    };

    //Triangles 3 points clockwise determines side visable
    int[] triangle = new int[]
    {
        //Octogon numbers are related to comments next to vertices
        #region Front Face
        0,1,20,
        1,2,20,
        2,3,20,
        3,4,20,
        4,5,20,
        5,6,20,
        6,7,20,
        7,8,20,
        8,9,20,
        9,10,20,
        10,11,20,
        11,12,20,
        12,13,20,
        13,14,20,
        14,15,20,
        15,16,20,
        16,17,20,
        17,18,20,
        18,19,20,
        19,0,20,
        #endregion

        #region Back Face
        21,22,41,
        22,23,41,
        23,24,41,
        24,25,41,
        25,26,41,
        26,27,41,
        27,28,41,
        28,29,41,
        29,30,41,
        30,31,41,
        31,32,41,
        32,33,41,
        33,34,41,
        34,35,41,
        35,36,41,
        36,37,41,
        37,38,41,
        38,39,41,
        39,40,41,
        40,21,41,
        #endregion

        //Goes clock wise around the cylinder starting at the top (Right top, Right Bottom, Left Bottom, Left Top)
        #region Body
        //Top Right Section
        0,21,40,
        40,1,0,
        1,40,39,
        39,2,1,
        2,39,38,
        38,3,2,
        3,38,37,
        37,4,3,
        4,37,36,
        36,5,4,
        //Bottom Right Section
        5,36,35,
        35,6,5,
        6,35,34,
        34,7,6,
        7,34,33,
        33,8,7,
        8,33,32,
        32,9,8,
        9,32,31,
        31,10,9,
        //Bottom Left Section
        10,31,30,
        30,11,10,
        11,30,29,
        29,12,11,
        12,29,28,
        28,13,12,
        13,28,27,
        27,14,13,
        14,27,26,
        26,15,14,
        //Top Left Section
        15,26,25,
        25,16,15,
        16,25,24,
        24,17,16,
        17,24,23,
        23,18,17,
        18,23,22,
        22,19,18,
        19,22,21,
        21,0,19
        #endregion
    };

    //For loop to take x and y of vertices to construct UVS
    Vector2[] UVS = new Vector2[vertices.Length];
    for (var i = 0; i < vertices.Length; i++)
    {
        UVS <em>= new Vector2(vertices_.x, vertices*.y);*_</em>

}
//Clear mesh values
mesh.Clear();
//Put in my values
mesh.vertices = vertices;
mesh.triangles = triangle;
mesh.uv = UVS;
//Put back togeather
MeshUtility.Optimize(mesh);
mesh.RecalculateNormals();
//Create a mesh collider on this object and assign it to the mesh
MeshCollider meshCollider = gameObject.AddComponent(typeof(MeshCollider)) as MeshCollider;
meshCollider.sharedMesh = mesh;
}
}

There is not much to “fix” here ^^. The UVs you create are a 2d projection along the x-y plane. You simply use the spatial position as UV coordinates which would work for flat meshes but not for 3d objects.

Next thing is a cylinder consists of 3 seperate parts: the top, the bottom and the “side” face(s). Those 3 parts have to use seperate normal vectors as edges between those parts are not continuous. You have to have a sharp edge there. That means you have to use seperate vertices for those 3 parts. Currently you share the vertices between the top / bottom side and the surrounding faces which doesn’t work that way.

Generally there are many different ways how you could “unwrap” / UV map a cylinder. However the most common way would be to map the surrounding faces like it’s a single rectangle once unrolled and to map the two circles onto the center of the texture.

To create a cylinder procedurally you usually want to create the vertices dynamically. Currently you have them hardcoded so it’s like you have created it in a modelling tool.

Here’s a procedural cylinder including UV and normal calculation. You can specify how many sides it should have, the radius, the height and the orientation as a Vector3 as well as a percentage value where the pivot should be:

using UnityEngine;

[RequireComponent(typeof(MeshFilter)), RequireComponent(typeof(MeshRenderer))]
public class ProceduralCylinder : MonoBehaviour
{
    public Vector3 direction = Vector3.forward;
    public float pivotPos = 0.5f;
    public float radius = 0.5f;
    public float height = 1f;
    public int sides = 3;
    public float phase = 0f;

	void Start ()
    {
        GetComponent<MeshFilter>().sharedMesh = CreateCylinder(direction, pivotPos, radius, height, sides, phase);
	}

    public static Mesh CreateCylinder(Vector3 aDir, float aPivot, float aRadius, float aHeight, int aSides, float aPhaseOffset)
    {
        aDir.Normalize();
        aSides = Mathf.Max(3, aSides);
        Vector3 u = Vector3.up;
        Vector2 uv = Vector2.right*0.5f;
        if (Mathf.Abs(aDir.y) > 0.98f)
            u = -Vector3.forward;
        u = Vector3.ProjectOnPlane(u, aDir).normalized;
        u = Quaternion.AngleAxis(aPhaseOffset, aDir) * u;
        Quaternion q = Quaternion.AngleAxis(360f / aSides, aDir);
        Quaternion q2 = Quaternion.AngleAxis(360f / aSides, -Vector3.forward);
        Vector3[] vertices = new Vector3[(aSides+1) * 4 + 2];
        Vector3[] normals = new Vector3[vertices.Length];
        Vector2[] UVs = new Vector2[vertices.Length];
        int[] triangles = new int[aSides * 12];
        // bottom / top center
        Vector3 b = vertices[0] = -aDir * aPivot*aHeight;
        Vector3 t = vertices[1] = aDir * (1f-aPivot) * aHeight;
        normals[0] = -aDir;
        normals[1] = aDir;
        UVs[0] = UVs[1] = new Vector2(0.5f, 0.5f);
        int count = aSides + 1;
        for (int i = 0; i < count; i++)
        {
            // bottom + sides bottom vertices
            vertices[2 + i] = vertices[2 + count + i] = b + u * aRadius;
            // sides top + top vertices
            vertices[2 + count* 2 + i] = vertices[2 + count * 3 + i] = t + u * aRadius;

            // bottom normal
            normals[2 + i] = -aDir;
            // top normal
            normals[2 + count * 3 + i] = aDir;
            // sides normals
            normals[2 + count + i] = normals[2 + count * 2 + i] = u;

            // bottom UV
            UVs[2 + i] = new Vector2(uv.x + 0.5f, uv.y + 0.5f);
            // sides UV
            float x = (float)i / (aSides);
            UVs[2 + count * 1 + i] = new Vector2(x, 0f);
            UVs[2 + count * 2 + i] = new Vector2(x, 1f);
            // top UV
            UVs[2 + count * 3 + i] = new Vector2(-uv.x + 0.5f, uv.y + 0.5f);

            // rotate vectors
            u = q * u;
            uv = q2 * uv;

        }
        for(int i = 0; i < aSides; i++)
        {
            // bottom face
            triangles[i * 12] = 0;
            triangles[i * 12 + 1] = 2 + i + 1;
            triangles[i * 12 + 2] = 2 + i;

            // top face
            triangles[i * 12 + 3] = 1;
            triangles[i * 12 + 4] = 2 + count * 3 + i;
            triangles[i * 12 + 5] = 2 + count * 3 + i + 1;

            // sides faces
            triangles[i * 12 + 6] = 2 + count * 1 + i;
            triangles[i * 12 + 7] = 2 + count * 1 + i + 1;
            triangles[i * 12 + 8] = 2 + count * 2 + i;

            triangles[i * 12 + 9] = 2 + count * 2 + i + 1;
            triangles[i * 12 + 10] = 2 + count * 2 + i;
            triangles[i * 12 + 11] = 2 + count * 1 + i + 1;

        }
        Mesh m = new Mesh();
        m.vertices = vertices;
        m.normals = normals;
        m.uv = UVs;
        m.triangles = triangles;
        return m;
    }
}

You can use the static ProceduralCylinder.CreateCylinder anywhere you like or attach the script to a gameobject and set the parameters in the inspector. Note that if “aPivot” is “0” the origin will be at the “bottom” of the cylinder, if it’s 1 the origin will be at the top and if it’s 0.5 it’s in the center.

The UVs are not exactly like Unity’s cylinder mesh. My cylinder wraps the texture around the cylinder once while Unity’s mesh does wrap it around twice. That means Unity has two UV seams while mine has only one at the side.