Search Unity

Official Unity.Mathematics available on github

Discussion in 'Entity Component System' started by xoofx, Apr 10, 2018.

Thread Status:
Not open for further replies.
  1. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    I think the documentation for Mathematics could be massively improved e.g. the math.cs file has a whole host of commands with minimal documentation on how they work.
     
  2. Dale_Kim

    Dale_Kim

    Unity Technologies

    Joined:
    May 8, 2019
    Posts:
    56
    I don't believe there is an equivalent, but you should be able to port your own version using Unity.Mathematics that's similar. Do you need to match the exact behavior of Mathf.SmoothDamp?
     
  3. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    My use case was that I was migrating traditional mono behavior code that was using "Mathf.SmoothDamp" (for player movement) to pure ECS. So I needed similar functionality (if not exact) so that I can use in Jobs. I was able to move forward with the "math.lerp" function. But it would be nice to have similar function to "Mathf.SmoothDamp" in the "Unity.Mathematics".
     
  4. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,447
    Could you, please, add implicit conversions between int2/int3/int4 vectors and Vector2Int/Vector3Int/Vector4Int, the way you did for floatX and VectorX.
     
    Cynicat likes this.
  5. arturmandas

    arturmandas

    Joined:
    Sep 29, 2012
    Posts:
    240
    Strongly upvoting - we could use 3D Geometry library accompanying this one.
     
  6. Sylmerria

    Sylmerria

    Joined:
    Jul 2, 2012
    Posts:
    369
    What is the equivalent of Matrix4x4.MultiplyPoint ? When I use math.transform(float4x4,float3) I don't found the good result :/
     
  7. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    mul(4x4, 4)?
     
  8. Sylmerria

    Sylmerria

    Joined:
    Jul 2, 2012
    Posts:
    369
    Of course the answer was simple :oops:
    Thanks ;)
     
  9. FlightOfOne

    FlightOfOne

    Joined:
    Aug 1, 2014
    Posts:
    668
    What is the equivalent of MoveTowards? I see, math.lerp, and step but can't find move towards.
     
  10. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    You can write your own, MoveTowards is simple.
    Code (CSharp):
    1. public static Vector3 MoveTowards(
    2.       Vector3 current,
    3.       Vector3 target,
    4.       float maxDistanceDelta)
    5.     {
    6.       float num1 = target.x - current.x;
    7.       float num2 = target.y - current.y;
    8.       float num3 = target.z - current.z;
    9.       float num4 = (float) ((double) num1 * (double) num1 + (double) num2 * (double) num2 + (double) num3 * (double) num3);
    10.       if ((double) num4 == 0.0 || (double) num4 <= (double) maxDistanceDelta * (double) maxDistanceDelta)
    11.         return target;
    12.       float num5 = (float) Math.Sqrt((double) num4);
    13.       return new Vector3(current.x + num1 / num5 * maxDistanceDelta, current.y + num2 / num5 * maxDistanceDelta, current.z + num3 / num5 * maxDistanceDelta);
    14.     }
     
    hippocoder and FlightOfOne like this.
  11. FlightOfOne

    FlightOfOne

    Joined:
    Aug 1, 2014
    Posts:
    668

    Awesome! Thanks a lot!
     
  12. SebLazyWizard

    SebLazyWizard

    Joined:
    Jun 15, 2018
    Posts:
    234
    What are the equivalents to (Inverse)Transform(Direction/Point/Vector)?
    Let's say I want to transform a position to the local space of another position and then check for the differences between both positions on each axis, how would I do that in the most effective way?
     
  13. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    mul space matrix and your vector (in world space).
     
    SebLazyWizard likes this.
  14. MrGuardianX

    MrGuardianX

    Joined:
    Sep 29, 2014
    Posts:
    58
    I don't think the naming comes from Shader world really. It is how HPC libraries and C style high perf libraries are written. And Unity wants us to finally move from script programmers not caring about your data to professionals. In this world, C-style dominates for historical reasons.

    Either way, I do really think the naming should obey C# rules. We incorporated this new math into our big project and code looks really odd when you stare inside a single method but half of your code is CamelCase and half is math.
     
  15. SebLazyWizard

    SebLazyWizard

    Joined:
    Jun 15, 2018
    Posts:
    234
    That worked fine for positions, but I didn't manage to create an equivalent method for (Inverse)TransformDirection.
    I need to compare directions of each axis separately, so logically a single dot product of both rotations wouldn't do the job here.
    Any ideas?
     
    Last edited: Jun 25, 2019
  16. DavidSWu

    DavidSWu

    Joined:
    Jun 20, 2016
    Posts:
    183
    The inefficient but easy way to inverse transform your direction is it is to treat it as a Vector4 with w=0 and multiply it through the 4x4 matrix or the transpose or whatever.
    This is assuming that your matrix is orthonormal.

    Hope that helps!
     
  17. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I don't see any half matrices and wonder if they are of any use (eg. half4x4)?
     
    Last edited: Jun 25, 2019
    ChristopherKerr likes this.
  18. SebLazyWizard

    SebLazyWizard

    Joined:
    Jun 15, 2018
    Posts:
    234
    Yea that worked.
    This is my solution if anyone is interested;
    Code (CSharp):
    1. float3[] moveDir = { new float3(1, 0, 0), new float3(0, 1, 0), new float3(0, 0, 1) };
    2. float[] dotDir = new float[3];
    3. for (int i = 0; i < 3; i++)
    4. {
    5.     var dirA = math.mul(matB, new float4(math.rotate(rotA, moveDir[i]), 0)).xyz;
    6.     var dirB = math.mul(matB, new float4(math.rotate(rotB, moveDir[i]), 0)).xyz;
    7.     dotDir[i] = math.dot(dirA, dirB);
    8. }
    There might be some room for improvement, so if you know some optimizations or even a better way to do it, please let me know!
     
  19. DavidSWu

    DavidSWu

    Joined:
    Jun 20, 2016
    Posts:
    183
    It seems like ARM64 supports half precision floating point numbers vias SIMD registers natively. Intel has hardware support for conversion to/from 16 bit floats so could store things as 16 bit and do your math operations using 32 bit floats and you would save on memory bandwidth.

    It would be wonderful if we could use 16 bit floats and have the compiler do what it can on the target architecture to perform operations. I.e. on X64 unpack on load to 32 bit, perform operations and and repack on store, and on ARM64 use the native 16 bit float registers.
    The results would be different on different platforms, but that is acceptable given that when you are using 16 bit floats you probably don't have strict precision requirements.
     
    GilCat likes this.
  20. DavidSWu

    DavidSWu

    Joined:
    Jun 20, 2016
    Posts:
    183
    Three and a half things that could help:
    - Since you are rotating the identity axises you can just use the vectors from the matrixes. You might have to use the transpose, I don't remember off hand if vectors are stored row major or column major.
    - the Dot product is the same for two equally rotated vectors as for unrotated vectors so you can skip the multiply by matB.
    - Since it is such a simple operation you probably don't want to create garbage with dotDir, and you might as well unroll the loop.
    Something like:
    Code (CSharp):
    1. var dotDir0 = math.Dot(rotA.c0,rotB.c0);
    2. var dotDir1 = math.Dot(rotA.c1,rotB.c1);
    3. var dotDir2 = math.Dot(rotA.c2,rotB.c2);
    If that doesn't work transpose both matrices and repeat ;)
     
    SebLazyWizard likes this.
  21. MixGrey

    MixGrey

    Joined:
    Dec 23, 2014
    Posts:
    9
    Is there a vector projection method in the library similar to Vector3.Project?
     
  22. SebLazyWizard

    SebLazyWizard

    Joined:
    Jun 15, 2018
    Posts:
    234
    For some reason that didn't work well, the positions were still effected by the world space.
    I decided to skip the matrix part and do the transformation by using the positions and rotations only, that worked fine;
    Code (CSharp):
    1. var localOffset = math.rotate(math.inverse(rotB), posA - posB);
     
  23. DavidSWu

    DavidSWu

    Joined:
    Jun 20, 2016
    Posts:
    183
    dot(vector,onNormal)/onNormal.LengthSquared()*onNormal
    Or skip the divide if onNormal is normalized
     
    MixGrey likes this.
  24. DavidSWu

    DavidSWu

    Joined:
    Jun 20, 2016
    Posts:
    183
    I may have misunderstood what you were doing. I hope that I didn't lead you astray.
    If this is performance critical and you posted more source I might be able to optimize it.
     
  25. SebLazyWizard

    SebLazyWizard

    Joined:
    Jun 15, 2018
    Posts:
    234
    Well I work on a VR game in which you can grab a weapon at any given point and orientation. In order "attach" the weapon to the hand (at the grabbed position) I need to get the position and rotation of the weapon relative to the hand that grabbed it ofc.
    Anyway that's the grab system, it all works fine, but optimization is always welcome;)

    Code (CSharp):
    1. [UpdateAfter(typeof(AgentMoveSystem))]
    2. public class AgentGrabSystem : ComponentSystem
    3. {
    4.     protected override void OnUpdate()
    5.     {
    6.         Entities.WithAllReadOnly<AgentTag>().ForEach((Entity agent) =>
    7.         {
    8.             Entities.ForEach((Entity hand, ref Translation position, ref Rotation rotation, ref Parent parent, ref AgentBone bone, ref AgentGrab grab, ref HandItem item) =>
    9.             {
    10.                 if (parent.Value != agent)
    11.                     return;
    12.  
    13.                 var handCenter = position.Value + math.rotate(rotation.Value, VrData.handCenter);
    14.                 var curHand = bone.Value - 1;
    15.                 if (grab.cur && !grab.last)//grabbing
    16.                 {
    17.                     var start = position.Value - math.rotate(rotation.Value, new float3(0, 0, 0.075f));
    18.                     var end = position.Value - math.rotate(rotation.Value, new float3(0, 0, 0.05f));
    19.                     item.Item = SphereCast(start, end, 0.075f);
    20.                     Debug.Log("hand:" + curHand + " grabbed entity:" + item.Item);
    21.  
    22.                     if (item.Item != Entity.Null)
    23.                     {
    24.                         var curItemPos = EntityManager.GetComponentData<Translation>(item.Item).Value;
    25.                         var curItemRot = EntityManager.GetComponentData<Rotation>(item.Item).Value;
    26.                         item.offsetPos.z = math.rotate(math.inverse(curItemRot), handCenter - curItemPos).z;
    27.                         item.offsetRot = quaternion.identity;
    28.  
    29.                         //flip
    30.                         if (math.dot(math.rotate(rotation.Value, new float3(0, 1, 0)), math.rotate(curItemRot, new float3(0, 1, 0))) < 0)
    31.                         {
    32.                             item.offsetRot = quaternion.RotateZ(math.PI);
    33.                             Debug.Log(curHand + " flip");
    34.                         }
    35.                         //upside down
    36.                         if (math.dot(math.rotate(rotation.Value, new float3(0, 0, 1)), math.rotate(curItemRot, new float3(0, 0, 1))) < 0)
    37.                         {
    38.                             item.offsetRot = math.mul(item.offsetRot, quaternion.RotateY(math.PI));
    39.                             Debug.Log(curHand + " upside down");
    40.                         }
    41.                         Debug.Log("hand:" + curHand + " offsetPos:" + item.offsetPos /*+ " X:" + dotDir[0] + " Y:" + dotDir[1] + " Z:" + dotDir[2]*/);
    42.                     }
    43.                 }
    44.                 else if (!grab.cur && grab.last)//releasing
    45.                 {
    46.                     item.Item = Entity.Null;
    47.                     item.offsetPos = float3.zero;
    48.                     item.offsetRot = quaternion.identity;
    49.                     Debug.Log("hand:" + curHand + " released");
    50.                 }
    51.             });
    52.         });
    53.     }
    54. }
     
    Last edited: Jul 11, 2019
  26. Dale_Kim

    Dale_Kim

    Unity Technologies

    Joined:
    May 8, 2019
    Posts:
    56
    I've been thinking about whether or not we should make half4x4 available but the main challenge is storing positions. A half precision float really isn't precise enough to be able to store positions in that format except for very specific circumstances which limits the use case for half4x4.
     
    GilCat likes this.
  27. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    How bad would it be to convert a float4x4 to half4x4?
    My use case is to use them to as the structures to upload into a compute buffer in order to reduce the amount of data as opposed to upload a float4x4.
    I've done a naive implementation of half4x4 to that purpose and convert my LocalToWorld float4x4 and the last possible moment.
     
    ChristopherKerr likes this.
  28. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
    Hello,

    I'm using jobs + mathematics with noises and i'm having float precision issues.
    It is planned to implement double for noises ? (double2 / double3)
     
  29. Dale_Kim

    Dale_Kim

    Unity Technologies

    Joined:
    May 8, 2019
    Posts:
    56
    Can you elaborate more on what issues you're having?
     
  30. Dale_Kim

    Dale_Kim

    Unity Technologies

    Joined:
    May 8, 2019
    Posts:
    56
    That depends on what those 4x4 matrices need to hold and the range of values they need to support. If you're dealing with something with very little translation from the origin and don't require a ton of precision for the rotation, then it's probably OK. Can you share more on what you're doing and what range of values you expect in those matrices?
     
  31. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    In all my entities i use LocalToWorld component (which has float4x4) and in the very last moment of setting the ComputeBuffer i convert the float4x4 to half4x4.
    The ranges can be anything since it follows the Transform System rules.
    This is all part of a Sprite Render system and the shader used expects uint values on its StructuredBuffer (See attached shader).
    So far i haven't seen any problems using this and as mentioned before setting the compute buffer data is way faster.
     

    Attached Files:

  32. pragmascript

    pragmascript

    Joined:
    Dec 31, 2010
    Posts:
    107
    For our game we split some code into a seperate Visual Studio Solution as a managed plugin.
    (So we can use the same code for client- and serverside unity projects)

    We wanted to use Unity Mathematics everywhere. But it is unclear how we can add a reference to the Unity Mathematics package for a standalone VS Solution. AFAIK there is no compiled DLL version of the library that we can just reference (as we do with UnityEngine.dll)

    So what would be recommended practice if we want to use Unity Mathematics both inside of Unity as a package as well as in custom managed plugins?
     
  33. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Library/ScriptAssemblies. This keeps your shared project automatically in sync with what you are using on the Unity side.
     
    pragmascript likes this.
  34. pragmascript

    pragmascript

    Joined:
    Dec 31, 2010
    Posts:
    107
    Oh nice I didn't know about that one :) thanks
     
  35. merpheus

    merpheus

    Joined:
    Mar 5, 2013
    Posts:
    202
    I have a question/request. Is it possible to have swizzling like we have in shader languages ? It is very useful and I feel like it can be a nice addition to math library.
     
  36. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    @m3rt32 - if you mean per-component swizzles all of the PRIMITIVE[N] types support this already, with things like .xxxx, .xy .zw, etc. It's all auto-generated C# code.
     
  37. merpheus

    merpheus

    Joined:
    Mar 5, 2013
    Posts:
    202
    Oh, my bad. This is awesome. Suddenly this math library became my favorite :D
     
    hippocoder likes this.
  38. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Considering this is already released, I feel like the github repo description is bit outdated, right now it's worded as:
    prototype makes it sound like it's some sort of a draft instead of fully released package.
     
  39. StefDevs

    StefDevs

    Joined:
    Jan 20, 2014
    Posts:
    23
    Are Unity.Math types serializable? I want to expose some 'half' values in the editor without jumping through too many hoops...
     
  40. Dale_Kim

    Dale_Kim

    Unity Technologies

    Joined:
    May 8, 2019
    Posts:
    56
    Many types are already serializable but not all. Unfortunately, it appears that half is one of those types that aren't serializable. We've already had a request internally to make more of the Unity.Mathematics types serializable so I'll try to make sure that we cover half. The only thing I don't know is how the editor will present the half precision float in the inspector.
     
    SirIntruder, recursive and StefDevs like this.
  41. SirIntruder

    SirIntruder

    Joined:
    Aug 16, 2013
    Posts:
    49
    Currently, it doesn't seem possible to do if (bool2), which I just encountered because I wanted to do if (!isnan(float2)).

    1. I think it would make a lot of sense to have true operator overloaded for bool2/bool3/bool4, so they would return true if all of their elements are true
    2. What is the most elegant way today to do if (bool2), or specifically if(!isnan(float2))?
     
  42. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    math.all
     
    SirIntruder likes this.
  43. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    Last edited: Oct 1, 2019
  44. Kmiecis

    Kmiecis

    Joined:
    Oct 11, 2017
    Posts:
    12
    Hello and quick question.
    Will this library support byte2, byte3 and byte4?
    I understand they may not be in shaders language but things like Color32 use 4 bytes so it could be helpful to use those instead and reinterpret later on for better performance with burst? Or maybe with following the library as it is now, one can create such implementation for himself and still benefit from burst?
     
    CodeSmile and Vanamerax like this.
  45. sheredom

    sheredom

    Unity Technologies

    Joined:
    Jul 15, 2019
    Posts:
    300
  46. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
    I would like to have this as well. Also, maybe in the case of byte add a byte8, byte16, (byte32) as well to make use of the wide SSE/AVX registers?
     
    CodeSmile likes this.
  47. Kmiecis

    Kmiecis

    Joined:
    Oct 11, 2017
    Posts:
    12
    @sheredom Done that. Hopefully it will be added. Thanks.
     
    CodeSmile, Orimay and sheredom like this.
  48. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Any reason, why random.NextInt ( min, max ) has min inclusive and max exclusive?
    Having max exclusive is none intuitive.
     
  49. elcionap

    elcionap

    Joined:
    Jan 11, 2016
    Posts:
    138
    That's actually the expected behaviour. Both DotNet (System.Random) and Unity (UnityEngine.Random) uses half-open interval (of half-open range) for integer values. Java has the same behaviour and a lot of libraries in other languages. The basic math for in the generator will result in a half-open by default. Changing this can mess with the number distribution and require some additional code. Half-open generation is also great when working with arrays since a Range(0, array.Length) will always be a valid index.

    []'s
     
  50. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Yep I can see use for collections. That makes sense. Yet then typically using only one property of random in such case.

    I understand that maybe not a priority, but I wish Unity team add comments, so when selecting method, we can see their description how it behaves, without needing drilling down to source code.
     
Thread Status:
Not open for further replies.