Jump to content
  • Advertisement
Sign in to follow this  
Misery

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

This topic is 1137 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
Advertisement

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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!