Procedurally generated mesh does not look quite right with a pre-made material

Sorry in advance for any grammatical or lexical mistakes. English is not my first language.

I have a problem and the title describes it fairly good. Looking at the screenshot, those two objects have the same material on them. The key difference is, one on the right is a cube primitive, and the other is procedurally generated. As we can see, there is very ugly shading on my generated mesh. It seems like when looked from a close distance, some sort of static shows itself. It looks grainy and offputting.

There isn’t really much to the code i think.

{ // Creates an n-sided table for n >= 3 and a square table otherwise
    MeshFilter filter = TableManager.inst.GetComponent<MeshFilter>();
    Mesh mesh = new Mesh();

    filter.mesh = mesh;

    List<Vector3> vertices = new List<Vector3>();
    for (int i = 0; i < 2 * n; i++)
    {
        vertices.Add(new Vector3(Mathf.Cos(2 * Mathf.PI / n * (i + 0.5f)) * radius,
            i >= n ? -0.5f : 0f,
            Mathf.Sin(2 * Mathf.PI / n * (i + 0.5f)) * radius));
    }

    List<int> indices = new List<int>();
    for (int i = 0; i < n - 2; i++)
    {
        indices.Add(0);
        indices.Add(i + 2);
        indices.Add(i + 1);
    }
    for (int i = n; i < 2 * n - 2; i++)
    {
        indices.Add(n);
        indices.Add(i + 1);
        indices.Add(i + 2);
    }
    for (int i = 0; i < n - 1; i++)
    {
        indices.Add(i);
        indices.Add(i + 1);
        indices.Add(i + n + 1);
        indices.Add(i);
        indices.Add(i + 1 + n);
        indices.Add(i + n);
    }
    indices.Add(n - 1);
    indices.Add(0);
    indices.Add(n);
    indices.Add(n - 1);
    indices.Add(n);
    indices.Add(2 * n - 1);

    mesh.Clear();
    mesh.vertices = vertices.ToArray();
    mesh.triangles = indices.ToArray();
    mesh.RecalculateNormals();
    mesh.RecalculateTangents();
}

I have really no idea what causes this. Could anyone please help?

Hey, the reason for this should be that you’re not using enough vertices. Each vertex can only have one normal, tangent and UV coordinate per UV channel. This can be problematic when multiple faces use the same vertices, just like in your case.
In this case, it seems like the math behind RecalculateNormals decided to assign something like Vector3.up to the table’s upper vertices, and Vector3.down to the bottom ones. The faces on the table’s sides then try to use these same normals (and lerp between them based on UVs which you’re not calculating in your script) since - as mentioned - each vertex can only have one normal.

If you take a look at Unity’s default cube mesh, you’ll see that it actually has 24 vertices and not 8 because of this reason. Each corner of the cube has three “duplicate vertices”, one for each side at the respective corner so they can hold different normals, tangents and UVs. The normals for one corner then look like this:


Of course the indices then need to index the correct “duplicate vertices” for each side.
Also discussed here: Why does a primitive cube contain 24 verts??

1 Like

Thank you so much, you’re a lifesaver! Your answer was really helpful.

1 Like