Search Unity

When adding two Vector3s and assigning to an existing variable, does Unity do the addition direct...

Discussion in 'Scripting' started by meejabychus, Sep 21, 2017.

  1. meejabychus

    meejabychus

    Joined:
    Sep 14, 2017
    Posts:
    3
    When adding two Vector3s and assigning to an existing variable, does Unity do the addition direct to the existing variable, or create a new one?

    For example:

    Vector3 v1, v2, v3;
    v1 = v2+v3;​

    What would Unity be doing internally? Would it be:

    v1.x = v2.x+v3.x
    v1.y etc, etc​

    Or:

    Vector3 temp = new Vector3();
    temp.x = v2.x+v3.x
    temp.y etc, etc
    v1 = temp​

    Sorry I know it's a niche question! I'm doing some optimisation and wondering if it's worth inlining all my vector math.
     
  2. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    This occurs in internal Unity C++ code that the Unity dev's are not likely to share with us, but these guys are professionals so I'm sure they do it in a way that is both well optimized and universally acceptable.

    My best guess is they do this:
    v1 = new Vector3(v2.x + v3.x, v2.y + v3.y, v2.z + v3.z);


    I would advise against trying to optimize to this level unless vector addition is something you do A LOT EVERY FRAME. You will often be sacrificing readability (and therefore your ability to easily modify your code) for an optimization that literally doesn't make your framerate or anything any faster because of how small the gain is.

    I would advise trying to focus more on multi-step functions or operations in your code and reducing the number of steps as opposed to making each individual step as optimized as possible.

    Best of luck achieving the results you're after!
     
  3. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Profile before optimizing. Make sure your optimization time is spent in all the right places.
     
    Kurt-Dekker likes this.
  4. meejabychus

    meejabychus

    Joined:
    Sep 14, 2017
    Posts:
    3
    Optimising is going well. Got GC down to 0 which was the goal for today :)

    Screen Shot 2017-09-22 at 01.45.38.jpg
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    Vectors are structs and therefore don't generate garbage, unless you explicitly box them in some manner.

    Vector3's are C#/.Net structs, and therefore are not actually performed on the C++ side of the engine.

    Here is the source for the Vector3 addition operator (decompiled for UnityEngine.dll):
    Code (csharp):
    1.  
    2.     public static Vector3 operator +(Vector3 a, Vector3 b)
    3.     {
    4.       return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
    5.     }
    6.  
    Effectively when you say:
    Code (csharp):
    1. v1 = v2 + v3;
    You're really saying:
    Code (csharp):
    1. v1 = Vector3.Add(v2, v3);
    So, the addition operator method is loaded up onto the stack, copies of v2 and v3 are passed in. This method then calls the struct constructor passing the in the sum of each vector component, this will technically allocate yet another method onto the stack to then set the fields of said struct (as for the mono runtime optimizing struct constructors... we're not going to get into all that). Finally that new Vector3 is returned and set to v1.

    For optimizations sake it is technically most efficient to inline addition as:
    Code (csharp):
    1.  
    2. v1.x = v2.x + v3.x;
    3. v1.y = v2.y + v3.y;
    4. v1.z = v2.z + v3.z;
    5.  
    Though if you're seeing performance issues at this level of things... you got bigger problems.

    The only places I would say you should inline vector addition is if you have some loop where you have to sum thousands of vectors. For example this:

    Code (csharp):
    1.  
    2. Vector3[] arr = *An array of thousands of Vectors*;
    3. Vector3 result = Vector3.zero;
    4. for(int i = 0; i < arr.Length; i++)
    5. {
    6.     result += arr[i];
    7. }
    8.  
    vs

    Code (csharp):
    1.  
    2. Vector3[] arr = *An array of thousands of Vectors*;
    3. Vector3 result = Vector3.zero;
    4. for(int i = 0; i < arr.Length; i++)
    5. {
    6.     result.x += arr[i].x;
    7.     result.y += arr[i].y;
    8.     result.z += arr[i].z;
    9. }
    10.  
    Which honestly though the difference still isn't much. On my machine we're talking a difference of 4ms vs 1.5ms for an array of 100,000 vectors. Which again... you have bigger issues here than the addition operator. Why are you looping and summing 100,000 vectors in an array? Maybe this expensive job should be threaded, rather than optimized via the operator.

    With that said... Unity's implementation of the addition operator uselessly requires 2 stack layers. It would technically been better for them to say:
    Code (csharp):
    1.  
    2. public static Vector3 operator +(Vector3 a, Vector3 b)
    3.     {
    4.         a.x += b.x;
    5.         a.y += b.y;
    6.         a.z += b.z;
    7.         return a;
    8.     }
    9.  
    But eh, who am I to complain.
     
    Last edited: Sep 22, 2017
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    Good points here from everybody, but don't forget when IL2CPP transmogrifies all this IL code, then the C++ compiler on your target platform gets done with it, good luck predicting what any of it actually compiles down to.

    Measure first. THEN optimize where it makes sense.
     
    lordofduct likes this.