Search Unity

  1. Curious about what's going to be in 2020.1? Have a look at the 2020.1 beta blog post.
    Dismiss Notice
  2. Want to see 2020.1b in action? Sign up for our Beta 2020.1 Overview Webinar on April 20th for a live presentation from our evangelists and a Q&A session with guests from R&D.
    Dismiss Notice
  3. Interested in giving us feedback? Join our online research interviews on a broad range of topics and share your insights with us.
    Dismiss Notice
  4. New Unity Live Help updates. Check them out here!

    Dismiss Notice

NativeArray and Mesh

Discussion in 'Data Oriented Technology Stack' started by DaDonik, Mar 21, 2018.

  1. DaDonik

    DaDonik

    Joined:
    Jun 17, 2013
    Posts:
    178
    It would be great if we could pass NativeArray's to the Mesh API.

    Methods like Mesh.SetVertices(), Mesh.SetNormals(), etc. currently require a list and can therefore not be jobified properly.

    Are there any plans to support this in the forseeable future?
     
  2. RootCauseProductions

    RootCauseProductions

    Joined:
    Feb 1, 2018
    Posts:
    31
    More then that, Mesh wants Vector3s and can only be used from the main thread. I do hope we get a way to create and manage meshes from inside the Jobs system (and thus inside ECS as well).
     
    MNNoxMortem, Jes28, davidfrk and 2 others like this.
  3. DaDonik

    DaDonik

    Joined:
    Jun 17, 2013
    Posts:
    178
    It would be great to alter meshes directly from a job, but for the time being i would be satisfied when i could just pass the data i have calculate in the job system to the mesh on the main thread.
    Let's not get too greedy ;)
     
    MNNoxMortem likes this.
  4. RootCauseProductions

    RootCauseProductions

    Joined:
    Feb 1, 2018
    Posts:
    31
    :D "The point is, ladies and gentleman, that greed, for lack of a better word, is good." - Gordon Gekko in Wall Street

    I'm not sure there would be huge amount of difference between modify Mesh and creating a new way to create a mesh then manage getting it to the main thread (when needed, DirectX 12, Vulkan and Metal don't have this limit).
     
  5. xoofx

    xoofx

    Unity Technologies

    Joined:
    Nov 5, 2016
    Posts:
    268
    Can't tell exactly when it is planned, but this is definitely part of the plan. There is an ultimate goal to make the whole rendering pipeline leveraging the C# ECS/job infrastructure, it will take time but once we will be there, it will be quite amazing.
     
    MNNoxMortem, Kender, GilCat and 9 others like this.
  6. DaDonik

    DaDonik

    Joined:
    Jun 17, 2013
    Posts:
    178
    Thanks for confirming that.
    Not that i'm in a hurry, but i think i speak for all users here when i say "We want it NOW" :)
     
    davidfrk likes this.
  7. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,412
    In the future we will also want to have overloads that would accept the types from the new math library, e.g. NativeArray<float3> etc
     
    Last edited: Mar 22, 2018
  8. Krajca

    Krajca

    Joined:
    May 6, 2014
    Posts:
    107
    better to not be outdated when that time comes :p
     
  9. GabrieleUnity

    GabrieleUnity

    Unity Technologies

    Joined:
    Sep 4, 2012
    Posts:
    116
    Absolutely. When the new math library will be out of experimental, we will make sure the new types can be used on any Unity API where it makes sense.
     
    MNNoxMortem, Kender, Jes28 and 4 others like this.
  10. FROS7

    FROS7

    Joined:
    Apr 8, 2015
    Posts:
    26
    This makes me gitty. I know good things take time, but i cant WAIT for all of this and will be watching the progress on all of this very closely.
     
  11. ecurtz

    ecurtz

    Joined:
    May 13, 2009
    Posts:
    639
    Any update on this or is it another case where we'll be waiting years for a few lines of code that everyone agrees are needed?
     
  12. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    564
    I'm glad I'm not the only one. I have requested this in an older thread. :)
     
  13. ecurtz

    ecurtz

    Joined:
    May 13, 2009
    Posts:
    639
  14. slim_trunks

    slim_trunks

    Joined:
    Dec 31, 2017
    Posts:
    41
    My RAM would appreciate this feature.
    This is one of the only (and biggest) sources of garbage I am forced to deal with as of now.

    But it's probably more likely that Unity is focusing on reworking the Mesh Component from the ground up for ECS.
    Just a guess.
     
  15. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    2,061
    How I convert DynamicBuffers to Mesh, no garbage, super quick Single memcpy per buffer.

    I actually had an even faster version that I've talked about a bit before where I could manipulate a List<T> within a job so it didn't even require a memcopy but I feel the very minor performance cost of a memcopy is worth the safety of using buffers instead. Also means I don't need SharedComponentData.

    Code (CSharp):
    1.  
    2.     public class MeshSystem : ComponentSystem
    3.     {
    4.         private readonly List<Vector3> verticesList = new List<Vector3>();
    5.         private readonly List<Vector3> normalsList = new List<Vector3>();
    6.         private readonly List<Vector3> uvsList = new List<Vector3>();
    7.         private readonly List<int> trianglesList = new List<int>();
    8.  
    9.         // ...
    10.  
    11.         private void SetMesh(
    12.             Mesh mesh,
    13.             DynamicBuffer<Vector3> vertices,
    14.             DynamicBuffer<Vector3> uvs,
    15.             DynamicBuffer<Vector3> normals,
    16.             DynamicBuffer<int> triangles)
    17.         {
    18.             mesh.Clear();
    19.  
    20.             if (vertices.Length == 0)
    21.             {
    22.                 return;
    23.             }
    24.  
    25.             this.verticesList.NativeAddRange(vertices);
    26.             this.uvsList.NativeAddRange(uvs);
    27.             this.normalsList.NativeAddRange(normals);
    28.             this.trianglesList.NativeAddRange(triangles);
    29.  
    30.             mesh.SetVertices(this.verticesList);
    31.             mesh.SetNormals(this.normalsList);
    32.             mesh.SetUVs(0, this.uvsList);
    33.             mesh.SetTriangles(this.trianglesList, 0);
    34.  
    35.             this.verticesList.Clear();
    36.             this.normalsList.Clear();
    37.             this.uvsList.Clear();
    38.             this.trianglesList.Clear();
    39.         }
    Code (CSharp):
    1. public static unsafe void NativeAddRange<T>(this List<T> list, DynamicBuffer<T> dynamicBuffer)
    2.             where T : struct
    3.         {
    4.             NativeAddRange(list, dynamicBuffer.GetBasePointer(), dynamicBuffer.Length);
    5.         }
    6.  
    7.         private static unsafe void NativeAddRange<T>(List<T> list, void* arrayBuffer, int length)
    8.             where T : struct
    9.         {
    10.             var index = list.Count;
    11.             var newLength = index + length;
    12.  
    13.             // Resize our list if we require
    14.             if (list.Capacity < newLength)
    15.             {
    16.                 list.Capacity = newLength;
    17.             }
    18.  
    19.             var items = NoAllocHelpers.ExtractArrayFromListT(list);
    20.             var size = UnsafeUtility.SizeOf<T>();
    21.  
    22.             // Get the pointer to the end of the list
    23.             var bufferStart = (IntPtr) UnsafeUtility.AddressOf(ref items[0]);
    24.             var buffer = (byte*)(bufferStart + (size * index));
    25.  
    26.             UnsafeUtility.MemCpy(buffer, arrayBuffer, length * (long) size);
    27.  
    28.             NoAllocHelpers.ResizeList(list, newLength);
    29.         }
     
  16. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    156
    How did you get access to the internal NoAllocHelpers class? It doesn't appear that you're using reflection.
     
  17. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    2,061
    Originally I wrote methods to mimic the behaviour but it required System.Reflection.Emit which is a no go so I just ended up calling it with reflection. The reflection is cached so except for the first time, it's nearly just as fast as calling it normally.

    Code (CSharp):
    1.     using System;
    2.     using System.Collections.Generic;
    3.     using System.Reflection;
    4.  
    5.     using UnityEngine;
    6.  
    7.     /// <summary>
    8.     /// Provides access to the internal UnityEngine.NoAllocHelpers methods.
    9.     /// </summary>
    10.     public static class NoAllocHelpers
    11.     {
    12.         private static readonly Dictionary<Type, Delegate> ExtractArrayFromListTDelegates = new Dictionary<Type, Delegate>();
    13.         private static readonly Dictionary<Type, Delegate> ResizeListDelegates = new Dictionary<Type, Delegate>();
    14.  
    15.         /// <summary>
    16.         /// Extract the internal array from a list.
    17.         /// </summary>
    18.         /// <typeparam name="T"><see cref="List{T}"/>.</typeparam>
    19.         /// <param name="list">The <see cref="List{T}"/> to extract from.</param>
    20.         /// <returns>The internal array of the list.</returns>
    21.         public static T[] ExtractArrayFromListT<T>(List<T> list)
    22.         {
    23.             if (!ExtractArrayFromListTDelegates.TryGetValue(typeof(T), out var obj))
    24.             {
    25.                 var ass = Assembly.GetAssembly(typeof(Mesh)); // any class in UnityEngine
    26.                 var type = ass.GetType("UnityEngine.NoAllocHelpers");
    27.                 var methodInfo = type.GetMethod("ExtractArrayFromListT", BindingFlags.Static | BindingFlags.Public)
    28.                     .MakeGenericMethod(typeof(T));
    29.  
    30.                 obj = ExtractArrayFromListTDelegates[typeof(T)] = Delegate.CreateDelegate(typeof(Func<List<T>, T[]>), methodInfo);
    31.             }
    32.  
    33.             var func = (Func<List<T>, T[]>)obj;
    34.             return func.Invoke(list);
    35.         }
    36.  
    37.         /// <summary>
    38.         /// Resize a list.
    39.         /// </summary>
    40.         /// <typeparam name="T"><see cref="List{T}"/>.</typeparam>
    41.         /// <param name="list">The <see cref="List{T}"/> to resize.</param>
    42.         /// <param name="size">The new length of the <see cref="List{T}"/>.</param>
    43.         public static void ResizeList<T>(List<T> list, int size)
    44.         {
    45.             if (!ResizeListDelegates.TryGetValue(typeof(T), out var obj))
    46.             {
    47.                 var ass = Assembly.GetAssembly(typeof(Mesh)); // any class in UnityEngine
    48.                 var type = ass.GetType("UnityEngine.NoAllocHelpers");
    49.                 var methodInfo = type.GetMethod("ResizeList", BindingFlags.Static | BindingFlags.Public)
    50.                     .MakeGenericMethod(typeof(T));
    51.                 obj = ResizeListDelegates[typeof(T)] =
    52.                     Delegate.CreateDelegate(typeof(Action<List<T>, int>), methodInfo);
    53.             }
    54.  
    55.             var action = (Action<List<T>, int>)obj;
    56.             action.Invoke(list, size);
    57.         }
    58.     }
     
    MNNoxMortem, The5, Zoey_O and 3 others like this.
  18. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    156
    Sweet. I was previously using reflection to manually adjust my managed list's array and size (using FieldInfo.Get/SetValue), but this is a bit faster and way easier to work with. Also doesn't have any recurring GC allocations. Thanks! :D
     
  19. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    454
    @GabrieleUnity Ideally we could use it on anything that is enumerable and of type Vector3 or float3. That way we dont need overloads for Lists, and all other types work too.
     
  20. OldLegWig

    OldLegWig

    Joined:
    Mar 18, 2018
    Posts:
    84
    The mathematics library has been out of preview for a few months. Is there a timeline now for supporting it throughout the other libraries (but like OP I'm particularly interested in meshes)?
     
  21. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    401
    OldLegWig likes this.
  22. OldLegWig

    OldLegWig

    Joined:
    Mar 18, 2018
    Posts:
    84
    @julian-moschuering Thank you! This looks even better than I was expecting. It's unclear whether the mathematics library types are accepted though. I'll have to test it out when I get a moment unless someone knows offhand.
     
    Last edited: Aug 29, 2019
  23. OldLegWig

    OldLegWig

    Joined:
    Mar 18, 2018
    Posts:
    84
    @julian-moschuering It looks like you may be able to set a mesh's VertexAttributeFormat, for example, with SetVertexBufferParams allowing manual specification of the data type (aka float3). I cannot find the use of these in the documentation, though.
     
  24. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    401
    Last edited: Aug 29, 2019
  25. Dinamytes-Gabriel_Mota

    Dinamytes-Gabriel_Mota

    Joined:
    Nov 3, 2016
    Posts:
    10
    Is it possible to use Mesh.SetVertexBufferParams with Position - float16 (mathemetics.half)?
    I'm getting a format error on Mesh.SetVertexBufferData
     
  26. OldLegWig

    OldLegWig

    Joined:
    Mar 18, 2018
    Posts:
    84
    Are there equivalent methods for setting UVs, normals and tangents manually?

    Edit: jeeze, I just needed to read a little more carefully. To answer my own question in case someone else is feeling as lazy as I was, its done by creating a struct for a custom vertex layout that contains values for vertex position, normal, tangent, and uv. Then by specifying the proper data characteristics in the second argument of Mesh.SetVertexBufferParams, you can pass in an array of your custom vertex struct to get all of that in there. The VertexAttribute that corresponds with default UVs is TexCoord0. This is all in the example for Mesh.SetVertexBufferData.
     
    Last edited: Sep 3, 2019
  27. TheJavierD

    TheJavierD

    Joined:
    Jan 6, 2017
    Posts:
    21
    Would it be possible to use NativeList instead of DynamicBuffer?, I'm not using Entities and i don't think i can use DynamicBuffer.

    I'm thinking something like:
    NativeAddRange<T>(this List<T> list, NativeList<T> aNativeList)
     
  28. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    2,061
    This thread is a bit dated as Unity added support for using NativeArray with SetVertices, SetUVs in 2019.3

    Just use AsArray on your NativeList and pass that in.
     
unityunity