2016-07-24 7 views
0

現在私が持っているメッシュの頂点を持つ構造体を埋める問題(画面が高解像度でクワッドを充填)のOpenGL ESのための頂点とインデックスバッファを持つ構造体の右側を埋める方法

これは構造体である:

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

通常、私はちょうど

など、手あたりでそれを埋める例えば

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

と私のバッファにこれを結合します

もっと高い解像度のメッシュが必要なので(11x11メッシュで十分ではありませんでした)、私はこの方法でこれを埋め込むことを考えました。私のrenderメソッドで

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

    } 

iはGLubyte工業は、関数の外に存在しないため、私は、私のような

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

を経由してサイズを取得することはできません

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

を経由して描きます通常はやります。

これは構造体を埋める正しい方法ですか、それとも何とか他の方法で行う必要がありますか?このアプローチは私にとっては正しいと思われますが、これは私の適切な客観的知識が不足しているためでもあります。

今、私のアプリは、必要なハードウェアを接続するときにクラッシュするので、メモリ割り当てを伴う。

また、目的のc/openglで高解像度のメッシュを正しく設定する方法についての情報はありますか?

私はすでにC++でダイヤモンドステップアルゴリズムを実装していますが、このアプローチが完全にコーディングされていないことを知っています。

これは、一致するgles呼び出しと組み合わせてstruct型を適切に使用する方法の詳細です。

何か援助を歓迎します。

EDIT:いくつかのことが私の自動インデックスと間違っていた

、主に私は、行の彼の最後の要素をアリないので、次の行の最後にジャンプするのを忘れました次の三角形ブロックの出発点であることが

これは右でなければならない:

//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、forループ内でiを増やしてjの代わりに増やした場合、 頂点とインデックスが作成されるようになりました。

EDIT#3

だから私は単なるテキストファイル内のすべてを印刷するには、このアルゴリズムの変更を使用して、その後、私はそれらを必要とする私のプロジェクトのすべてをコピーすることによってこの問題を回避するために管理。

もし誰かが何か間違ったことをしたがって、この構造体の権利を実際に埋める方法を説明したいのであれば、この質問に答えて歓迎します。あなたのメッシュの作成について

答えて

0

あなたが本当にあなたの最も基本的なコードをovercomplicateで開始します。また、コードのデバッグに役立つコメントもあります。このリメイクを見てみましょう:

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

私はコードを私が正しく作品を掲示したが、それはない場合に、単純なブレークポイントでデバッグすることは非常に簡単であるべきことを確認していません。現在のコードがうまく機能するようになるまで、コードを最適化しようとしないでください。

は、この例ではいくつかのことに注意してください:

  • mallocは、メモリ上のバッファを作成するために使用されます。これは、大きなデータセットの場合は必須です。スタックがオーバーフローする可能性があります。
  • インデックスバッファはbyteに256個までのユニークインデックスしか格納できないため、大規模なメッシュではコードが失敗するため、shortとして使用されます。 (より大きい型の場合は、一般的に短くはインデックス作成ではサポートされません)
  • ポインタによる頂点へのアクセスなどのコードはデモ用です。それらを直接アクセスに変更することができます。
  • Vertexについて

私はC言語であなたがしたようなデータ構造が行われていますが、少しさらに続けることができると主張しています。 position,colorおよびtextureの座標は、structuresである必要があります。また、値へのより自然なアクセスをサポートします。このような何かは興味深いものになる必要があります:あなたはunionの概念に使用されていない場合は

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; 

私はあなたがあなたのTO-READ-ABOUTリストにそれを置く提案します。この場合、複数のプロパティを使用して同じデータにアクセスすることができます。Vector4f myVectorがある場合、myVector.xは常にmyVector.rと同じです。これは、実行中のコードがより明確になるように行われます。 GLSL(シェーダ言語)は同じ原則を使用していることがわかります。使い方はその後になります

  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 

あなたは(私は属性へのポインタを割り当てるときに使用している願っています)素敵なあなたが必要とするすべてのsizeofある構造(あなたはすでにそれを使用している)とoffsetofを持っていた後。これにより、構造を編集する場合に図面コードを変更する必要がなくなります。たとえば、ある時点でVertex構造体に法線を追加することを選択した場合、構造体に別のベクトルを追加するだけで、プログラムを動作させるために他のコードを変更する必要はありません。データをラッピング

あなたの構造を持っているので、後にあなたには、いくつかのオブジェクトにこれらをパックしたいと思います。この時点で、Objective-Cを完全に使ってオブジェクトを描画するために必要なすべてのデータを保持する新しいクラスを作成することをお勧めします。これは、頂点バッファとインデックスバッファ、描画モード、オフセット、ストライド、頂点数のIDを持つことを意味します。 ...

しかし、その後

@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 

これはあなたのメッシュ生成方法を開催すると、おそらく、このような立方体、球体などの他の形状の発電機が含まれるクラスは以下のようになります。基本的な実装では、このようなものでなければなりませんウサギの穴がいっそう深くなる...システム上にシステムを構築することができたので、テクスチャID(これらのIDを含むオブジェクトTexture)とメッシュオブジェクトを含むより複雑なオブジェクトを作成することができます。あなたは右のそれをやったり、少なくとも正しい予定されている

:その後も

...シーンとあなたがパイプラインを描画で使用行列を生成するための便利上の位置と向きのために結論をデータを追加方法。しかし、システムを構築したい場合は、コードをデバッグし、主にコードを維持できるようにするには、できるだけシンプルにモジュールをコメントにして、ビルドアップを続けてください。

+0

このような詳細な回答ありがとうございます!したがって、要するに:特定のサイズの配列を作成する代わりにmallocを使って手動でメモリを割り当て、作成した構造体/要素を正しい場所にプッシュする必要があります。 – seko

+0

割り当て自体はほとんど違いがありません。一般に、配列が十分に小さく、頂点の数が固定されている場合は、静的配列を使用できます。それ以外の場合、明示的なメモリ割り当てはパフォーマンスと安定性の向上であり、目的を達成するための欠点はほとんどありませんので、使用することをお勧めします。もう1つの方法は、NSDataまたはその可変バージョンを使用することです。これはほぼ同じことですが、既にobjectiveCでラップされているため、ARCによって処理されるようにメモリを解放する必要はありません。 Vertex * vertexBuffer =(Vertex *)[data bytes]のようなものを使うことができます。 –

関連する問題