Search Unity

Modifying vertices using advanced mesh API

Discussion in 'General Graphics' started by MostNimbus, Dec 12, 2021.

  1. MostNimbus

    MostNimbus

    Joined:
    Dec 21, 2016
    Posts:
    15
    I need some help with the new mesh api. The documentation is so sparse it's hard to find anything useful yet.I create my mesh using:

    Code (CSharp):
    1. mesh.SetVertexBufferParams(vertices.Length, new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32));            
    2. mesh.SetVertexBufferData(vertices, 0, 0, vertices.Length);                    
    3.  
    4. mesh.SetIndexBufferParams(triangles.Length, IndexFormat.UInt32);            
    5. mesh.SetIndexBufferData(triangles, 0, 0, triangles.Length);            
    6.  
    7. mesh.SetSubMesh(0, new SubMeshDescriptor(0, triangles.Length));
    Then, I need to modify said mesh's vertices. Modifying the NativeArray directly does nothing, and calling SetVertexBufferData again results in https://imgur.com/ArFNUzB (before calling SetVertexBufferData again it looks like it's supposed to: https://imgur.com/jvpJTgW).

    What's the proper way to modify vertices using advanced mesh API? Is it even possible, without allocating an extra array for modified vertices?
     
  2. paddan

    paddan

    Unity Technologies

    Joined:
    Jun 19, 2019
    Posts:
    13
    When using SetVertexBufferData the data gets copied into the internal vertex data, which is why changing the original NativeArray will not result in any changes in the mesh. You could however make changes to your NativeArray and then call SetVertexBufferData with it again, which avoids creating a new array for your modified vertices.

    Something along the lines of:
    Code (CSharp):
    1. //Set initial vertices
    2. var tempVertices = new[]
    3. {
    4.         new Vector3(-1f,0,-1f),
    5.         new Vector3(1f,0,-1f),
    6.         new Vector3(1f,0,1f),
    7.         new Vector3(-1,0,1),
    8.         new Vector3(0,2,0)
    9. };
    10. m_vertices = new NativeArray<Vector3>(tempVertices, Allocator.Persistent);
    11. m_mesh.SetVertexBufferParams(tempVertices.Length, new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32));
    12. m_mesh.SetVertexBufferData(tempVertices, 0, 0, tempVertices.Length);
    13.  
    14. //Modify at some later stage
    15. m_vertices[0] = new Vector3(-0.5f, 0, -0.5f);
    16. m_vertices[1] = new Vector3(0.5f, 0, -0.5f);
    17. m_vertices[2] = new Vector3(0.5f, 0, 0.5f);
    18. m_vertices[3] = new Vector3(-0.5f, 0, 0.5f);
    19. m_vertices[4] = new Vector3(0, 1, 0);
    20. m_mesh.SetVertexBufferData(m_vertices, 0, 0, m_vertices.Length);

    What does the code look like the second time you call SetVertexBufferData? I can't see why setting the data again would cause issues. Have you verified that the new vertex positions are valid?
     
  3. atr0phy

    atr0phy

    Joined:
    Nov 5, 2014
    Posts:
    43
    Not to resurrect this but as MostNimbus said, it doesn't work like that (see his first screenshot of what happens if you attempt what you're suggesting.) If it does work like that and you omitted some important step, then I'd love to see a barebones, fully functional example.

    E.g. I have a method that initializes the mesh after I fill the NativeArray:
    Code (CSharp):
    1.     private void InitializeMesh()
    2.     {
    3.         _mesh.SetVertexBufferParams(_mvertices.Length,
    4.             new VertexAttributeDescriptor(VertexAttribute.Position, dimension: 3),
    5.             new VertexAttributeDescriptor(VertexAttribute.Normal, dimension: 3),
    6.             new VertexAttributeDescriptor(VertexAttribute.TexCoord0, dimension: 2)
    7.         );
    8.         _mesh.SetVertexBufferData(_mvertices, 0, 0, _mvertices.Length, 0);
    9.  
    10.         _mesh.SetIndexBufferParams(_indices.Length, IndexFormat.UInt32);
    11.         _mesh.SetIndexBufferData(_indices, 0, 0, _indices.Length);
    12.        
    13.         _mesh.subMeshCount = 1;
    14.         _mesh.SetSubMesh(0, new SubMeshDescriptor(0, _indices.Length, MeshTopology.Triangles)
    15.         {
    16.             firstVertex = 0,
    17.             vertexCount = _mvertices.Length
    18.         }, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontNotifyMeshUsers);
    19.         _mesh.bounds = new Bounds(Vector3.zero, Vector3.one * 1000);
    20.     }
    21.  
    Which results in this:



    Then, any time I modify the NativeArray, I have to call InitializeMesh() again. I.e.:
    Code (CSharp):
    1.             _mvertices[0] = new MeshVertex()
    2.             {
    3.                 vertex = new float3(0, 10, 0),
    4.                 normal = new float3(0, 0, 1),
    5.                 uv = new float2(0, 0),
    6.             };
    7.  
    8.             InitializeMesh();
    That works, of course, it results in this:



    But if I attempt what you suggested... i.e.:
    Code (CSharp):
    1.             _mvertices[0] = new MeshVertex()
    2.             {
    3.                 vertex = new float3(0, 10, 0),
    4.                 normal = new float3(0, 0, 1),
    5.                 uv = new float2(0, 0),
    6.             };
    7.        
    8.             _mesh.SetVertexBufferData(_mvertices, 0, 0, _mvertices.Length, 0);
    9.  
    ...it results in incredibly broken geometry, like this:



    I'm using a height-based color effect for my custom wireframe shader. So it looks to me like the GPU is reading that absurdly incorrect vertex position correctly. Also note I turned on Unity's shaded wireframe to see if the editor could make sense of that geometry, which unsurprisingly it can't.

    All that said, if there's an actual proper way to update the vertices in this mesh API without having to re-set all the other data that it should already have, I would definitely love to hear it.
     
  4. paddan

    paddan

    Unity Technologies

    Joined:
    Jun 19, 2019
    Posts:
    13
    I left out the creation of the index buffer and the sub mesh, as I did not want to take up too much space. I'll include a small script that modifies a vertex position.

    You should not have to do the whole initialization again if you're not changing the vertex count, or any data types.

    Are you sure that the other data in your cached vertex buffer is valid? Is the index buffer valid? If so I would suggest creating a bug report with a minimal repo of the issue.
     

    Attached Files:

    DragonCoder likes this.