Flipping mesh for performance

Hello,

We compose the enemies of our game by constructing them out of a small subset of meshes and materials. I recently noticed in the frame debugguer that Unity doesn’t like transforms with negative scales. So I started doing a script to generate meshes with flipped vertices to replace those and avoid those warnings. Coupled with instancing, it greatly reduces our draw call count!

Unfortunately, I seem to be missing something as the result isn’t exactly what I expected it to be.

    Mesh FlipMesh(Mesh mesh, Vector3 scale) // scale = -1 or 1 per component, will also be applied to transform
    {
        vertices.Clear();
        normals.Clear();
        mesh.GetVertices(vertices);
        mesh.GetNormals(normals);

        for (int i = 0; i < vertices.Count; i++)
            vertices[i] = Vector3.Scale(vertices[i], scale);
        for (int i = 0; i < normals.Count; i++)
            normals[i] = Vector3.Scale(normals[i], scale);

        Mesh fixedMesh = new Mesh();

        fixedMesh.vertices = vertices.ToArray();
        fixedMesh.normals = normals.ToArray();

        fixedMesh.uv = mesh.uv;
        if (mesh.uv2 != null)
            fixedMesh.uv2 = mesh.uv2;
        if (mesh.colors != null)
            fixedMesh.colors = mesh.colors;
        else if (mesh.colors32 != null)
            fixedMesh.colors32 = mesh.colors32;

        fixedMesh.subMeshCount = mesh.subMeshCount;
        for (int i = 0; i < mesh.subMeshCount; i++)
            fixedMesh.SetIndices(mesh.GetIndices(i), mesh.GetTopology(i), i);

        fixedMesh.RecalculateTangents();
        fixedMesh.RecalculateBounds();

        return fixedMesh;
    }

It works on some enemies but I sometimes get weird results, like this :

I noticed on this one that if I manually flip the Y scale on the transform, I get something back that is close to the original but not quite and darker.

Any idea of what I would be missing ?

Well, while making a gif, I found the issue: I also needed to change the winding order. Here’s the updated code for anyone who would care!

    Mesh FlipMesh(Mesh mesh, Vector3 scale) // scale = -1 or 1 per component, will also be applied to transform
    {
        vertices.Clear();
        normals.Clear();
        mesh.GetVertices(vertices);
        mesh.GetNormals(normals);

        for (int i = 0; i < vertices.Count; i++)
            vertices[i] = Vector3.Scale(vertices[i], scale);
        for (int i = 0; i < normals.Count; i++)
            normals[i] = Vector3.Scale(normals[i], scale);

        Mesh fixedMesh = new Mesh();

        fixedMesh.vertices = vertices.ToArray();
        fixedMesh.normals = normals.ToArray();

        fixedMesh.uv = mesh.uv;
        if (mesh.uv2 != null)
            fixedMesh.uv2 = mesh.uv2;
        if (mesh.colors != null)
            fixedMesh.colors = mesh.colors;
        else if (mesh.colors32 != null)
            fixedMesh.colors32 = mesh.colors32;

        fixedMesh.subMeshCount = mesh.subMeshCount;
        for (int i = 0; i < mesh.subMeshCount; i++)
        {
            indices.Clear();
            mesh.GetIndices(indices, i);
            MeshTopology topology = mesh.GetTopology(i);
            switch (topology)
            {
                case MeshTopology.Triangles:
                {
                    for (int j = 0; j < indices.Count; j += 3)
                    {
                        int s = indices[j];
                        indices[j] = indices[j + 2];
                        indices[j + 2] = s;
                    }
                    break;
                }

                default:
                {
                    Debug.LogError("Unsupported topology: " + topology);
                    break;
                }
            }
            fixedMesh.SetIndices(indices.ToArray(), topology, i);
        }

        fixedMesh.RecalculateTangents();
        fixedMesh.RecalculateBounds();

        return fixedMesh;
    }
3 Likes