2016-07-24 1 views
0

actuellement j'ai des problèmes de remplissage d'un struct avec des sommets pour un maillage (écran de remplissage Quad avec une haute résolution)Comment remplir un droit Struct avec des sommets et tampon d'index pour openGL ES

C'est le struct:

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

Normalement, je voudrais juste le remplir avec par main, par exemple

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

et se lier à mon tampon, etc.

Depuis que j'ai besoin d'un Mesh avec une résolution beaucoup plus élevée (11x11 mesh que je remplis à la main ne suffisait pas) j'ai pensé à Remplir ceci via cette méthode.

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

    } 

dans ma méthode render je dessine via

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

depuis le GLubyte Ind n'existe pas en dehors de la fonction, je ne peux pas obtenir la taille via

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

comme i ferait normalement.

Alors, est-ce la bonne façon de remplir une structure ou est-ce que je dois le faire d'une autre manière? Cette approche me semble juste, mais cela pourrait aussi être à cause de mon manque de connaissance objective objective c dans ce cas

maintenant, mon application se bloque au démarrage, lors de la connexion du matériel requis, donc il pourrait y avoir un problème avec l'allocation de mémoire.

Ou est-ce que quelqu'un a des informations sur la façon de configurer correctement un maillage de plus haute résolution dans les objectifs c/opengl?

J'ai déjà implémenté un algorithme en pas à pas en C++, et je sais que cette approche n'est pas parfaitement codée, je viens de simplifier les appels pour mon usage personnel.

Il s'agit davantage de l'utilisation correcte du type struct en combinaison avec les appels gles correspondants.

toute aide est la bienvenue.

EDIT:

Il y avait quelques choses de mal à mes indices automatiques, principalement j'ai oublié de sauter à la fin d'une ligne à l'autre, puisque je ne fourmi pas qu'il dernier élément d'une rangée être un point de départ du prochain triangle bloc

Cela devrait être bon:

//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, interne for-loop incrémenté i au lieu de j, fixé que, vertices et les index sont maintenant créés comme ils devraient être.

EDIT # 3

Je réussi à contourner ce problème en utilisant une modification de cet algorithme pour imprimer uniquement tout dans un fichier texte, puis tout copier dans mon projet où je les ai besoin.

Si quelqu'un veut toujours expliquer où j'ai fait quelque chose de mal et comment remplir réellement ce droit struct, vous êtes invités à répondre à cette question pour d'autres apprentissages.

Répondre

0

A propos de la création de votre maillage:

Pour commencer, vous overcomplicate vraiment votre code le plus élémentaire. En outre, certains commentaires vous aideront à déboguer votre code. Jetez un oeil à ce 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); 
} 

Je ne suis pas sûr que le code ne fonctionne correctement que j'affiché, mais devrait être très facile à déboguer avec un simple point d'arrêt dans le cas où il ne fonctionne pas. N'essayez pas d'optimiser votre code tant que vous n'avez pas besoin de ce qui fonctionne après le code actuel.

Prenez note quelques petites choses dans cet exemple:

  • Un malloc est utilisé pour créer la mémoire tampon dans la mémoire. Ceci est obligatoire pour les grands ensembles de données ou votre pile peut déborder.
  • Le tampon d'index est utilisé comme short car un byte ne peut stocker que jusqu'à 256 index uniques, de sorte que votre code échouera de toute façon pour les maillages de grande taille. (Les types plus grands que les formats courts ne sont généralement pas pris en charge pour l'indexation)
  • Un code tel que l'accès aux sommets par pointeur est juste pour la démo. Vous pouvez les changer pour un accès direct.

A propos du Vertex:

J'insistent sur le fait que dans les langues C une telle structure de données se fait comme vous l'avez fait, mais vous pouvez continuer un peu plus loin. Les coordonnées position, color et texture doivent être structures. Et pour soutenir un accès plus naturel aux valeurs. Quelque chose comme cela devrait être intéressant:

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; 

Si vous n'êtes pas habitué au concept de union je vous suggère de mettre cela sur votre liste à lire-PROPOS. Dans ce cas, il vous permet d'accéder aux mêmes données via plusieurs propriétés: Si vous avez un Vector4f myVector alors myVector.x est toujours le même que myVector.r, ceci est fait pour que le code soit plus clair sur ce que vous faites. Vous pouvez voir que GLSL (shader language) utilise les mêmes principes. L'utilisation peut alors être:

  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 

Une fois que vous avez une belle structure tout ce que vous aurez besoin est sizeof (vous utilisez déjà) et offsetof (que j'espère que vous utilisez lors de l'attribution des pointeurs aux attributs). En faisant cela, vous n'aurez pas besoin de changer le code de dessin si vous éditez votre structure. Par exemple, si à certains moments vous avez choisi d'ajouter des normales dans votre structure Vertex, vous ajouterez simplement un autre vecteur dans la structure et aucun autre code ne devra changer pour que votre programme fonctionne.

Envelopper les données:

Donc une fois que vous avez vos structures que vous voulez emballer ces derniers dans certains objets. À ce stade, je vous suggère d'aller en Objective-C et de créer une nouvelle classe qui contient toutes les données dont vous avez besoin pour dessiner l'objet. Cela signifie que vous aurez un identifiant du tampon de vertex et du tampon d'index, du mode de dessin, des offsets, du pas de foulée et du nombre de vertex. Une mise en œuvre de base devrait être quelque chose comme ceci:

@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 

Ceci est maintenant la classe qui détiendrait votre méthode de génération de maillage et pourrait éventuellement inclure d'autres générateurs de forme tels que des cubes, des sphères ...

Mais le trou de lapin va encore plus loin ... Maintenant que vous pouvez construire un système sur le système, vous pouvez créer des objets plus complexes qui incluent également des identifiants de texture (ou encore plutôt des objets qui incluent ces identifiants) et les objets maillés. Puis aussi ajouter les données pour leur emplacement et l'orientation sur la scène et les commodités pour générer les matrices que vous utilisez dans la canalisation dessin ...

La conclusion:

Vous faites bien ou au moins aller correct façon. Mais si vous voulez continuer à construire un système, si vous voulez pouvoir déboguer votre code et surtout pouvoir maintenir votre code, gardez les modules aussi simples que possible et aussi commentés qu'ils peuvent être et continuez simplement à construire.

+0

Merci pour cette réponse détaillée! Donc, en bref: il faut allouer de la mémoire manuellement avec malloc au lieu de créer un tableau avec une taille spécifique, et ensuite pousser les structures/éléments créés au bon endroit. – seko

+0

La répartition elle-même fait peu de différence. En général, vous pouvez utiliser des tableaux statiques si les tableaux sont suffisamment petits et si le nombre de sommets est fixe. Sinon, l'allocation explicite de la mémoire est un gain de performance et de stabilité et comme il n'y a pratiquement aucun inconvénient à l'utiliser dans l'objectif, je vous suggère de l'utiliser. Une autre façon est d'utiliser NSData ou sa version mutable qui fait à peu près la même chose mais qui est déjà enveloppée dans objectiveC, il n'est donc pas nécessaire de libérer la mémoire car elle sera gérée par l'ARC. Vous pouvez utiliser quelque chose comme Vertex * vertexBuffer = (Vertex *) [octets de données] –