2016-07-28 1 views
0

J'ai moi-même écrit des utilitaires mathématiques, qui font tout ce dont j'ai besoin pour les graphiques simples que je programme. Cependant, je ne sais pas comment les rendre éligibles pour passer directement à OpenGL. Cela peut être fait avec GLM, par exemple:Comment les types de données glm peuvent-ils être transmis directement au GPU via des buffers OpenGL?

std::vector<glm::vec3> locations; 

[...] 


glGenBuffers(NUM_BUFFERS, _vbo); 
glBindBuffer(GL_ARRAY_BUFFER, _vbo[POSITION_VBO]); 

// throw data in vbo[0] 
glBufferData(GL_ARRAY_BUFFER, _num_vertices * sizeof(locations[0]), &locations[0], GL_STATIC_DRAW); 

Je voudrais être en mesure de le faire avec mon propre type vec3, maths :: vec3f, comme je ne voudrais pas avoir « perdu » mon temps écrire ces utilitaires. Son implémentation peut être vue ici:

namespace math 
{ 
    template<typename _type> class vec2; 

    template<typename _type> 
    class vec3 
    { 
     private: 
      _type _gl_a[3]; 

     public: 
      _type x, y, z; 

      vec3() {}; 
      vec3(_type _x, _type _y, _type _z) 
      { 
       _gl_a[0] = x = _x; 
       _gl_a[1] = y = _y; 
       _gl_a[2] = z = _z; 
      } 

      vec3(vec2<_type> v, _type w) 
      { 
       _gl_a[0] = x = v.x; 
       _gl_a[1] = y = v.y; 
       _gl_a[2] = z = w; 
      } 

      inline vec3<_type> operator=(vec2<_type> &v) 
      { 
       _gl_a[0] = x = v.x; 
       _gl_a[1] = y = v.y; 
       _gl_a[2] = z = 0; 
      } 

      inline vec3<_type> operator+(_type other)  { return vec3<_type>(x + other, y + other, z + other); } 
      inline vec3<_type> operator-(_type other)  { return vec3<_type>(x - other, y - other, z - other); } 
      inline vec3<_type> operator*(_type other)  { return vec3<_type>(x * other, y * other, z * other); } 
      inline vec3<_type> operator/(_type other)  { return vec3<_type>(x/other, y/other, z/other); } 

      inline vec3<_type> operator+(vec3<_type> &other) { return vec3<_type>(x + other.x, y + other.y, z + other.z); } 
      inline vec3<_type> operator-(vec3<_type> &other) { return vec3<_type>(x - other.x, y - other.y, z - other.z); } 
      inline vec3<_type> operator*(vec3<_type> &other) { return vec3<_type>(x * other.x, y * other.y, z * other.z); } 
      inline vec3<_type> operator/(vec3<_type> &other) { return vec3<_type>(x/other.x, y/other.y, z/other.z); } 

      inline _type operator[](int i) 
      { 
       if(i < 0 || i >= 3) 
        return 0; 

       _gl_a[0] = x; 
       _gl_a[1] = y; 
       _gl_a[2] = z; 
       return _gl_a[i]; 
      } 

      inline double magnitude() 
      { 
       return sqrt(x * x + y * y + z * z); 
      } 

      inline vec3<_type> normal() 
      { 
       double m = this->magnitude(); 
       return vec3<_type>(x/m, y/m, z/m); 
      } 

      inline _type dot(vec3<_type> other) 
      { 
       return x * other.x + y * other.y + z * other.z; 
      } 

      inline vec3<_type> cross(vec3<_type> other) 
      { 
       return vec3<_type>(y * other.z - other.y * z, 
            z * other.x - other.z * x, 
            x * other.y - other.x * y); 
      } 
    }; 

    typedef vec3<float>    vec3f; 
    typedef vec3<double>   vec3d; 
    typedef vec3<int>    vec3i; 
    typedef vec3<unsigned int>  vec3ui; 
    typedef vec3<short>    vec3s; 
    typedef vec3<unsigned short> vec3us; 
}; 

Est-ce une autre fonction de surcharge d'opérateur que je dois ajouter, ou quelque chose de complètement différent?

+0

Vous avez besoin de 2 'operator []' (un non-const et un const) voir std :: vector pour les signatures. Ils devraient retourner '_type &' et '_type const &' pour les versions non const et const. –

+0

Ajout d'une telle fonction ne fait aucune différence pour le résultat. (quand je remplace toutes les occurrences de glm :: vec3 avec math :: vec3f) – Anickyan

