Sign in to follow this  

Unity Most efficient way of designing a vector class in 3D

This topic is 827 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Recently I started to use unity3d for my hobby game project and I really liked a Vector3 (and similar) classes (in C#). At the moment at work I am implementing a simple (but for large simulations) SPH solver. What I would like to achieve is a similar Vector3 class in C++ in the means of access to elements both by v.x, v.y, v.z and v[0], v[1], v[2]. In general to obtain this is very simple, but none of the solutions that came to my mind is free of flaws.

 

Solution 1: using references &x, &y, &z, problem: such class has three additional variables which occupy the memory. In the case of large simulation it is problematic:

template <class T>
  class Vector3
  {
    public:
        T &x,&y,&z;
        T v[3];

        Vector3(): x(v[0]), y(v[1]), z(v[2])
        {
          v[0]=0; v[1]=1;  v[2]=2;
        }

        T& operator[](int i)
        {
            return v[i];
        }
  };

The access is very elegant:

v[i] 

as well as

v.x, v.y and v.z

And this is what I woluld like to obtain - this elegant access. However the additional memory overhead is unacceptable.

 

Solution 2: using class fileds x,y,z and access operator with if statement: problem performance of [] operator

template <class T>
  class Vector3
  {
    public:
        T x,y,z;

        Vector3(): x(0), y(1), z(2)
        { }

        T& operator[](int i) 
        {
            if (i==0) return x;
            else if (i==1) return y;
            else if (i==2) reurn z;
            else 
            {
                //throw access error
            }
        }
  };

This solution is elegant as well, but the operator [] will be very slow.

 

Solution 3: Using the class functions x(), y(), z()

template <class T>
  class Vector3
  {
    public:
        T v[3];

        Vector3()
        {
          v[0]=0; v[1]=1; v[2]=2;
        }

        T& operator[](int i)
        {
            return v[i];
        }

       T& x() { return v[0]; }
       T& y() { return v[1]; }
       T& z() { return v[2]; }
  };

This solution is ideal in means of efficiency and memory overhead, but, does not allow elegant access to members, requires for example v.x() instead of v.x.

 

The question is: is there a way to obtain this elegant access with no efficiency and memory loss?

 

 

Share this post


Link to post
Share on other sites

Yeah union with anonymous struct has got to be the easiest way to do it,

 

Just to expand on imoogiBG's answer to follow suit with templates.

template <class T>
struct Vector3
{
    union
    {
        T v[3];
	struct { T x; T y; T z; };
    };
};
Edited by Syntac_

Share this post


Link to post
Share on other sites

Couldn't you just use the array access? Will you later want to add r, g, b, a and s, t or u, v?

namespace vectors {

enum accessors {
  x,
  y,
  z,
  w
};

template <typename T>
struct Vector4
{
  T d[4];
  T& operator[](size_t index);
  const T& operator[](size_t index) const;
};

}

Share this post


Link to post
Share on other sites

Sorry I forgot to include the operator to be able access like v[0].

template <class T>
struct Vector3
{
    union
    {
	T v[3];
	struct { T x;  T y; T z; };
    };

    T& operator[](int i)
    {
	// guard against accessing out-of-bounds
        return v[i];
    }
};

Vector3<float> v;
v.x = 3.0f;

std::cout << v[0]; // prints 3

Share this post


Link to post
Share on other sites

How does that code allow me to write "v.x"?

It does not really need to and avoids weird workarounds/UB for a questionable convenience.

But you can easily do:

using namespace vectors;

float bar(const Vector4<float>& v) {
  return v[x];
}

Edited by wintertime

Share this post


Link to post
Share on other sites

Re-iterating what Hodgman wrote, these arrays of floats are functional but not ideal.

 

If you are looking for performance most systems will use built-in SIMD structures for the data that are specific to the system you are developing for.  That can mean the intrinsic type __m128 variables in the x86 family, or the intrinsic float32x4_t variables in ARM chips. 

 

Transferring to and from these packed, special-purpose registers is not efficient. If possible leave your data packed in the more efficient formats.

Share this post


Link to post
Share on other sites

Solution 4

union 
{
    float v[3];
    struct { float x, float y, float z; };
}

 
 

Yeah union with anonymous struct has got to be the easiest way to do it,


 
Union-based type-punning is non-standard. It is supported by both GCC and Visual Studio, so I use it, but it's important to remember that it's not guaranteed by the standard.
 
I've heard talk of them standardizing it in a future C++ standard, but I'm not sure if they already did that (in C++14 maybe?), or if they are intending to do it, what the status is on it.

Share this post


Link to post
Share on other sites

My vector class is basically:

Vector<ComponentType, Dimensions>

 

With typedefs as:

Vec2f

Vec3i

Vec4ui

etc. (for all primitive types for dimensions 1-4)

 

And I chose to ONLY allow array subscript access:

myVector[0] = 1.0f;

 

For matrices (similar in all other aspects), I instead use call operator overload:

myMatrix(0,0) = 1.0f;

Because Im not going to make a fancy proxy class just so I can use [].

 

 

Its just 2 extra characters so I didnt see a reason to hack support for x,y,z,w. Those dont even allow indexing by variable (which is usually needed to avoid code repetition) so it would be a messy combination of array style access and letters, which would probably just lead to bugs and harder to understand code.

 

 

Ill have to add Vector.swizzle(indices) (as in glsls vec.xz for example) because lack of having that has annoyed me recently...

 

If I were to add x,y,z I would probably just use methods named x() y() z() for them. That way I could implement the swizzle stuff like xy() xz() and so on using same syntax.

 

EDIT:

Also I love how VS2015 can create the method definition body for me because creating those by hand is not fun with these template classes...

Edited by Waterlimon

Share this post


Link to post
Share on other sites

If you really need vector types like this then I would say just use GLM, but if you want performance then I would say stay away from class VectorN...

 

If you do want a simple vector type and you don't want to use GLM you could use the following in Clang anyway:

 

using Vector3 = float __attribute__((ext_vector_type(3)));
//Vector3 is pretty much identical to vec3 or float3 from GLSL or HLSL
Edited by Chris_F

Share this post


Link to post
Share on other sites

 

Solution 4

union 
{
    float v[3];
    struct { float x, float y, float z; };
}
 
 

Yeah union with anonymous struct has got to be the easiest way to do it,


 
Union-based type-punning is non-standard. It is supported by both GCC and Visual Studio, so I use it, but it's important to remember that it's not guaranteed by the standard.
 
I've heard talk of them standardizing it in a future C++ standard, but I'm not sure if they already did that (in C++14 maybe?), or if they are intending to do it, what the status is on it.

 

Yeah it's not, but the world will collapse (literally) so this will never be changed.

Additional tip. It is currently better to implement the methods of the vector class using v[] instead of x,y,z, becase for some reason(at least msvc) the compiler doesn't know that x,y,z are sequental in memory, thus wont use the multiple lane SIMD instructions (for example movss could be used multiple times instead of one movups). 

 

EDIT: I saf the fastcall22 answer; My mistake this was on VS2013, I really don't know about 2015

Edited by imoogiBG

Share this post


Link to post
Share on other sites

for some reason(at least msvc) the compiler doesn't know that x,y,z are sequental in memory, thus wont use the multiple lane SIMD instructions.


Hmm? I don't think this is true. Or am I misunderstanding? I recently SIMD-ified an inner loop in one of my projects and compared the assembly before and after. I was using a home-grown xywz vector4 and Visual Studio 2015 properly used the *PS instructions.

When I get home today, I can double check.

Share this post


Link to post
Share on other sites


Hmm? I don't think this is true. Or am I misunderstanding? I recently SIMD-ified an inner loop in one of my projects and compared the assembly before and after. I was using a home-grown xywz vector4 and Visual Studio 2015 properly used the *PS instructions.

Automatic vectorization sometimes works, sometimes doesn't.  If the compiler happens to recognize a specific pattern it might do it in parallel.

 

The problem is that the result isn't guaranteed.  It is an optimization that sometimes the compiler does, but it could easily stop doing due to a minor change in the code, or an update to the compiler and build tools.

 

And there are many cases where the code could be easily made SIMD where the compiler doesn't recognize it. The programmer could take some few simple actions and vectorize loops with little work.

 

If you want to actually rely on SIMD, you need to explicitly code for it.  

Share this post


Link to post
Share on other sites

I see automatic vectorization as a way to get a free performance boost from old code by simply recompiling it. If you are writing new code with performance in mind you should not count on the compiler automatically doing anything for you.

Share this post


Link to post
Share on other sites

In MathGeoLib I use Hodgman's method, see https://github.com/juj/MathGeoLib/blob/master/src/Math/float3.h#L104 , and that has worked well in practice. For float4 type and __m128 support, I use the union approach, see https://github.com/juj/MathGeoLib/blob/master/src/Math/float4.h#L56 . I favor using those over fancy template accesses, simply because the generated intermediate code is much straightforward, and the code also looks cleaner. (and I extensively unit test on MinGW32/MingW64/GCC/Clang/MSVCs on different platforms so I know when the code is good or not for the platforms I care. Nothing beats rigorous automated testing when it comes to having a peace of mind for correctness)

Share this post


Link to post
Share on other sites

This topic is 827 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      628642
    • Total Posts
      2983993
  • Similar Content

    • By arash khalaqhdoust
      hey guys i hope you doing all well. last night i released my first game in google app store, i really appreciate you guys  to download it. and share your reviews about it
      the idea of game comes from mini hackgame of Bioshock.
       link of download:
      https://play.google.com/store/apps/details?id=com.RVBinary.piperist
      many thanks
    • By ForgedInteractive
      Who We Are
      We are Forged Interactive, a small team of like-minded game developers with the sole purpose of making games we love! Currently, we're progressing very quickly with our first project and there are plenty of opportunities and work for new interested programmers. With this project, our development platform is Unity 5.5.2 and C# as our behavioral language. Since this project is our first release, the game itself is a smaller project though progress is moving quickly. We are looking to finalize the current project and get started on future projects in the near future and are expanding our team to do so.
       
      Who We Are Looking For:
      Programmer Level Designer  
      About the Game
      Ours is the tale of two siblings, thrown into a world of chaos. Living in the shadow of their parents' heroic deeds and their Uncle's colorful military career, Finn and Atia are about to become the next force to shape our world. How will you rise through the ranks of Hereilla and what will be your legacy? Once defeated your enemies turn coat and join you in your adventures. Players can enjoy a range of troops and abilities based on their gameplay style which become more important as maps introduce more challenging terrain, enemies and bosses. Strong orc knights, dangerous shamans, and even a dragon are out on the prowl. Knowing when to fight and when to run, and how to manage your army is essential. Your actions alone decide the fate of this world.
       
      Previous Work by Team
      Although we are working towards our first game as Forged Interactive, our team members themselves have worked on titles including and not limited to:
      Final Fantasy Kingsglaive FIFA 2017 Xcom 2 Civilization  
      What do we expect?
      Reference work or portfolio. Examples what have you already done and what projects you have worked on academic or otherwise. The ability to commit to the project on a regular basis. If you are going on a two-week trip, we don't mind, but it would be good if you could commit 10+ hours to the project each week. Willingness to work with a royalty based compensation model, you will be paid when the game launches. Openness to learning new tools and techniques
       
      What can we offer?
      Continuous support and availability from our side. You have the ability to give design input, and creative say in the development of the game. Shown in credits on websites, in-game and more. Insight and contacts from within the Industry.
       
      Contact
      If you are interested in knowing more or joining, please email or PM us on Skype. A member of our management team will reply to you within 48 hours.
       
      E-mail: Recruitment@ForgedInteractive.com
      Skype: ForgedInteractive
       
      Regards,
      David, Colin and Joseph
       
      Follow us on:
      Facebook: https://www.facebook.com/ForgedInteractive/
      Twitter: @ForgedInteract
      Youtube: https://www.youtube.com/channel/UCpK3zhq5ToOeDpdI0Eik-Ug?view_as=subscriber
      Reddit: www.reddit.com/user/Forged_Interactive

    • By dell96
      I'm trying to make my first project but I'm stuck i don't know how to make my crate to start to spawn again when i hit the start button after i die.
      hoping someone can help!!!
      Crate.cs
      CrateSpawn.cs
      Cratework.cs
      GameController.cs
      GameManager.cs
  • Popular Now