Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Bug Copying mesh data results in corrupted copy - simple repro

Discussion in 'Scripting' started by Zergling103, May 2, 2023.

  1. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    I'm trying to copy the contents of a mesh (vertex positions, normals, and triangle indices) from a source mesh to a destination mesh.

    The end goal isn't just to copy them, (I intend on modifying the mesh at some point) but it seems even doing a simple copy is broken:

    Code (CSharp):
    1. // This extremely simple mesh copying function somehow does not work.
    2. Mesh CopyMesh(Mesh mesh)
    3. {
    4.     var vertices = mesh.vertices;
    5.     var normals = mesh.normals;
    6.     var triangles = mesh.triangles;
    7.  
    8.     var meshOut = new Mesh();
    9.     meshOut.vertices = vertices;
    10.     meshOut.normals = normals;
    11.     meshOut.triangles = triangles;
    12.     return meshOut;
    13. }
    Expected behaviour: The contents (vertex positions, normals, and connectivity) of the first mesh are copied to the second mesh, but are combined into a single submesh (if the source mesh has multiple submeshes).
    Actual behaviour: The resulting mesh has broken geometry. Most of it appears normal, but many of the triangles are missing and others are connecting random vertices.

    Notes:
    • I don't care about keeping submeshes separate in the copy.
    • The mesh I'm having trouble with has 2 submeshes.
    • I've tried using GetTriangles() and SetTriangles() with various combinations of arguments with the exact same corrupted geometry resulting each time. E.g GetTriangles(0), GetTriangles(0, true/false), etc.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
    That simplifies things.

    What are some of the numbers coming back for your submesh triangle count vs that triangles list's length?

    That one array is supposed to have ALL triangles, but maybe that's not the case??

    And when you say simple, how simple can you get it? Two triangles on two submeshes perhaps?
     
    ansdyd0803 likes this.
  3. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    Original mesh:
    .triangles.Length: 392208
    .subMeshCount: 2
    .GetTriangles(0).Length: 385680
    .GetTriangles(1).Length: 6528

    Copied mesh:
    .triangles.Length: 392208
    .subMeshCount: 1
    .GetTriangles(0).Length: 392208

    Simple as in the code is as straightforward as it could possibly be but still breaks.

    I suspect that the two submeshes do not share the same vertices. Thus, the indices for the second submesh start at 0 instead of where the first submesh's vertices end. However, I've tried to simply ignore the second submesh (using GetTriangles(0) and SetTriangles(0) instead of .triangles) and wound up with the same broken geometry problem, which seems to destroy that theory.
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    What Unity version is this?

    I would also test on very simple shapes first before moving into complicated meshes. Start with the Unity primitives.

    I've got my own tool that I use to duplicate meshes into the same asset, made in 2021 and haven't experienced this. Though I'm also copying the Tangents as well.

    Start small, debug plenty. Took me a bit to get my tool working.
     
  5. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    2021.3.15f1

    I think it is possible that the mesh itself is the problem, as I've tried another fairly complex mesh with 2 submeshes and it works fine.

    Which... isn't a very satisfying answer, as Unity seems to have no problem drawing the mesh.
     
  6. ansdyd0803

    ansdyd0803

    Joined:
    Nov 27, 2020
    Posts:
    4
    Hello,
    When I tried a large mesh parser, I had the same bug.
    UnityEngine.Mesh vertice has a default with represents 65535.
    Try this?

    // This extremely simple mesh copying function somehow does not work.
    Mesh CopyMesh(Mesh mesh)
    {
    var vertices = mesh.vertices;
    var normals = mesh.normals;
    var triangles = mesh.triangles;

    var meshOut = new Mesh();
    meshOut.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
    meshOut.vertices = vertices;
    meshOut.normals = normals;
    meshOut.triangles = triangles;
    return meshOut;
    }
     
    Bunny83 and Zergling103 like this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
    And what happens if you use
    .SetVertices()
    instead of assigning it to
    .vertices
    ?

    https://docs.unity3d.com/ScriptReference/Mesh.SetVertices.html

    (And obviously, if you have more than 64k verts you must do what Andy says above with the

    Code (csharp):
    1. meshOut.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
    ... line.)
     
    Bunny83 likes this.
  8. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    I think this solves it.

    Though, I'm kind of taken back that this is the solution. You'd think that they'd have written this property to be robust and check for what sort of index format to use based on the values provided in the array.
     
  9. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    Yep, definitely works! Thanks!
     
    ansdyd0803 likes this.
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
  11. ansdyd0803

    ansdyd0803

    Joined:
    Nov 27, 2020
    Posts:
    4
    Sadly I don't know that... And It didn't solve the problem.
    We don't know how to work in SetVertices, But we can get a hint.
    In the unity docs,

    "Sets the vertex positions of the Mesh, using a part of the input array.

    This method behaves as if you called SetVertices with an array that is a slice of the whole array, starting at start index and being of a given length. The resulting Mesh has length amount of vertices."

    And in the unity git repo, SetVertices call with SetArrayForChannelImpl.

    We can just have these hints...
     
    Last edited: May 2, 2023