2016-07-24 22 views
0
füllen

zur Zeit habe ich Probleme eine Struktur mit den Eckpunkten für ein Mesh-Füllung (Screen Quad Befüllung mit hohen Auflösung)Wie ein Struct rechts mit Ecken und Indexpuffern für OpenGL ES

Dies ist die Struktur:

typedef struct { 
    float Position[3]; 
    float Color[4]; 
    float TexCoord[2]; 
    }Vertex; 

Normalerweise würde ich es nur mit per Hand ausfüllen, zB

const Vertex Vertices[]= { 
    {{1,-1,0},{1,0,0,1},{1,1}}, 
    {{1,1,0},{0,1,0,1},{1,0}}, 
    {{-1,1,0},{0,0,1,1},{0,0}}, 
    {{-1,-1,0},{0,0,0,1},{0,1}} 
    }; 

und binden diese zu meinen Buffer usw.

Da ich ein Mesh mit viel höherer Auflösung brauche (11x11 mesh, das ich per Hand ausgefüllt habe, war nicht genug) dachte ich daran, dies mit dieser Methode zu füllen.

- (void) createMesh : (int) width withHeight: (int)height{ 
     int size = width * height + height +1; 
     Vertex Vert[]; //since we will be adding a vertex at the end for the (1,y), (1,v) and the x u 

     int sizeInd = width * height * 2 * 3; 
     GLubyte Ind[sizeInd]; // width * height * 2 number triangles, 3 indices per triangle 

     float x,y,u,v; 
     int count = 0; 

     // Fill Vertices 
     for (int i = 0 ; i <= height ; i++){ 

      y = ((1.0 - i/height) * -1.0) + ((i/height) * 1.0); 
      v = 1.0 - (float) i/(float) height; 

      for (int j = 0; j <= width; j++){ 

       x = (float) j/(float) width; 
       u = x; //(float) j/ (float) count; 

       //Vert[count]= {{x,y,0},{0,0,0,1.0},{u,v}}; 
       Vert[count].Position[0] = x; 
       Vert[count].Position[1] = y; 
       Vert[count].Position[2] = 0; 

       Vert[count].Color[0] = 0.0; 
       Vert[count].Color[1] = 0.0; 
       Vert[count].Color[2] = 0.0; 
       Vert[count].Color[3] = 1.0; 

       Vert[count].TexCoord[0] = u; 
       Vert[count].TexCoord[1] = v; 
       count++; 
      } 
     } 
     //Fill indices 

     count = 0; 
     for (int c = 0; c < sizeInd; c++){ 
      Ind[c] = count; 
      c++; 
      Ind[c] = count + 1; 
      c++; 
      Ind[c] = count + width + 1 + 1; 
      c++; 
      Ind[c] = count + 1; 
      c++; 
      Ind[c] = count + width + 1 + 1 + 1; 
      c++; 
      Ind[c] = count + width + 1 + 1; 
      count++; 
     } 

     //Fill buffer 
     glGenBuffers(1,&_vertexMeshBuffer); 
     glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(Vert), Vert, GL_STATIC_DRAW); 

     glGenBuffers(1, &_indexMeshBuffer); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer); 
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Ind), Ind, GL_STATIC_DRAW); 

    } 

in meiner Render-Methode i ziehen über

glDrawElements(GL_TRIANGLES, (sizeof(GLubyte)* width * height * 2 * 3/sizeof(GLubyte))/*sizeof(Ind)/sizeof(Ind[0])*/, 
       GL_UNSIGNED_BYTE, 0); 

da die GLubyte Ind nicht außerhalb der Funktion existieren, kann ich nicht die Größe über

sizeof(Ind)/sizeof(Ind[0]) 

wie ich bekommen würde normalerweise tun.

Also, ist das der richtige Weg, um eine Struktur zu füllen, oder muss ich das irgendwie anders machen? Dieser Ansatz scheint mir richtig zu sein, aber das könnte auch wegen meines Mangels an sachgemäßem c Wissen in diesem Fall sein

gerade stürzt meine App beim Start, beim Anschließen der erforderlichen Hardware, so dass es möglicherweise nur ein Problem gibt mit der Speicherzuweisung.

Oder hat jemand Informationen darüber, wie man ein Netz mit höherer Auflösung in Ziel-C/Opengles richtig einrichtet?

Ich habe bereits einen Diamant-Schritt-Algorithmus in C++ implementiert, und ich weiß, dass dieser Ansatz nicht perfekt codiert ist, ich habe nur die Anrufe für meinen persönlichen Gebrauch vereinfacht.

Dies ist mehr über die ordnungsgemäße Verwendung des Strukturtyps in Kombination mit den passenden Gles Calls.

