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.

Feedback Wanted: Mesh scripting API improvements

Discussion in 'Graphics Experimental Previews' started by Aras, May 26, 2019.

  1. Minchuilla

    Minchuilla

    Joined:
    Feb 28, 2014
    Posts:
    16
    We have the SetVertexBufferData but what about the getter? It makes quite hard to modify an existing mesh without this.
     
  2. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    240
    Minchuilla likes this.
  3. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,419
    What happens if I import a mesh that has a 64 bit positioned set of vertices into the editor? -- Will those be precisely positioned in the future?

    Kinda wondering if this is going to be possible... Maybe a wrapper for when importing this sort of mesh?
     
  4. thatfrtd

    thatfrtd

    Joined:
    Apr 21, 2019
    Posts:
    8
    I have not seen any examples of how to use MeshDataArrays in jobs.

    I am sure there is a way to schedule a job that writes to the MeshDataArray from one system and then from another system in the main thread actually call ApplyAndDisposeWritableMeshData with that MeshDataArray.

    However, I can not figure it out. Any help would be great.
     
    pragmascript likes this.
  5. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    240
    Samples for the MeshData API can be found here: https://github.com/Unity-Technologies/MeshApiExamples-2020.1
     
    pragmascript, bsgbryan and Minchuilla like this.
  6. thatfrtd

    thatfrtd

    Joined:
    Apr 21, 2019
    Posts:
    8
    Thanks!
     
  7. Minchuilla

    Minchuilla

    Joined:
    Feb 28, 2014
    Posts:
    16
  8. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,690
    Would be nice if we could have multipe UVs per vertex on the same UV maps to avoid having to stack verts
     
  9. gnostici

    gnostici

    Joined:
    Jul 27, 2013
    Posts:
    23
    General API feedback:

    If I go to a specific part of the API documentation (say, Namespace Unity.Rendering), and it's for an older version, it's because Google took me there. When I see a button at the top that claims to take me to the current version, it lands me on a page that is not the API documentation and not Namespace Unity.Rendering. This basically takes me back to Google because for some unknown reason, it's nigh-unto impossible to find Unity documentation using Unity's website.

    Can we please, please get version linking that takes us to the correct page for the current version? If I land on an old version's scripting API page, then I may want that specifically that part of the API documentation for the current version. I almost certainly won't want the manual covering related concepts.
     
  10. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    47
    Hello all, I just made a non-GC allocating, Mesh.CopyTo() function using the new MeshData API in 2020.1. Essentially it creates a copy of an existing mesh without creating intermediate garbage and without requiring Lists to be already set-up prior to copying. Have a look:
    https://github.com/GeorgeAdamon/FastMeshCopy .

    Code (CSharp):
    1.  
    2. #define USE_UNSAFE // Comment this line to use the "safe" version of copying.
    3.  
    4. using Unity.Collections;
    5. using Unity.Collections.LowLevel.Unsafe;
    6. using UnityEngine;
    7. using UnityEngine.Rendering;
    8.  
    9.  
    10. /// <summary>
    11. /// Author: George Adamopoulos
    12. /// Version: 1.0.0
    13. /// Date: 2020-05-03
    14. /// License: GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
    15. /// </summary>
    16. public static class FastMeshCopyUtility
    17. {
    18.  
    19.     private const int SHORT_SIZE = 2;
    20.     private const int INT_SIZE = 4;
    21.     private const int FLOAT_SIZE = 4;
    22.  
    23. #if UNITY_2020_1_OR_NEWER
    24.     /// <summary>
    25.     /// Attempts to copy the data of the current <see cref="Mesh"/> to another one, as fast as possible,
    26.     /// with minimal allocations (a few tens of bytes in scenarios with very large meshes).
    27.     /// </summary>
    28.     public static void CopyTo(this Mesh inMesh, ref Mesh outMesh)
    29.     {
    30.         if (inMesh == null) return;
    31.  
    32.         if (outMesh == null)
    33.         {
    34.             outMesh = new Mesh {name = "Mesh Copy"};
    35.         }
    36.         else
    37.         {
    38.             outMesh.Clear();
    39.         }
    40.  
    41.  
    42.         using (var readArray = Mesh.AcquireReadOnlyMeshData(inMesh))
    43.         {
    44.             //-------------------------------------------------------------
    45.             // INPUT INFO
    46.             //-------------------------------------------------------------
    47.             var readData = readArray[0];
    48.  
    49.             // Formats
    50.             var vertexFormat = inMesh.GetVertexAttributes();
    51.             var indexFormat  = inMesh.indexFormat;
    52.             var isIndexShort =  indexFormat == IndexFormat.UInt16 ;
    53.            
    54.             // Counts
    55.             var vertexCount = readData.vertexCount;
    56.             var indexCount = isIndexShort ? data.GetIndexData<ushort>().Length : data.GetIndexData<uint>().Length;
    57.  
    58.             // Element Size in bytes
    59.             var indexSize = isIndexShort ? SHORT_SIZE : INT_SIZE;
    60.             var vertexSize = 0;
    61.  
    62.             for (var i = 0; i < vertexFormat.Length; i++)
    63.                 vertexSize += vertexFormat[i].dimension * FLOAT_SIZE;
    64.  
    65.  
    66.             //-------------------------------------------------------------
    67.             // OUTPUT SETUP
    68.             //-------------------------------------------------------------
    69.             var writeArray = Mesh.AllocateWritableMeshData(1);
    70.             var writeData  = writeArray[0];
    71.             writeData.SetVertexBufferParams(vertexCount, vertexFormat);
    72.             writeData.SetIndexBufferParams(indexCount, indexFormat);
    73.  
    74.             //-------------------------------------------------------------
    75.             // MEMORY COPYING
    76.             //-------------------------------------------------------------
    77.             NativeArray<byte> inData;
    78.             NativeArray<byte> outData;
    79.  
    80.             // Vertices
    81.             inData  = readData.GetVertexData<byte>();
    82.             outData = writeData.GetVertexData<byte>();
    83.  
    84.         #if USE_UNSAFE
    85.             unsafe
    86.             {
    87.                 UnsafeUtility.MemCpy(outData.GetUnsafePtr(), inData.GetUnsafeReadOnlyPtr(), vertexCount * vertexSize);
    88.             }
    89.         #else
    90.             inData.CopyTo(outData);
    91.         #endif
    92.  
    93.  
    94.             // Indices
    95.             inData  = readData.GetIndexData<byte>();
    96.             outData = writeData.GetIndexData<byte>();
    97.  
    98.         #if USE_UNSAFE
    99.             unsafe
    100.             {
    101.                 UnsafeUtility.MemCpy(outData.GetUnsafePtr(), inData.GetUnsafeReadOnlyPtr(), indexCount * indexSize);
    102.             }
    103.         #else
    104.             inData.CopyTo(outData);
    105.         #endif
    106.  
    107.             //-------------------------------------------------------------
    108.             // FINALIZATION
    109.             //-------------------------------------------------------------
    110.             writeData.subMeshCount = inMesh.subMeshCount;
    111.  
    112.             // Set all submeshes
    113.             for (var i = 0; i < inMesh.subMeshCount; i++)
    114.             {
    115.                 writeData.SetSubMesh(i,
    116.                                      new SubMeshDescriptor((int) inMesh.GetIndexStart(i),
    117.                                                            (int) inMesh.GetIndexCount(i)));}
    118.  
    119.  
    120.             Mesh.ApplyAndDisposeWritableMeshData(writeArray, outMesh);
    121.  
    122.  
    123.         outMesh.RecalculateBounds();
    124.     }
    125.  
    126. #else
    127.  
    128.     /// <summary>
    129.     /// Attempts to copy the data of the current <see cref="Mesh"/> to another one, as fast as possible,
    130.     /// with minimal allocations (a few tens of bytes in scenarios with very large meshes).
    131.     /// </summary>
    132.     public static void CopyTo(this Mesh inMesh, ref Mesh outMesh)
    133.     {
    134.             // PRE-UNITY 2020 WAY OF COPYING
    135.             outMesh.indexFormat = inMesh.indexFormat;
    136.             outMesh.SetVertices(inMesh.vertices);
    137.             outMesh.SetNormals(inMesh.normals);
    138.             outMesh.SetUVs(0,inMesh.uv);
    139.             outMesh.SetIndices(inMesh.GetIndices(0), inMesh.GetTopology(0), 0);
    140.             outMesh.SetColors(inMesh.colors);
    141.     }
    142. #endif
    143.  
    144. }
     
    Last edited: May 4, 2020
  11. Minchuilla

    Minchuilla

    Joined:
    Feb 28, 2014
    Posts:
    16
    Interesting, have you run any tests on the runtime? is there any speedup relative to the 2019 version of copying?

    Also with which macros did you run the performance test on the github page where you got 80 Bytes gc?
     
  12. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    47
    Both the
    UnsafeUtility.MemCpy
    and the
    NativeArray.CopyTo
    generate the same amount of garbage, since behind the scenes, the
    CopyTo
    is a
    MemCpy
    + safety checks.

    A test I run just now using the old way of copying, shows that the 2020.1 way is ~1.5x faster (150ms vs 90 ms excluding RecalculateBounds) and creates 875.000x less garbage (73 MB vs 80 B), if I'm not mistaken. (All that's for a 98 MB mesh with Positions, Normals & Tangents)
     
    Last edited: May 4, 2020
  13. Minchuilla

    Minchuilla

    Joined:
    Feb 28, 2014
    Posts:
    16
    Cool thanks for sharing the code and the extra details!
     
  14. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    47
    Just excited to test the new API! Definitely a step forward. @Aras It would be interesting to see if such a kind of usage makes sense.
     
  15. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    240
    Note that the above code won't copy over bind poses, weights, blend shapes or the original bounds. If your mesh uses multiple vertex buffer streams, you'll need to modify it to support those as well.

    Unfortunately, it's not currently possible to copy over bind poses or blend shapes without allocating garbage, but if you require that data to be copied over regardless, here is a similar set of APIs that I currently use in a project (I haven't checked if this compiles, I just stripped the relevant code out of my project, so YMMV):
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3.  
    4. public static class MeshUtility
    5. {
    6.     const MeshUpdateFlags DontUpdate = MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds | MeshUpdateFlags.DontValidateIndices;
    7.  
    8.     const MeshUpdateFlags DontUpdateOrNotify = DontUpdate | MeshUpdateFlags.DontNotifyMeshUsers;
    9.  
    10.     public static int GetIndexCount(Mesh.MeshData data)
    11.     {
    12.         int count = 0;
    13.  
    14.         for (int i = 0; i < data.subMeshCount; i++)
    15.             count += data.GetSubMesh(i).indexCount;
    16.  
    17.         return count;
    18.     }
    19.  
    20.     public static void CopyMeshData<T>(Mesh.MeshDataArray sourceArray, Mesh.MeshDataArray destinationArray)
    21.         where T : unmanaged, IVertexLayout
    22.     {
    23.         CopyMeshData(sourceArray, destinationArray, VertexLayout<T>.Layout);
    24.     }
    25.  
    26.     public static void CopyMeshData(Mesh.MeshDataArray sourceArray, Mesh.MeshDataArray destinationArray, VertexAttributeDescriptor[] attributes)
    27.     {
    28.         for (int i = 0; i < sourceArray.Length; i++)
    29.         {
    30.             var source = sourceArray[i];
    31.             var output = destinationArray[i];
    32.  
    33.             output.SetVertexBufferParams(source.vertexCount, attributes);
    34.             output.SetIndexBufferParams(GetIndexCount(source), source.indexFormat);
    35.  
    36.             for (int s = 0; s < source.vertexBufferCount; s++)
    37.                 output.GetVertexData<byte>(s).CopyFrom(source.GetVertexData<byte>(s));
    38.  
    39.             output.GetIndexData<byte>().CopyFrom(source.GetIndexData<byte>());
    40.             output.subMeshCount = source.subMeshCount;
    41.  
    42.             for (int m = 0; m < source.subMeshCount; m++)
    43.                 output.SetSubMesh(m, source.GetSubMesh(m), DontUpdateOrNotify);
    44.         }
    45.     }
    46.  
    47.     public static void CopyTo(Mesh source, Mesh destination)
    48.     {
    49.         using (var sourceArray = Mesh.AcquireReadOnlyMeshData(source))
    50.         {
    51.             var destinationArray = Mesh.AllocateWritableMeshData(1);
    52.             CopyMeshData(sourceArray, destinationArray, source.GetVertexAttributes());
    53.             Mesh.ApplyAndDisposeWritableMeshData(destinationArray, destination, DontUpdate);
    54.         }
    55.  
    56.         destination.name      = source.name;
    57.         destination.bounds    = source.bounds;
    58.         destination.bindposes = source.bindposes;
    59.  
    60.         destination.SetBoneWeights(
    61.             source.GetBonesPerVertex(),
    62.             source.GetAllBoneWeights()
    63.         );
    64.  
    65.         if (destination.blendShapeCount > 0)
    66.             destination.ClearBlendShapes();
    67.  
    68.         if (source.blendShapeCount > 0)
    69.         {
    70.             var vertices = new Vector3[source.vertexCount];
    71.             var normals  = new Vector3[source.vertexCount];
    72.             var tangents = new Vector3[source.vertexCount];
    73.  
    74.             for (int i = 0; i < source.blendShapeCount; i++)
    75.             {
    76.                 var name   = source.GetBlendShapeName(i);
    77.                 var frames = source.GetBlendShapeFrameCount(i);
    78.  
    79.                 for (int f = 0; f < frames; f++)
    80.                 {
    81.                     source.GetBlendShapeFrameVertices(i, f, vertices, normals, tangents);
    82.                     var w = source.GetBlendShapeFrameWeight(i, f);
    83.                     destination.AddBlendShapeFrame(name, w, vertices, normals, tangents);
    84.                 }
    85.             }
    86.         }
    87.     }
    88. }
    Edit: Upon posting this, I realized after all this time that GetIndexCount could be improved further to cover more cases:
    Code (CSharp):
    1. public static int GetIndexCount(Mesh.MeshData data)
    2. {
    3.     int count = 0;
    4.  
    5.     for (int i = 0; i < data.subMeshCount; i++)
    6.     {
    7.         var subMesh = data.GetSubMesh(i);
    8.         count       = Mathf.Max(count, subMesh.indexStart + subMesh.indexCount);
    9.     }
    10.  
    11.     return count;
    12. }
    A potentially even better option would be to calculate the index count from the length of the NativeArray returned by the source MeshData's GetIndexData:
    Code (CSharp):
    1. public static int GetIndexCount(Mesh.MeshData data)
    2. {
    3.     if (data.indexFormat == IndexFormat.UInt16)
    4.         return data.GetIndexData<ushort>().Length;
    5.  
    6.     return data.GetIndexData<uint>().Length;
    7. }
     
    Last edited: May 4, 2020
    FM-Productions and GeorgeAdamon like this.
  16. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    47
    Good call for Blendshapes + BoneWeights.
    As I rarely use them in my workflow, I didn't think about them when making this prototype. It's weird how Unity left them out of this new API, no?

    Thanks for spotting this silliness on my part regarding total index count. I was testing storing per-submesh index counts, and left this one there.
     
    pragmascript and TheZombieKiller like this.
  17. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    240
    It definitely feels like a missing piece of the API, yeah. I make use of them often so not having any non-allocating versions is a bit of a pain.
     
    awesomedata likes this.
  18. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,353
    Taking a guess this might be because the future direction is DOTS animation which doesn't store that data on the mesh.
     
  19. Muuuuo

    Muuuuo

    Joined:
    Apr 16, 2015
    Posts:
    57
    I tested out the new Mesh APIs in 2020.1 and only managed to encounter some performance problems and editor crash issues... (Cases 1245844, 1245825)

    Wondering what's the status of these new APIs? Are they badly WIP or should they be stable enough to at least use? Should it be expected to hit crash issues when playing around with native collections and Mesh APIs?
     
  20. jesta

    jesta

    Joined:
    Jun 19, 2010
    Posts:
    293
    I'd like to emphasize this request by @richardmatthias. We need the ability to draw a vertex buffer without any index buffer (ID3D11DeviceContext: Draw equivalent).

     
    Per-Morten and cultureulterior like this.
  21. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,419
    I think some "helper" functions to more easily draw/create connected quads (without resorting to untangling the tris) would be SO DAMN USEFUL.

    Also, now that unity has its own SPLINE data construct...

    Being able to perform a "deform" operation along a spline while drawing a group of these (e.g. a "grid" of quads) at the mesh level would be EVEN MORE USEFUL.

    Please, please, pretty please??

    @Aras

    I find myself needing to triangulate procedural surfaces from 2d shapes as well (see Archimatix), so if the Mesh-level API would just let me take in a few of the Unity splines (to automatically generate a "surface" across them), this would lead to ALL SORTS of very performant (an EXTREMELY USEFUL) procedural modeling tools (we totally need in Unity.)

    Since these things are done on the mesh-level, we could use them to draw gizmos, bones, whatever. Anyone could make meshes (and therefore make more visual tools) much more easily (since we'd just need to focus on the SHAPE of the model, rather than the individual triangle structure -- which holds A LOT of people back).

    Anybody @Unity Game for this? D:
     
    NotaNaN likes this.
  22. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    952
    Can I use new mesh API for vertex compressing? Currently, Unity compress internally "non-readable" mesh assets's vertext to Float16 when building player if "Vertex Compression" is enabled in Player Settings.

    So If I created custom mesh with other vertex format, like UNorm8, is it serialized preserving its vertex format?
     
    Last edited: Jun 30, 2020
  23. valarus

    valarus

    Joined:
    Apr 7, 2019
    Posts:
    416
    Would this be more performant with shader graph ?

     
  24. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,404
    yes..
     
    oldhighscore and Prodigga like this.
  25. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,156
  26. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,419
    Seems like there would be an API call to return a compressed-vertex mesh:

    i.e. compressedMesh = ReadCompressedMesh(WriteCompressedMesh(standardUnityMesh, compressionMethodEnum));

    Or something similar. Yeah?
     
  27. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    952
    I implemented my own compressing method, which convert to lower-precision format mesh. (float32 --> float16) and it works with MeshRenderer.

    But I found that float16 meshes does not work with following unity features: SkinnedMeshRenderer, Lightmap baking, StaticBatching, Projector.
     
  28. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,419
    Yeah -- We need a LOT more flexibility (and control) with meshes in Unity. Scriptable-Mesh Rendering Pipeline anyone?


    This would definitely be useful ESPECIALLY when dealing with open-world mesh-modification scenarios. I am working on something requiring this right now. D:
     
    NotaNaN and Kichang-Kim like this.
  29. torano

    torano

    Joined:
    Apr 7, 2017
    Posts:
    46
    Does anyone has the issue that mesh doesn't get rendered correctly? My mesh sometimes disapear while the player can still see it.
    Code (CSharp):
    1.     _mesh.Clear();
    2.    
    3.     _mesh.SetVertexBufferParams(_eVertices.Count, _vertexDescriptor);
    4.     // pass vertices and uvs here
    5.     _mesh.SetVertexBufferData(_eVertices, 0, 0, _eVertices.Count);
    6.    
    7.     _mesh.SetIndexBufferParams(_triangles.Count, _indexFormat);
    8.     _mesh.SetIndexBufferData(_triangles, 0, 0, _triangles.Count, MeshUpdateFlags.
    9.     DontRecalculateBounds
    10.     );
    11.    
    12.     var subMeshDescriptor = new SubMeshDescriptor(0, _triangles.Count, MeshTopology.Triangles);
    13.     subMeshDescriptor.bounds = new Bounds(new Vector3(Extent, Extent, Extent) * ((float)Size - 1f), new Vector3(Extent, Extent, Extent) * 2f * Size);
    14.     subMeshDescriptor.vertexCount = _eVertices.Count;
    15.     _mesh.subMeshCount = 1;
    16.     _mesh.SetSubMesh(0, subMeshDescriptor, MeshUpdateFlags.
    17.     DontRecalculateBounds
    18.     );
    19.  
    It seemed that my bounds isn't calculated correctly but when I checked it with Gizmos.DrawWireCube(transform.position + GetSubMesh(0).bounds.center, GetSubMesh(0).bounds.size) method it looked ok. Using MeshUpdateFlags.Default doesn't work either.

    Using Mesh.RecalculateBounds() after all of the code above works, but I don't know why then MeshUpdateFlags.Default doesn't work. Both bounds looks the same with Gizmos.DrawWireCube method.
     
  30. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    952
    How about BlendhShape APIs? it still not have NativeArray version of Get/Set blendshapes. It need very expensive Vector3[], Vector4[] allocation.

    Also, it currently need whole size of vertex array even the blendshape changes very small part of the mesh. If it provide that method which has partially modified vertices as parameters, like this AddBlendShape(name, positionDelta, positionDeltaStart, positionDeltaLength, normalDelta, normalDeltlaStart, normalDeltaLength, ...) then skipping 0 values, it can save many temporary allocations.
     
    kenamis and TheZombieKiller like this.
  31. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    240
    Yeah, blend shapes desperately need an API revamp (maybe something similar to the MeshData API?), the functionality in there right now is showing its age. There's actually a bug related to texture UVs when using the new MeshData APIs alongside blend shapes too (they get all corrupted unless the UVs are in a separate vertex stream or are added after the blend shapes) which I need to remind myself to make a bug report for.
     
    Kichang-Kim likes this.
  32. Alex1337rus

    Alex1337rus

    Joined:
    Mar 30, 2016
    Posts:
    37
    Graphics.DrawMeshInstanced with NativeArray<Matrix4x4> would be so nice.
     
  33. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    937
    And the mathematics matrices for that matter
     
    GeorgeAdamon likes this.
  34. LaireonGames

    LaireonGames

    Joined:
    Nov 16, 2013
    Posts:
    682
    One big one I would like is for MeshData.SetVertexBufferParams to accept a native array and not just an array.

    Without this I can't fully chain my jobs cause I have to wait until the mesh is calculated to get the vertice length and then I have to call this before executing my mesh build job (which generates a sync point).

    Attached are the sort of attributes I'm working with. I'm about to look into setting this data one at a time instead but I don't really want to do that since it wasn't long ago I switched to using VertexAttributes in the first place and it was a lot of work to restructure the data!

    Screenshot_1.png
     
    cultureulterior likes this.
  35. LaireonGames

    LaireonGames

    Joined:
    Nov 16, 2013
    Posts:
    682
    Invertex and tteneder like this.
  36. hickv

    hickv

    Joined:
    Oct 31, 2018
    Posts:
    38
    Would be cool to have a Mesh.SetBoneWeights(NativeArray<BoneWeight> weights) (the default BoneWeight struct)
     
    awesomedata and Invertex like this.
  37. o1o1o1o1o2

    o1o1o1o1o2

    Joined:
    May 22, 2014
    Posts:
    34
  38. LaireonGames

    LaireonGames

    Joined:
    Nov 16, 2013
    Posts:
    682
    I don't understand your question :/

    These new mesh functions can be used with jobs and even be burst compiled now since they back ported this fix to 2020.1.5 (before this version, you couldn't set mesh flags on a job since the only input was a traditional rather than native array)
     
  39. Ziflin

    Ziflin

    Joined:
    Mar 12, 2013
    Posts:
    127
    @Aras
    We would very much like to see a user-specified "position scale" value that can be applied to meshes so that the SNorm16 format can be used. This is something that we did in our previous engine for nearly every model and it allowed us to get optimal precision over something like the half-float format with optimal memory usage.

    This Vector3 position scale would be multipled by the SNorm16 vertex positions in the shader to rescale them to the proper size as well as certain operations in the editor such as when it performs 'pick' operations using only the visible mesh. Trying to do this with a localToWorld scale is very much *not* desired as we also want to update our glTF importer to use the SNorm16 format for nearly all of our models as we have with our previous engine, and we do not want to have them all have a non-uniform (transform) scale applied. This is basically just a fixed-point to floating-point conversion factor.

    The scale needs to be a full Vector3 as we're able to optimize the precision per dimension. For example, our custom terrain editor could then support significantly larger sizes and provide much better height-precision than when using the half format. Even all of our smaller props would benefit from the increase in precision over using half-floats.
     
  40. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,419
    @Aras

    Is there any way to manage procedural meshes when they are located outside of the 5000-8000 meter unit range without them losing precision?


    I ask because I have meshes from Houdini's Unity Plugin that uses 64 bit positioning in my world and need to modify these parts of my world in Unity sometimes through digital assets that position these verts far away from the origin while editing -- as far as Unity is concerned -- inside the same mesh.

    Is there any solution to this?
     
    Last edited: Nov 24, 2020
    Dinamytes, oldhighscore and NotaNaN like this.
  41. Dinamytes

    Dinamytes

    Joined:
    Nov 3, 2016
    Posts:
    50
    @Aras
    Could Mesh.ApplyAndDisposeWritableMeshData support jobs? Using MeshInstancesId like Physics.BakeMesh, this way we wouldn't need to be Main Thread dependent between those two calls, applying the Mesh Data and then baking the collider right away.

    Edit: please, sync points are multithreading enemy ;)
     
    Last edited: Jan 6, 2021
  42. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    903
    Not sure related but I wish we could share vertex buffer between mesh

    I have create a custom terrain mesh with noise. And I need to create multiple mesh for each LOD. But all of them can just use the same vertex buffer, And just decrease the detail of index buffer

    And so I wish we would have a mesh that can share vertex buffer. Or a mesh that support LOD by itself. Or the system that allow us to draw with raw vertexbuffer and indexbuffer directly
     
    TheZombieKiller likes this.
  43. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,419
    What would be _nice_, @Aras, my friend, is to simply have programmable geometry for these sort of things (i.e. such as LODs, impostors, and culling chunks).


    Programmable geometry (i.e. at the Houdini "group" level -- where primitives, points, lines/edges, and faces can be programmed with UVs, offsets, decimation, and/or LOD algorithms based on volumetrics or textures and scattering) would greatly help environment design -- which is sorely lacking. D:

    Plz? -- Pretty plz w/cherry on top?
     
    NotaNaN likes this.
  44. capkoh

    capkoh

    Joined:
    Oct 1, 2016
    Posts:
    24
    Hi,

    I started to try things with new mesh API, and realized that Dynamic Batching does not work at all. I tried to use Float32 for position as Aras mentioned in one of the posts and basically use Float32 everywhere, but my identical meshes still do not batch. Meshes are just a few quads. Interestingly, Frame Debugger shows absolutely identical parameters for the draw calls, but does not provide any reason why draw calls are not batched.

    Is it a known limitation of the new mesh API that it always breaks Dynamic Batching? Maybe I am missing some more conditions that attributes should satisfy in order to be dynamically batched? E.g. UNorm8 should not be used, or something?

    Does anyone have the same issue? I'm using Unity 2019.4.18f1.
     
  45. capkoh

    capkoh

    Joined:
    Oct 1, 2016
    Posts:
    24
    I'm replying to myself and maybe to someone else who faces the same problem.

    In Unity 2019.4.18f1 in order to make Dynamic Batching work with your custom vertex layout, attributes should satisfy these minimum requirements:
    • Position attribute should have exactly 3 components of type Float32
    • There should be only one vertex stream, the stream 0.
    The first requirement is ok for now as some data could be packed into the 3rd float if it's not used for Z coordinate. But the second requirement is much more limiting. Imagine, that there is a mesh with vertex colors. And each frame you update vertex colors to create some effect. In case of a single stream, it is required to cache the entire vertex data array per instance as the entire vertex data should be uploaded when colors are changed. On the other hand, if it's allowed to have the second stream, then per instance cache is not needed as colors array could be built separately from the reset of vertex attributes. Some static buffer could be used for it. A lot of memory could be saved this way.

    Is it possible that Dynamic Batching will be improved, so that it could batch vertex buffers of the same layout with multiple streams?
     
  46. DrSeltsam

    DrSeltsam

    Joined:
    Jul 24, 2019
    Posts:
    96
    Is there a chance that Mesh.AllocateWritableMeshData() could become thread-safe? Right now we are not allowed to allocate that data from another thread (throws an exception). We can fill it from another thread, but allocation still must happen on the main thread apparently - this slows down my mesh generation and adds another level of complexity (allocate in main thread -> fill data from other thread -> apply to mesh in main thread again)...
     
  47. unisip

    unisip

    Joined:
    Sep 15, 2010
    Posts:
    328
    Hey guys, I looked at the API and can see some interesting use for it, but there is a part I'm still a little confused about. I'm loading GLTF geometry at runtime, and I mean a *lot* of it. Sometimes each GLTF file has a mesh with 20k vertices for instance.

    Anyway, I do most of the work on a separate thread and it works fine, but I have yet to figure out a way to copy the data to the mesh without a severe performance hit (I measured about 1ms for a 20k vertices mesh). I tried native arrays and mesh.SetVertexBufferData, but it still copies the data, I guess.

    So my question is: with the new API, is there a way to set vertices and indices on a mesh WITHOUT a serious hit on the mean thread ? (assuming of course the data has been prepared on a separate thread)
     
  48. Zuntatos

    Zuntatos

    Joined:
    Nov 18, 2012
    Posts:
    611
  49. kadd11

    kadd11

    Joined:
    Mar 11, 2018
    Posts:
    33
    @Aras One thing that would be nice not that we can have fully custom vertex buffer layout is to not have warnings spewed if the position attribute is missing or not of type float3
     
  50. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    240
    Just want to repeat the request to make Mesh.AllocateWritableMeshData usable outside of the main thread, but I'd also like to extend that request to Mesh.MeshDataArray.Dispose as well. I currently fill in mesh data on another thread, and if I encounter an exception or some other kind of failure, I want to dispose of the mesh data to avoid a memory leak. Since the Dispose method can only be called from the main thread, I have to queue it on the main thread using my own dispatcher class.

    It would also be nice to have a Mesh.ApplyWritableMeshData method as an alternative to Mesh.ApplyAndDisposeWritableMeshData so I can re-use mesh data arrays, and write code like this without getting double-free errors:
    Code (CSharp):
    1. using (var array = Mesh.AllocateWritableMeshData(meshes.Length))
    2. {
    3.     //
    4.     // fill in mesh data here
    5.     //
    6.  
    7.     Mesh.ApplyAndDisposeWritableMeshData(array, meshes);
    8. }
    A non-disposing variant of ApplyAndDisposeWritableMeshData actually already exists as a private method and can be called via reflection, but making this part of the official API would be ideal.