Is it possible to UV map a cylinder without duplicating a column of vertices?

I’ve procedurally generated a mesh of a mushroom, and I’m currently trying to get the UV maps added to it. I’ve managed it no problem for the cap and gills, but I’m running into a problem with the stem. I’ve mapped all the vertices to equally spaced points in the UV plane, but the problem that arises is that the triangles between the last and first vertices now stretch the entirety of the plane, causing the squished texture you see here in the last column of triangles. Of course, I could duplicate the first row of vertices and have the mesh actually be disconnected along that line, but that would make the edge hard, and I don’t want to do that. Besides, it seems rather inelegant to have that asymmetry in the geometry of what’s essentially a cylinder. I’ve had to duplicate the rings joining the cap to the gills and the gills to the stem, which, while more aesthetically acceptable, is still unpreferable. Is there a way to reuse vertices in the UVs without creating hard edges?

No, there’s no other way around that. However duplicating the vertices along the seam doesn’t make it a hard edge. Relying on RecalculatNormals will produce a hard edge because it doesn’t know about this “logical” connection. The easiest solution is if you don’t want to calculate all normals manually to use RecalculateNormals and after that iterate through the seam vertices in pairs and simply calculate the average of the two normals and assign the resulting normal to each pair.

Since we don’t know how you partition your vertices and how they are laid out in the array we can’t give you the exact solution here. However it’s something along

mesh.RecalculateNormals()
Vector3 normals = mesh.normals;
for(int i = 0; i < heightVertexCount; i++)
{
    int index1 = (calculate first vertex based on i);
    int index2 = (calculate paired vertex based on i);
    var n1 = normals[index1];
    var n2 = normals[index2];
    var n = (n1 + n2).normalized;
    normals[index1] = normals[index2] = n;
}

This will assign the same normal to each pair of vertices at the seam. Of course if you need this a lot you could put the “combining / averaging code” in a seperate method

static void AverageNormals(Vector3[] normals, int index1, int index2)
{
    var n1 = normals[index1];
    var n2 = normals[index2];
    var n = (n1 + n2).normalized;
    normals[index1] = normals[index2] = n;
}

So all you have to care about is calculating the right indices for your seam pairs.