Répondre

1

glBufferData prend un pointeur void. C'est exactement ce que vous faites en utilisant le morceau de code avec glm :: vec3. Cependant, vous pouvez le faire de différentes manières.

Depuis GLM stocke ses données dans un union, vous pouvez accéder aux éléments d'un vecteur de plusieurs façons: par operator[] ou par des coordonnées x, y, z. Puisque les éléments sont des valeurs et non des pointeurs, vous avez besoin de l'opérateur & pour les déréférencer. Donc &myvec[0] a le même effet que &myvec.x.

Votre extrait de code prend le pointeur du 1er glm :: vec3 dans le fichier std :: vector. L'adresse mémoire de chaque glm :: vec3 est l'adresse mémoire de son 1er élément. De cette façon, vous passez un pointeur vers un tableau de flotteurs (les éléments du vecteur, si elles sont bien emballés - dans GLM ils sont):

std::vector<glm::vec3> locations; 

glBufferData(GL_ARRAY_BUFFER, _num_vertices * sizeof(locations[0]), &locations[0], GL_STATIC_DRAW); 

// same as above 
//glBufferData(GL_ARRAY_BUFFER, _num_vertices * sizeof(locations[0]), &locations[0][0], GL_STATIC_DRAW); 

// same as above 
//glBufferData(GL_ARRAY_BUFFER, _num_vertices * sizeof(locations[0]), &locations[0].x, GL_STATIC_DRAW); 

je vous recommande de vous familiariser avec le concept des pointeurs, des références et des syndicats en C++, puisque la partie suivante de ma réponse repose sur eux.


Votre implémentation math::vec3 a de multiples problèmes.

1) Comme d'autres déjà indiqué dans les commentaires, vous avez besoin à la fois

_type operator[](int i); 
_type operator[](int i) const; 

pour soutenir const ness.

2) Renvoyer une référence (_type& au lieu d'une valeur (_type).Actuellement, vous renvoyez une valeur par _type operator[](int i);, vos éléments sont donc en lecture seule. En utilisant des références, vous pouvez les lire et les écrire.

_type& operator[](int i); 
_type& operator[](int i) const; 

3) Puisque vous ne pouvez pas avoir des indices négatifs, vous ne devriez pas utiliser signé int pour l'indexation. Utilisez un type non signé: unsigned int fait le travail, mais size_t est encore mieux.

&_type operator[](size_t i); 
&_type operator[](size_t i) const; 

4) Essais fondés sur les if (i < 0 || i >= 3) n'est pas nécessaire. Cela fait simplement en sorte que votre élément accède beaucoup plus lentement aux boucles critiques (lorsque vous accédez aux éléments plusieurs fois). En utilisant size_t vous ne pouvez pas avoir une valeur inférieure à 0, et dans un code correct, vous ne devriez jamais dépasser un indice supérieur à la taille réelle du vecteur.

5) Vous stockez vos données deux fois: une fois dans _gl_a[3] et une fois dans x, y, z. C'est un énorme gaspillage de mémoire. Au lieu de cela, vous devez utiliser un union pour accéder aux mêmes données de plusieurs façons.

union // anonymous union 
{ 
    _gl_a[3]; 
    struct { x, y, z, }; // anonymous struct 
}; 

Une fois que vous avez une bonne mise en œuvre de votre math::vec3, vous pourrez l'utiliser de la même manière que les types de GLM.

+0

Merci! Je n'avais pas pensé à utiliser les syndicats de cette façon. Cela prend tout son sens. – Anickyan

2

glBufferData() prend un void*, donc peu importe le type que vous lui passez. Cette fonction ne voit que la mémoire brute.

Toutefois, vous devez indiquer à OpenGL d'autres manières comment interpréter ces données (par exemple glVertexAttribPointer()). Si vous lui dites d'attendre un tableau de float x3 alors vous devez lui passer un tableau de float x3, sinon vous aurez une sortie cassée.

Alors que glm::vec3 contient 3 flottants, le vôtre contient 6 (en supposant que _type est flottant). Vous avez dupliqué les composants pour apparemment pas de raison. Supprimez les doublons, ou dites à opengl d'attendre votre format, de préférence le premier.

+0

Aussi: instrumentez votre code avec assez de static_asserts pour être sûr qu'il n'y a pas de remplissage caché entre les membres, ni à la fin de la structure, ni d'exigences d'alignement cela peut introduire un remplissage lorsque vous construisez un tableau! – peppe