jede Hilfe ist willkommen.

EDIT:

Es gibt ein paar Dinge falsch mit meiner automatischen Indizes waren, vor allem vergaß ich zum nächsten am Ende einer Zeile zu springen, da ich, dass er letzte Element einer Reihe Ameise nicht sein, um einen Startpunkt des nächsten Dreiecks-Block

Dies sollte richtig sein:

//Fill indices 

    count = 0; 
    int jumpBarrier = 1; 
    for (int c = 0; c < sizeInd; c++){ 
     Ind[c] = count; 
     c++; 
     Ind[c] = count + 1; 
     c++; 
     Ind[c] = count + width + 1; //; + 1; 
     c++; 
     Ind[c] = count + 1; 
     c++; 
     Ind[c] = count + width + 1 + 1;// + 1; 
     c++; 
     Ind[c] = count + width + 1 ;//+ 1; 

     //jump 
     if (jumpBarrier == width){ 
      count++; 
      count++; 
      jumpBarrier = 1; 
     } 
     else{ 
      count++; 
      jumpBarrier++; 
     } 
    } 

EDIT # 2

duh, innere For-Schleife inkrementiert i statt j, behoben, dass Vertices und Indizes jetzt genau so erzeugt werden, wie sie sein sollten.

EDIT # 3

So gelang es mir, unter Verwendung einer Modifikation dieses Algorithmus nur, um dieses Problem zu bekommen, um alles in eine Textdatei zu drucken und dann in meinem Projekt zu kopieren alles, wo ich sie brauche.

Wenn jemand immer noch erklären möchte, wo ich etwas falsch gemacht habe und wie man diese Struktur richtig füllt, können Sie diese Frage gerne beantworten, um weitere Informationen zu erhalten.

Antwort

0

Über Ihre Masche erstellen:

Um damit zu beginnen Sie wirklich Ihre grundlegendsten Code verkomplizieren. Auch einige Kommentare helfen Ihnen beim Debuggen Ihres Codes. Werfen Sie einen Blick auf dieses Remake:

- (void)createMesh:(int)width height:(int)height { 
    int horizontalVertexCount = width+1; // one more then the number of surfaces 
    int verticalVertexCount = height+1; // one more then the number of surfaces 

    int vertexCount = horizontalVertexCount * verticalVertexCount; // a number of unique vertices 

    // generate a buffer 
    size_t vertexBufferSize = sizeof(Vertex)*vertexCount; 
    Vertex *vertexBuffer = malloc(vertexBufferSize); 

    // iterate through vertices and fill them 
    for(int h=0; h<verticalVertexCount; h++) { 

     // generate y position coordinate 

     GLfloat y = h; 
     y /= verticalVertexCount; // normalzie to be in range of [0,1] 
     y = 2.0f*y - 1; // converting the range [0,1] to [-1,1] 

     // generate y texture coordinate 

     GLfloat v = h; 
     v /= verticalVertexCount; // normalzie to be in range of [0,1] 
     v = 1.0f - v; // converting the range [0,1] to [1,0] 

     for(int w=0; h<horizontalVertexCount; w++) { 
      // generate x position coordinate 

      GLfloat x = w; 
      x /= horizontalVertexCount; // normalzie to be in range of [0,1] 

      // generate x texture coordinate 

      GLfloat u = x; 

      /* 
      The next segment may be replaced by using access as: 

      vertexBuffer[h*horizontalVertexCount + w].Position[0] = x; 
      */ 

      Vertex *currentVertex = vertexBuffer + h*horizontalVertexCount + w; 
      currentVertex->Position[0] = x; 
      currentVertex->Position[1] = y; 
      currentVertex->Position[2] = .0f; 

      currentVertex->Color[0] = .0f; 
      currentVertex->Color[1] = .0f; 
      currentVertex->Color[2] = .0f; 
      currentVertex->Color[3] = 1.0f; 

      currentVertex->TexCoord[0] = u; 
      currentVertex->TexCoord[1] = v; 
     } 
    } 

    // create index buffer 
    int numberOfSurfaces = width*height; 
    int indicesPerSurface = 2*3; // 2 triangles per surface 
    size_t indexBufferSize = sizeof(GLushort)*numberOfSurfaces*indicesPerSurface; 
    GLushort *indexBuffer = malloc(indexBufferSize); 

    for(int h=0; h<height; h++) { 
     for(int w=0; w<width; w++) { 
      int surfaceIndex = h*width + w; 
      int firstIndexIndex = surfaceIndex*indicesPerSurface; 

      indexBuffer[firstIndexIndex] = h*horizontalVertexCount + w; // upper left 
      indexBuffer[firstIndexIndex] = h*horizontalVertexCount + (w + 1); // upper right 
      indexBuffer[firstIndexIndex] = (h+1)*horizontalVertexCount + w; // lower left 

      indexBuffer[firstIndexIndex] = h*horizontalVertexCount + (w + 1); // upper right 
      indexBuffer[firstIndexIndex] = (h+1)*horizontalVertexCount + (w+1); // lower right 
      indexBuffer[firstIndexIndex] = (h+1)*horizontalVertexCount + w; // lower left 
     } 
    } 

    //Fill buffer 
    glGenBuffers(1,&_vertexMeshBuffer); 
    glBindBuffer(GL_ARRAY_BUFFER, _vertexMeshBuffer); 
    glBufferData(GL_ARRAY_BUFFER, vertexBufferSize, vertexBuffer, GL_STATIC_DRAW); 

    glGenBuffers(1, &_indexMeshBuffer); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexMeshBuffer); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSize, indexBuffer, GL_STATIC_DRAW); 

    // release the memory 
    free(vertexBuffer); 
    free(indexBuffer); 
} 

