Search Unity

Vector4Int missing?

Discussion in 'Scripting' started by arkano22, Jan 14, 2020.

  1. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,929
    Maybe I'm the only one looking for it, but.... the absence of Vector4Int when there's Vector3Int and Vector2Int to match their floating point counterparts, is mildly uncomfortable. :)

    Any plans to include it?
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    I think you may be the only one looking for it, TBH. I'm having a hard time imagining a point for Vector4Int. It's tough enough thinking of ways to use Vector4, and all the examples for that I can think of for that (v3+time, some graphics shenanigans, etc) are very explicitly dependent on the numbers being floats.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    Agreed with StarManta, but if you find yourself needing it you can just write your own:
    Code (csharp):
    1.  
    2. using System;
    3. using System.Globalization;
    4. using System.Runtime.InteropServices;
    5. using UnityEngine.Scripting;
    6.  
    7. namespace UnityEngine
    8. {
    9.     [System.Serializable]
    10.     [StructLayout(LayoutKind.Sequential)]
    11.     public struct Vector4Int : IEquatable<Vector4Int>, IFormattable
    12.     {
    13.         public int x { get { return m_X; } set { m_X = value; } }
    14.         public int y { get { return m_Y; } set { m_Y = value; } }
    15.         public int z { get { return m_Z; } set { m_Z = value; } }
    16.         public int w { get { return m_W; } set { m_W = value; } }
    17.  
    18.         private int m_X;
    19.         private int m_Y;
    20.         private int m_Z;
    21.         private int m_W;
    22.  
    23.         public Vector4Int(int x, int y, int z, int w)
    24.         {
    25.             m_X = x;
    26.             m_Y = y;
    27.             m_Z = z;
    28.             m_W = w;
    29.         }
    30.  
    31.         // Set x, y and z components of an existing Vector.
    32.         public void Set(int x, int y, int z, int w)
    33.         {
    34.             m_X = x;
    35.             m_Y = y;
    36.             m_Z = z;
    37.             m_W = w;
    38.         }
    39.  
    40.         // Access the /x/, /y/ or /z/ component using [0], [1] or [2] respectively.
    41.         public int this[int index]
    42.         {
    43.             get
    44.             {
    45.                 switch (index)
    46.                 {
    47.                     case 0: return x;
    48.                     case 1: return y;
    49.                     case 2: return z;
    50.                     case 3: return w;
    51.                     default:
    52.                         throw new IndexOutOfRangeException(UnityString.Format("Invalid Vector4Int index addressed: {0}!", index));
    53.                 }
    54.             }
    55.  
    56.             set
    57.             {
    58.                 switch (index)
    59.                 {
    60.                     case 0: x = value; break;
    61.                     case 1: y = value; break;
    62.                     case 2: z = value; break;
    63.                     case 3: w = value; break;
    64.                     default:
    65.                         throw new IndexOutOfRangeException(UnityString.Format("Invalid Vector4Int index addressed: {0}!", index));
    66.                 }
    67.             }
    68.         }
    69.  
    70.         // Returns the length of this vector (RO).
    71.         public float magnitude { get { return Mathf.Sqrt((float)(x * x + y * y + z * z + w * w)); } }
    72.  
    73.         // Returns the squared length of this vector (RO).
    74.         public int sqrMagnitude { get { return x * x + y * y + z * z + w * w; } }
    75.  
    76.         // Returns the distance between /a/ and /b/.
    77.         public static float Distance(Vector4Int a, Vector4Int b) { return (a - b).magnitude; }
    78.  
    79.         // Returns a vector that is made from the smallest components of two vectors.
    80.         public static Vector4Int Min(Vector4Int lhs, Vector4Int rhs) { return new Vector4Int(Mathf.Min(lhs.x, rhs.x), Mathf.Min(lhs.y, rhs.y), Mathf.Min(lhs.z, rhs.z), Mathf.Min(lhs.w, rhs.w)); }
    81.  
    82.         // Returns a vector that is made from the largest components of two vectors.
    83.         public static Vector4Int Max(Vector4Int lhs, Vector4Int rhs) { return new Vector4Int(Mathf.Max(lhs.x, rhs.x), Mathf.Max(lhs.y, rhs.y), Mathf.Max(lhs.z, rhs.z), Mathf.Max(lhs.w, rhs.w)); }
    84.  
    85.         // Multiplies two vectors component-wise.
    86.         public static Vector4Int Scale(Vector4Int a, Vector4Int b) { return new Vector4Int(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); }
    87.  
    88.         // Multiplies every component of this vector by the same component of /scale/.
    89.         public void Scale(Vector4Int scale) { x *= scale.x; y *= scale.y; z *= scale.z; w *= scale.w; }
    90.  
    91.         public void Clamp(Vector4Int min, Vector4Int max)
    92.         {
    93.             x = Math.Max(min.x, x);
    94.             x = Math.Min(max.x, x);
    95.             y = Math.Max(min.y, y);
    96.             y = Math.Min(max.y, y);
    97.             z = Math.Max(min.z, z);
    98.             z = Math.Min(max.z, z);
    99.             w = Math.Max(min.w, w);
    100.             w = Math.Min(max.w, w);
    101.         }
    102.  
    103.         // Converts a Vector4Int to a [[Vector4]].
    104.         public static implicit operator Vector4(Vector4Int v)
    105.         {
    106.             return new Vector4(v.x, v.y, v.z, v.w);
    107.         }
    108.  
    109.         // Converts a Vector4Int to a [[Vector2Int]].
    110.         public static explicit operator Vector3Int(Vector4Int v)
    111.         {
    112.             return new Vector3Int(v.x, v.y, v.z);
    113.         }
    114.  
    115.         // Converts a Vector4Int to a [[Vector2Int]].
    116.         public static explicit operator Vector2Int(Vector4Int v)
    117.         {
    118.             return new Vector2Int(v.x, v.y);
    119.         }
    120.  
    121.         public static Vector4Int FloorToInt(Vector4 v)
    122.         {
    123.             return new Vector4Int(
    124.                 Mathf.FloorToInt(v.x),
    125.                 Mathf.FloorToInt(v.y),
    126.                 Mathf.FloorToInt(v.z),
    127.                 Mathf.FloorToInt(v.w)
    128.             );
    129.         }
    130.  
    131.         public static Vector4Int CeilToInt(Vector4 v)
    132.         {
    133.             return new Vector4Int(
    134.                 Mathf.CeilToInt(v.x),
    135.                 Mathf.CeilToInt(v.y),
    136.                 Mathf.CeilToInt(v.z),
    137.                 Mathf.CeilToInt(v.w)
    138.             );
    139.         }
    140.  
    141.         public static Vector4Int RoundToInt(Vector4 v)
    142.         {
    143.             return new Vector4Int(
    144.                 Mathf.RoundToInt(v.x),
    145.                 Mathf.RoundToInt(v.y),
    146.                 Mathf.RoundToInt(v.z),
    147.                 Mathf.RoundToInt(v.w)
    148.             );
    149.         }
    150.  
    151.         public static Vector4Int operator+(Vector4Int a, Vector4Int b)
    152.         {
    153.             return new Vector4Int(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
    154.         }
    155.  
    156.         public static Vector4Int operator-(Vector4Int a, Vector4Int b)
    157.         {
    158.             return new Vector4Int(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
    159.         }
    160.  
    161.         public static Vector4Int operator*(Vector4Int a, Vector4Int b)
    162.         {
    163.             return new Vector4Int(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
    164.         }
    165.  
    166.         public static Vector4Int operator-(Vector4Int a)
    167.         {
    168.             return new Vector4Int(-a.x, -a.y, -a.z, -a.w);
    169.         }
    170.  
    171.         public static Vector4Int operator*(Vector4Int a, int b)
    172.         {
    173.             return new Vector4Int(a.x * b, a.y * b, a.z * b, a.w * b);
    174.         }
    175.  
    176.         public static Vector4Int operator*(int a, Vector4Int b)
    177.         {
    178.             return new Vector4Int(a * b.x, a * b.y, a * b.z, a * b.w);
    179.         }
    180.  
    181.         public static Vector4Int operator/(Vector4Int a, int b)
    182.         {
    183.             return new Vector4Int(a.x / b, a.y / b, a.z / b, a.w / b);
    184.         }
    185.  
    186.         public static bool operator==(Vector4Int lhs, Vector4Int rhs)
    187.         {
    188.             return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w;
    189.         }
    190.  
    191.         public static bool operator!=(Vector4Int lhs, Vector4Int rhs)
    192.         {
    193.             return !(lhs == rhs);
    194.         }
    195.  
    196.         public override bool Equals(object other)
    197.         {
    198.             if (!(other is Vector4Int)) return false;
    199.  
    200.             return Equals((Vector4Int)other);
    201.         }
    202.  
    203.         public bool Equals(Vector4Int other)
    204.         {
    205.             return this == other;
    206.         }
    207.  
    208.         public override int GetHashCode()
    209.         {
    210.             var yHash = y.GetHashCode();
    211.             var zHash = z.GetHashCode();
    212.             var wHash = w.GetHashCode();
    213.             return x.GetHashCode() ^ (yHash << 8) ^ (yHash >> 24) ^ (zHash << 16) ^ (zHash >> 16) ^ (wHash << 24) ^ (wHash >> 8);
    214.         }
    215.  
    216.         public override string ToString()
    217.         {
    218.             return ToString(null, CultureInfo.InvariantCulture.NumberFormat);
    219.         }
    220.  
    221.         public string ToString(string format)
    222.         {
    223.             return ToString(format, CultureInfo.InvariantCulture.NumberFormat);
    224.         }
    225.  
    226.         public string ToString(string format, IFormatProvider formatProvider)
    227.         {
    228.             return UnityString.Format("({0}, {1}, {2}, {3})", x.ToString(format, formatProvider), y.ToString(format, formatProvider), z.ToString(format, formatProvider), w.ToString(format, formatProvider));
    229.         }
    230.  
    231.         public static Vector4Int zero { get { return s_Zero; } }
    232.         public static Vector4Int one { get { return s_One; } }
    233.  
    234.         private static readonly Vector4Int s_Zero = new Vector4Int(0, 0, 0, 0);
    235.         private static readonly Vector4Int s_One = new Vector4Int(1, 1, 1, 1);
    236.     }
    237. }
    238.  
    completely untested, written quickly in notepad, based off the unity source for Vector3Int:
    https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector3Int.cs
     
    HalfAsWise, z3nth10n and arkano22 like this.
  4. Deleted User

    Deleted User

    Guest

    I was surprised to see that Vector4 existed; what could it be used for?
     
    Joe-Censored likes this.
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    4-dimensional vector math.

    Specifically in unity things like mesh tangents, and shader logic. Shader logic uses 4d vectors for various things since a lot of the math utilizes a 4x4 matrix for transformations, and a row/col of that matrix will be a 4d vector. Vector4 exists as a type to translate between shaders and unity. Also color information in shaders can be stored as 4d vectors (rgba, argb, etc). As well as when you may just need to do some 4d vector math of your own.
     
  6. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,929
    Hi!

    I wrote my own simplistic version of it, but it simply struck me as strange that it did not already exist.

    My use case is a bit special. Im writing a cell based spatial subdivision structure in which cells are four dimensional. So the index of a cell is 4 ints. Might as well write a “CellIndex” struct specific for this.

    Vector4, in addition to matrix multiplication, shaders, storing colors and some unconventional quaternion operations, also comes in handy when interfacing with native code that needs 16 byte alignment for simd intrinsics. I guess i’m a weirdo, but I very often I find myself using Vector4.
     
    Last edited: Jan 14, 2020
    BrainSlugs83 likes this.
  7. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    As ridiculous as it sounds, technically doing this is a violation of the Unity Reference Only License in which the Unity source is licensed under :p

    https://unity3d.com/legal/licenses/Unity_Reference_Only_License
     
  8. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    I absolutely think Unity should include Vector4Int. The argument for consistency should be enough. I am using it for containing values to be uploaded to shaders.
     
  9. Eden1230

    Eden1230

    Joined:
    Feb 23, 2020
    Posts:
    10
    download the mathametics package from package manager
     
  10. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,929
    Not a valid replacement for me. However I wrote my own struct that contains 4 ints, as well as some very specific operations over it. All is well ;)
     
  11. BrainSlugs83

    BrainSlugs83

    Joined:
    Jun 18, 2015
    Posts:
    38
    That is a ridiculous statement. Anytime you need to do 4D math you need a 4D vector. It's also ridiculous that it's missing and we have to use Vector4 instead.
     
    viseztrance and Walter_Hulsebos like this.
  12. ATMLVE

    ATMLVE

    Joined:
    Jun 11, 2023
    Posts:
    75
    This is an old thread (warn me and lock it if you dare) but I wanted to use Vector4Int to store data for RectInts, which I'm using to procedurally generate things on a grid. The int is important due to the grid nature. It's not even needed as I only ever supply it with ints, not floats, but that's beside the point.

    All I had to do was add (int) to the components when I needed to reference them. However I was compelled to add my use case here since a few people mentioned "I can't imagine why you would need to do that" which was obviously the case with whoever neglected to include it in the first place, and is simply a naive statement as shown by the various people here with interest in Vector4Int or representing various uses for it. There will always be people trying to do different things in different ways. Sure, sometimes maybe it's because they're trying to do something an unintendedly bad way and they don't know any better, but you can always give people the benefit of the doubt.
     
  13. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    What data of a RectInt are you storing that can't be stored in a RectInt?

    A RectInt consists of 4 int values... x(min), y(min), width, height. All other values are implied from those 4.
    https://github.com/Unity-Technologi...98f9af/Runtime/Export/Geometry/RectInt.cs#L19

    What is the Vector4Int doing that the RectInt isn't already doing?

    ...

    Years ago when StarManta said that they can't imagine a need for Vector4Int... they weren't talking about not imagining needing a struct of 4 ints. Sure, a struct of 4 ints could have boundless uses.

    And if you need a struct of 4 ints... creating one is trivial:

    Code (csharp):
    1. public struct Int4
    2. {
    3.     public int x;
    4.     public int y;
    5.     public int z;
    6.     public int w;
    7. }
    They're referring specifically to the need of a Vector4Int. Because Vector4Int has a greater implied thing. It's not just a data container (which appears to be your need... you want store some data for some RectInts that RectInt isn't itself suitable?) But rather is a mathematical concept. It's... a vector of discrete values. Vectors have certain attributes, namely "magnitude and direction". It's the definition of a vector. And from there various mathematical operations are defined (like scalar products, addition and subtraction, distance (which is the magnitude of the vector resulting from a subtraction), and other things.

    This is what StarManta is referring to not knowing what you may need a Vector4Int for.

    Vector2Int and Vector3Int are specifically intended for positional vectors with only whole values. This makes sense since Unity has 2D and 3D gameplay.

    It doesn't have 4D gameplay.

    You might say "well then what is Vector4 for", but as I said a few years ago that has to do with shader logic and the sort and it behaves as a translation struct between shader code and C#. But there isn't really a need for int versions there since well shaders are all about float math... not integer math. It's what GPUs do best... they're effectively thousands of FPUs (floating point units) running in parallel.

    ...

    Now yeah, some people may come up with edge case scenarios for such things. May it be 4D math related (as some people have suggested). But if you're out here doing 4D maths for your 4D game... well writing a simple struct to do it is trivial. Especially considering that Vector4Int from Unity wouldn't have any of the interesting functions you might expect (Vector3Int is fairly basic as well and lacks things like dot products and the sort... so a Vector4Int version would lack such things as well likely and we'd all be back in the boat of "why doesn't it have this function or that").

    Speaking of which... mathematics has it! And if you're doing complicated 4d maths you probably are going to want the unity mathematics library.

    And sure... maybe all you want is just this one struct and don't want to import the whole unity mathematics library in just for int4.

    Yeah... that's a good point.

    But couldn't you also argue that why should Unity have to implement Vector4Int in the core library just because a couple people might have this weird edge case of needing it but not needing the unity mathematics library and isn't otherwise just exploiting it as a basic data storage struct in which case... implementing it yourself is trivial as I showed above in just 7 lines of code.

    Wait... I'll do it in one:
    Code (csharp):
    1. public struct Vector4Int { public int x, y, z, w; }
    If all you need is storage...
     
    Bunny83, ATMLVE, MelvMay and 2 others like this.
  14. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    482
    int4 isn't good enough?
    https://docs.unity3d.com/Packages/com.unity.mathematics@1.3/api/Unity.Mathematics.int4.html
     
    ATMLVE, Ryiah, MelvMay and 1 other person like this.
  15. ATMLVE

    ATMLVE

    Joined:
    Jun 11, 2023
    Posts:
    75
    Thank you both for your responses. To address the first thing that came up, I need to make another non-rectint object with the same dimensions so just start with simple data.

    As you both pointed out, there are a multitude of ways to accomplish the task. Those are great and appropriate answers.