2016-07-28 5 views
0

Ich habe selbst Mathematik-Programme geschrieben, die alles tun, was ich für die einfachen Grafiken brauche, die ich programmiere. Ich weiß jedoch nicht, wie sie für die direkte Weitergabe an OpenGL geeignet sind. Dies kann mit GLM, zB erfolgen:Wie können Glm-Datentypen über OpenGL-Puffer direkt an die GPU übergeben werden?

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); 

Ich mag wäre in der Lage sein, dies zu tun mit meiner eigenen vec3 Art, Mathematik :: vec3f, da ich nicht „verschwendete“ meine eigene Zeit haben möchte diese Dienstprogramme schreiben. Seine Implementierung kann hier gesehen werden:

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; 
}; 

Ist es eine andere Operator Überlastfunktion, die ich hinzufügen muss, oder etwas ganz anderes?

+0

Sie benötigen 2 'operator []' (eine nicht-const und eine const) siehe std :: vector für die Signaturen. Sie sollten '_type &' und '_type const &' für die nicht-const und const Versionen zurückgeben. –

+0

Das Hinzufügen einer solchen Funktion hat keinen Einfluss auf das Ergebnis. (Wenn ich alle Vorkommen von Glm :: Vec3 durch Mathe :: Vec3f ersetze) – Anickyan

Antwort

1

glBufferData dauert ein void Zeiger. Genau das tun Sie mit dem Code-Stück mit glm :: vec3. Sie können dies jedoch auf verschiedene Arten tun.

Seit GLM seine Daten in einem union speichert, können Sie die Elemente eines Vektors auf mehrere Arten zugreifen: durch operator[] oder durch Koordinaten x, y, z. Da die Elemente Werte sind, keine Zeiger, benötigen Sie den Operator &, um sie zu dereferenzieren. So hat &myvec[0] den gleichen Effekt wie &myvec.x.

Ihr Codeausschnitt nimmt den Zeiger des 1. Glm :: vec3 im std :: vector. Die Speicheradresse jedes glm :: vec3 ist die Speicheradresse seines ersten Elements. Auf diese Weise übergeben Sie einen Zeiger auf ein Array von Schwimmern (die Elemente des Vektors, wenn sie dicht gepackt sind - in GLM sie sind):

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); 

Ich empfehle Ihnen mit dem Konzept vertraut zu machen von Zeigern, Referenzen und Vereinigungen in C++, da sich der folgende Teil meiner Antwort auf sie stützt.


Ihre math::vec3 Implementierung hat mehrere Probleme.

1) Wie andere bereits in den Kommentaren erwähnt, müssen Sie beide

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

const -ness zu unterstützen.

2) Geben Sie eine Referenz (_type&) anstelle eines Werts (_type) ein.Derzeit geben Sie einen Wert von _type operator[](int i); zurück, daher sind Ihre Elemente schreibgeschützt. Mit Referenzen können Sie sie lesen und schreiben.

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

3) Da Sie nicht negative Indizes haben kann, sollten Sie nicht int für die Indizierung unterzeichnet verwenden. Verwenden Sie einen unsigned Typ: unsigned int macht den Job, aber size_t ist noch besser.

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

4) Prüfung gegen if (i < 0 || i >= 3) ist nicht erforderlich. Es macht Ihr Element nur in kritischen Schleifen viel langsamer zugänglich (wenn Sie oft auf die Elemente zugreifen). Mit size_t können Sie keinen Wert kleiner als 0 haben, und in einem korrekten Code sollten Sie niemals einen Index höher als die tatsächliche Größe des Vektors übergeben.

5) Sie speichern Ihre Daten zweimal: einmal in _gl_a[3] und einmal in x, y, z. Dies ist eine riesige Verschwendung von Erinnerung. Stattdessen sollten Sie einen union verwenden, um auf dieselben Daten auf mehrere Arten zuzugreifen.

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

Sobald Sie eine korrekte Umsetzung Ihrer math::vec3 haben, können Sie es als GLM-Typen in der gleichen Art und Weise nutzen.

+0

Danke! Ich hatte nicht daran gedacht, Gewerkschaften auf diese Weise zu nutzen. Es macht durchaus Sinn. – Anickyan

2

glBufferData() dauert ein void*, so ist es egal, welchen Typ Sie daran übergeben. Diese Funktion sieht nur rohen Speicher.

Sie müssen OpenGL jedoch auf andere Weise mitteilen, wie diese Daten zu interpretieren sind (z. B. glVertexAttribPointer()). Wenn Sie sagen, dass es ein Array von float x3 erwartet, müssen Sie ihm ein Array float x3 übergeben, sonst erhalten Sie eine fehlerhafte Ausgabe.

Während glm::vec3 3 Gleitkommazahlen enthält, enthält Ihr Gleitkommazahl 6 (vorausgesetzt, dass _type float ist). Du hast die Komponenten für scheinbar keinen Grund dupliziert. Entweder entfernen Sie die Duplikate oder sagen Sie opengl, um Ihr Format zu erwarten, vorzugsweise ersteres.

+0

Außerdem: Instrumentieren Sie Ihren Code mit genügend 'static_asserts', um sicher zu sein, dass hier keine versteckten Padding zwischen Mitgliedern, noch am Ende der Struktur noch Ausrichtung Anforderungen das kann Padding einführen, wenn Sie ein Array erstellen! – peppe

Verwandte Themen