Procedural Mesh UV problem

I’m learning the basics of mesh generation, and am having some trouble with mapping the correct UV to the new generated mesh.

This is the code I’m using to clone the mesh:

using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;

public class MeshDupe : MonoBehaviour
{
    public GameObject target;

    public List<Vector3> targetVertices = new List<Vector3>();
    public int[] targetTriangles;
    public List<Vector3> targetNormals = new List<Vector3>();
    public List<Vector4> targetTangents = new List<Vector4>();
    public Vector2[] targetUVs;

    public List<Vector3> newVertices = new List<Vector3>();
    public List<int> newTriangles = new List<int>();
    public List<Vector3> newNormals = new List<Vector3>();
    public List<Vector4> newTangents = new List<Vector4>();
    public List<Vector2> newUVs = new List<Vector2>();

    private Material targetMaterial;
    private Shader targetShader;

    [Button]
    void DupeMesh()
    {
        Mesh mesh = target.GetComponent<MeshFilter>().mesh;
    
        mesh.GetVertices(targetVertices);
        targetTriangles = mesh.triangles;
        mesh.GetNormals(targetNormals);
        mesh.GetTangents(targetTangents);
        targetUVs = mesh.uv;

        targetMaterial = target.GetComponent<Renderer>().material;
        targetShader = targetMaterial.shader;

        for (int i = 0; i < targetTriangles.Length; i += 3)
        {
            Vector3 v0 = targetVertices[targetTriangles[i + 0]];
            Vector3 v1 = targetVertices[targetTriangles[i + 1]];
            Vector3 v2 = targetVertices[targetTriangles[i + 2]];

            Vector2 uv0 = targetUVs[targetTriangles[i + 0]];
            Vector2 uv1 = targetUVs[targetTriangles[i + 1]];
            Vector2 uv2 = targetUVs[targetTriangles[i + 2]];

            AddData(v0, uv0, i);
            AddData(v1, uv1, i + 1);
            AddData(v2, uv2, i + 2);
        }
        CreateNew();
    }
    void AddData(Vector3 v, Vector2 uv, int i)
    {
        if (!newVertices.Contains(v))
        {
            newVertices.Add(v);
            newNormals.Add(targetNormals[targetTriangles[i]]);
            newTangents.Add(targetTangents[targetTriangles[i]]);
            newUVs.Add(uv);
        }
        newTriangles.Add(newVertices.IndexOf(v));     
    }
    void CreateNew()
    {
        GameObject dupe = new GameObject("dupe");
        MeshRenderer meshRenderer = dupe.AddComponent<MeshRenderer>();
        meshRenderer.sharedMaterial = new Material(Shader.Find("Standard"));
        MeshFilter meshFilter = dupe.AddComponent<MeshFilter>();
        Mesh newMesh = new Mesh();

        MeshCollider posCollider = dupe.AddComponent<MeshCollider>();
        posCollider.sharedMesh = newMesh;
        newMesh.SetVertices(newVertices);
        newMesh.SetTriangles(newTriangles, 0);
        newMesh.SetNormals(newNormals);
        newMesh.SetTangents(newTangents);
        newMesh.SetUVs(0, newUVs);

        meshFilter.mesh = newMesh;
        meshRenderer.material = targetMaterial;
        meshRenderer.material.shader = targetShader;

        target.SetActive(false);
    }
}

note: I’m creating this as an analog to another project, that is the reason I’m not referencing the mesh directly. In my project, I need to get the references from previously assigned lists.

This issue is pretty straight-forward to resolve. You need to add an additional vertices where the hard uv edge supposed to be.

now; edge 0-3 is shared between two polygons, causing interpolation between 50-0 & 51-3 edges:

  --50-------0-------1--
     |       |       |
     |       |       |
  --51-------3-------2--

fix; edges 0-3 & 51-52, while occupying identical positions, created an invisible split between two polygons and put an end to unwanted uv interpolation:

  --50-------51 0-------1--
    |        |  |       |
    |        |  |       |
  --53-------52 3-------2--

Every vertex has it’s very own UV. Pixels (surface between 3 vertices), on the other hand, have no UV data of their own so what GPU is doing is to calculate their uv from these vertex uv values. This interpolation can be observes as this gradient here.