Ich bin nicht sicher, der Code, den ich Arbeiten richtig geschrieben, sollte aber sehr leicht zu debuggen mit einem einfachen Haltepunkt, falls dies nicht der Fall. Versuchen Sie nicht, Ihren Code zu optimieren, bis Sie nach dem aktuellen Code arbeiten müssen.

Sie ein paar Dinge in diesem Beispiel beachten Sie:

  • A malloc verwendet wird, um den Puffer auf den Speicher zu erstellen. Dies ist für große Datenmengen obligatorisch oder Ihr Stack kann überlaufen.
  • Der Indexpuffer wird als short verwendet, da ein byte nur bis zu 256 eindeutige Indizes speichern kann, sodass Ihr Code für große Netze trotzdem fehlschlägt. (Größere Typen als short werden im Allgemeinen nicht zur Indizierung unterstützt.)
  • Ein Code wie der Zugriff auf die Vertices per Zeiger ist nur eine Demo. Sie können sie in einen direkten Zugriff ändern.

Über den Vertex:

Ich bestehe darauf, dass in C Sprachen eine solche Datenstruktur durchgeführt wird, wie Sie taten, aber man könnte ein bisschen weiter fortsetzen. Die Koordinaten position, color und texture sollten structures sein. Und um einen natürlicheren Zugang zu den Werten zu unterstützen. So etwas sollte interessant sein:

typedef union { 
    struct { 
     GLfloat x, y; 
    }; 
    struct { 
     GLfloat u, v; 
    }; 
}Vector2f; 

typedef struct { 
    GLfloat x, y, z; 
}Vector3f; 

typedef union { 
    struct { 
     Vector3f vector3f; 
     GLfloat _w; 
    }; 
    struct { 
     GLfloat x, y, z, w; 
    }; 
    struct { 
     GLfloat r, g, b, a; 
    }; 
}Vector4f; 

typedef struct { 
    Vector3f position; 
    Vector4f color; 
    Vector2f textureCoordinates; 
}Vertex; 

Wenn Sie nicht auf den Begriff der union verwendet werden, schlage ich vor, Sie setzen, dass auf dem TO-READ-ÜBER-Liste. In diesem Fall können Sie auf dieselben Daten über mehrere Eigenschaften zugreifen: Wenn Sie eine Vector4f myVector haben, dann ist myVector.x immer dasselbe wie myVector.r, dies wird getan, damit der Code klarer ist, was Sie tun. Sie können sehen, dass GLSL (Shader-Sprache) die gleichen Prinzipien verwendet. Die Nutzung kann dann sein:

  currentVertex->position.x = x; 
      currentVertex->position.y = y; 
      currentVertex->position.z = .0f; 

      currentVertex->color.r = .0f; // could use .x 
      currentVertex->color.g = .0f; // could use .y 
      currentVertex->color.b = .0f; // could use .z 
      currentVertex->color.a = 1.0f; // could use .w 

Nachdem Sie eine schöne Struktur haben alles, was Sie jemals brauchen werden, ist sizeof (Sie verwenden es bereits) und offsetof (was ich hoffe, dass Sie verwenden, wenn Hinweise auf Attribute zuweisen). Dadurch müssen Sie den Zeichencode nicht ändern, wenn Sie Ihre Struktur bearbeiten. Wenn Sie beispielsweise an einer bestimmten Stelle in Ihrer Struktur Vertex Strukturen hinzufügen, fügen Sie einfach einen weiteren Vektor in die Struktur ein, und kein anderer Code muss geändert werden, damit Ihr Programm funktioniert.

Wrapping die Daten:

