c++矢量数学和OpenGL兼容

C++ Vector Math and OpenGL compatible

本文关键字:OpenGL 兼容 c++      更新时间:2023-10-16

我一直在做很多矢量数学的东西,并为它写了自己的模板。

我的需求是大量的矢量数学(加法,减法,比例,交叉prod和点prod),我还需要能够将我的矢量作为浮点数传递[],以便openGL可以使用它。

我一直很高兴地使用它一段时间,今天一个讲师看到它并抱怨。有两件事他特别讨厌(其中一件我理解),我对继承的使用,因为它似乎不遵循is a的风格。而我选的(T*)this,当然他没有太多的解决办法。

: 继承,我需要能够利用vec2到vec4的,所以我这样设计我的向量

template<typename T>
Vector2D
{
 public:
 getX(), getY(), setX(), setY() ....
};
template<typename T>
Vector3D : public Vector2D<T>
{
 public:
 getZ(), setZ() ...
}
template<typename T>
Vector4D : public Vector3D<T>
{
 public:
 getW(), setW() ...
}

为什么这不好?而且我不知道如何改进它。我需要(想要)能够定义类型,并有某种类型的getter和setter。如果我把它重新排列成

template<typename T, int _size>
VectorT

我会失去我的.getX(), .setX()的东西,不得不取代它与.at()[]的东西。我更喜欢.getX()的可读性,尽管它会使操作符定义更容易。

第二:

我可以看到为什么这是不好的,但为了使它,我可以将这些向量传递到openGL的方法,期望一个浮点数组,我已经重载了splat操作符

// Defined in Vector2D<T>
operator*() { return (T*)this; }

在我的理解中,不能保证编译器会将成员变量x、y、z、w放在类的开头,如果不小心的话,我可能最终会传递v表。但是我必须承认,到目前为止我还没有遇到任何问题。

我能看到的唯一方法是维护一个返回的数组。我想如果我一开始就改变处理向量的方式的话会容易一些

您可能需要考虑使用GLM。它完成了您所描述的所有功能(尽管我发现缺少文档),包括与OpenGL的集成。

你可以听你的老师,并使用部分专业化(警告:未测试):

template<typename T, int size>
class Vector;
template< typename T >
class Vector< T, 2 >
{
  public :
    Vector() : data() {}
    T GetX() const { return data[0]; };
    T GetY() const { return data[1]; };
    void SetX( const T v ) const { data[0]=v; };
    void SetY( const T v ) const { data[1]=v; };
  private :
    T data[2];
};
template< typename T >
class Vector< T, 3 >
{
  public :
    Vector() : data() {}
    T GetX() const { return data[0]; };
    T GetY() const { return data[1]; };
    T GetZ() const { return data[2]; };
    void SetX( const T v ) const { data[0]=v; };
    void SetY( const T v ) const { data[1]=v; };
    void SetZ( const T v ) const { data[2]=v; };
  private :
    T data[3];
};

这个怎么样:

template<class T, int _dim>
class Vector
{
    T v[_dim];
    operator*(){return v;}
friend T inner_product(Vector<T, _dim> const &v1, Vector<T, _dim> const &v2);
};
template<class T, int _dim>
T inner_product(Vector<T, _dim> const &v1, Vector<T, _dim> const &v2)
{
    T p = 0.;
    for(int i; i < _dim; i++)
        p += v1.v[i] * v2.v[i];
    return p;
}
template<class T>
class Vector2 : Vector<T, 2>
{
    float getX() const {return v[0];}
    float getS() const {return v[0];}
    float getY() const {return v[1];}
    float getT() const {return v[1];}
}
template<class T>
class Vector3 : Vector<T, 3>, Vector2<T>
{
    float getZ() const {return v[2];}
    float getR() const {return v[2];}
}
template<class T>
class Vector4 : Vector<T, 4>, Vector3<T>
{
    float getW() const {return v[3];}
    float getQ() const {return v[3];}
}

注意,使inner_product成为朋友,而不是类的一部分,允许您将其用于所有派生类型!

就像你说的,你在滥用继承的"is-a"性质。如果您编写这样的函数,可能会出现问题

float dotProduct(vector2D a, vector2D b);

你可以传入一个3D向量并得到一个标量结果,而实际上2d向量和3D向量的点积是未定义的,这实际上是一个可能导致奇怪行为的bug。虽然这不是什么大问题,但是你放弃了一些类型检查,如果你要处理静态类型的痛苦,你也可以在类似的错误出现时得到它的好处。

维护数组绝对是一个更好的解决方案,你不想依赖于未定义的行为,因为你永远不知道什么时候它会把你彻底搞砸。

我可能会这样做:

template<typename T>
class VectorT{
protected:
  T* m_data;
  int m_size;
public:
  VectorT(unsigned int size) 
  : m_size(size)
  {
    m_data=new T[size];
  }
  virtual ~VectorT()
  {
    delete[] m_data;
  }
  T* operator*() { return m_data; }
  T& operator[](int ii) { return m_data[ii]; }
}
template<typename T>
class Vector3 : public VectorT<T>
{
public:
  Vector3() : VectorT(3) {}
  T getX() { return m_data[0]; }
  T getY() { return m_data[1]; }
  T getZ() { return m_data[2]; }
  Vector3 crossP(const Vector3& vv) { ... }
}

这是一个完整的OpenGL风格的c++数学库(开源)

http://glm.g-truc.net/