So, nachdem Sie Ihre Strukturen haben Sie würden diese in einige Objekte zu packen. An dieser Stelle empfehle ich Ihnen, zu vollständiger Objective-C zu gehen und eine neue Klasse zu erstellen, die alle Daten enthält, die Sie zum Zeichnen des Objekts benötigen. Dies bedeutet, dass Sie eine IDs des Vertexpuffers und Indexpuffers, Zeichnungsmodus, Offsets, Schritt und Scheitelwert haben. Eine grundlegende Implementierung sollte wie folgt sein:

@interface MeshVertexObject : NSObject 

@property (nonatomic) GLuint vertexBufferID; // assigned when generating a mesh 
@property (nonatomic) GLuint indexBufferID; // assigned when generating a mesh 
@property (nonatomic) GLuint vertexCount; // assigned when generating a mesh 
@property (nonatomic) GLenum drawMode; // assigned when generating a mesh. GL_TRIANGLES 

@property (nonatomic, readonly) void *positionPointer; // depending on the Vertex structure 
@property (nonatomic, readonly) void *colorPointer; // depending on the Vertex structure 
@property (nonatomic, readonly) void *texturePointer; // depending on the Vertex structure 

@property (nonatomic, readonly) GLint positionStride; // depending on the Vertex structure 
@property (nonatomic, readonly) GLint colorStride; // depending on the Vertex structure 
@property (nonatomic, readonly) GLint textureStride; // depending on the Vertex structure 


@end 

@implementation MeshVertexObject 

- (void)dealloc { 
    // remove all the GL data bound to this calss on destructor 
    if(self.vertexBufferID > 0) { 
     GLuint vBuffer = self.vertexBufferID; 
     self.vertexBufferID = 0; 
     glDeleteBuffers(1, &vBuffer); 
    } 
    if(self.indexBufferID > 0) { 
     GLuint iBuffer = self.indexBufferID; 
     self.indexBufferID = 0; 
     glDeleteBuffers(1, &iBuffer); 
    } 
} 

- (void *)positionPointer { 
    return (void *)offsetof(Vertex, position); 
} 
- (void *)colorPointer { 
    return (void *)offsetof(Vertex, color); 
} 
- (void *)texturePointer { 
    return (void *)offsetof(Vertex, textureCoordinates); 
} 

- (GLint)positionStride { 
    return sizeof(Vertex); 
} 
- (GLint)colorStride { 
    return sizeof(Vertex); 
} 
- (GLint)textureStride { 
    return sizeof(Vertex); 
} 

@end 

Dies ist nun die Klasse, die Ihre Masche Erzeugungsverfahren halten würde und würde möglicherweise eine andere Form Generatoren wie Würfel, Kugeln ...

Aber dann Das Kaninchenloch geht noch tiefer ... Jetzt, da Sie ein System auf dem System aufbauen können, können Sie komplexere Objekte erstellen, die auch Textur-IDs (oder wieder eher Texture Objekte, die diese IDs enthalten) und die Mesh-Objekte enthalten. Dann fügen Sie auch die Daten für ihre Lage und Orientierung auf der Szene und Serviceleistungen, die Matrizen Sie bei der Erstellung Pipeline ...

Die Schlussfolgerung verwenden zu generieren:

Sie machen es richtig oder zumindest gehen richtig Weg. Aber wenn Sie weiterhin ein System aufbauen wollen, wenn Sie in der Lage sein wollen, Ihren Code zu debuggen und meistens Ihren Code zu pflegen, dann behalten Sie die Module so einfach wie möglich und so kommentiert wie sie können und bauen Sie einfach weiter auf.

+0

Danke für solch eine detaillierte Antwort! Kurz gesagt: Man muss Speicher manuell mit malloc zuweisen, anstatt ein Array mit einer bestimmten Größe zu erstellen, und dann erzeugte Strukturen/Elemente an die richtige Stelle schieben. – seko

+0

Die Zuweisung selbst macht wenig Unterschied. Im Allgemeinen können Sie statische Arrays verwenden, wenn die Arrays klein genug sind und die Anzahl der Scheitelpunkte fest ist. Sonst ist die explizite Speicherzuweisung eine Verbesserung der Performance und der Stabilität, und da es praktisch keinen Nachteil gibt, wenn man sie in objectiveC verwendet, schlage ich vor, sie zu verwenden. Eine andere Möglichkeit besteht darin, NSData oder seine veränderbare Version zu verwenden, die praktisch dasselbe tut, aber bereits in objectiveC eingebettet ist, so dass der Speicher nicht freigegeben werden muss, da er von der ARC gehandhabt wird. Sie können etwas wie Vertex * vertexBuffer = (Vertex *) [Datenbytes] verwenden –