11

私は iOS 用の新しい OpenGL フレームワーク (GLKit という適切な名前) を検討しており、既存の OpenGL 1.0 コードを OpenGL ES 2.0 に移植して遊んでいました。

API と、Apple が提供するその他のベスト プラクティスと OpenGL のドキュメントを読んだ後、頂点バッファ オブジェクトを使用し、「要素」またはむしろ頂点インデックスを使用する必要があることをかなり深く理解しました。必要に応じてパディングを使用してメモリストレージを最適化することについても多くの言及があるようですが、それはおそらく別の日の会話です;)

SO で、従来の malloc/free よりも NSMutableData を使用する利点について少し前に読み、VBO を作成するときにこのアプローチを試してみたいと思いました。これまでのところ、正しい道を進んでいるように見えるスニペットをまとめることができましたが、VBO に含まれるデータの量については完全にはわかりません。これが私がこれまでに持っているものです:

//import headers
#import <GLKit/GLKit.h>

#pragma mark -
#pragma mark InterleavingVertexData

//vertex buffer object struct
struct InterleavingVertexData
{
    //vertices
    GLKVector3 vertices;

    //normals
    GLKVector3 normal;

    //color
    GLKVector4 color;

    //texture coordinates
    GLKVector2 texture;
};
typedef struct InterleavingVertexData InterleavingVertexData;

#pragma mark -
#pragma mark VertexIndices

//vertex indices struct
struct VertexIndices
{
    //vertex indices
    GLuint a;
    GLuint b;
    GLuint c;
};
typedef struct VertexIndices VertexIndices;

//create and return a vertex index with specified indices
static inline VertexIndices VertexIndicesMake(GLuint a, GLuint b, GLuint c)
{
    //declare vertex indices
    VertexIndices vertexIndices;

    //set indices
    vertexIndices.a = a;
    vertexIndices.b = b;
    vertexIndices.c = c;

    //return vertex indices
    return vertexIndices;
}

#pragma mark -
#pragma mark VertexBuffer

//vertex buffer struct
struct VertexBuffer
{
    //vertex data
    NSMutableData *vertexData;

    //vertex indices
    NSMutableData *indices;

    //total number of vertices
    NSUInteger totalVertices;

    //total number of indices
    NSUInteger totalIndices;
};
typedef struct VertexBuffer VertexBuffer;

//create and return a vertex buffer with allocated data
static inline VertexBuffer VertexBufferMake(NSUInteger totalVertices, NSUInteger totalIndices)
{
    //declare vertex buffer
    VertexBuffer vertexBuffer;

    //set vertices and indices count
    vertexBuffer.totalVertices = totalVertices;
    vertexBuffer.totalIndices = totalIndices;

    //set vertex data and indices
    vertexBuffer.vertexData = nil;
    vertexBuffer.indices = nil;

    //check vertices count
    if(totalVertices > 0)
    {
        //allocate data
        vertexBuffer.vertexData = [[NSMutableData alloc] initWithLength:(sizeof(InterleavingVertexData) * totalVertices)];
    }

    //check indices count
    if(totalIndices > 0)
    {
        //allocate data
        vertexBuffer.indices = [[NSMutableData alloc] initWithLength:(sizeof(VertexIndices) * totalIndices)];
    }

    //return vertex buffer
    return vertexBuffer;
}

//grow or shrink a vertex buffer
static inline void VertexBufferResize(VertexBuffer *vertexBuffer, NSUInteger totalVertices, NSUInteger totalIndices)
{
    //check adjusted vertices count
    if(vertexBuffer->totalVertices != totalVertices && totalVertices > 0)
    {
        //set vertices count
        vertexBuffer->totalVertices = totalVertices;

        //check data is valid
        if(vertexBuffer->vertexData)
        {
            //allocate data
            [vertexBuffer->vertexData setLength:(sizeof(InterleavingVertexData) * totalVertices)];
        }
        else
        {
            //allocate data
            vertexBuffer->vertexData = [[NSMutableData alloc] initWithLength:(sizeof(InterleavingVertexData) * totalVertices)];
        }
    }

    //check adjusted indices count
    if(vertexBuffer->totalIndices != totalIndices && totalIndices > 0)
    {
        //set indices count
        vertexBuffer->totalIndices = totalIndices;

        //check data is valid
        if(vertexBuffer->indices)
        {
            //allocate data
            [vertexBuffer->indices setLength:(sizeof(VertexIndices) * totalIndices)];
        }
        else
        {
            //allocate data
            vertexBuffer->indices = [[NSMutableData alloc] initWithLength:(sizeof(VertexIndices) * totalIndices)];
        }
    }
}

//release vertex buffer data
static inline void VertexBufferRelease(VertexBuffer *vertexBuffer)
{
    //set vertices and indices count
    vertexBuffer->totalVertices = 0;
    vertexBuffer->totalIndices = 0;

    //check vertices are valid
    if(vertexBuffer->vertexData)
    {
        //clean up
        [vertexBuffer->vertexData release];
        vertexBuffer->vertexData = nil;
    }

    //check indices are valid
    if(vertexBuffer->indices)
    {
        //clean up
        [vertexBuffer->indices release];
        vertexBuffer->indices = nil;
    }
}

現在、インターリーブ頂点データには、各頂点の頂点、法線、色、およびテクスチャ座標を格納するのに十分なデータが含まれています。頂点とインデックスの数が等しいという印象を受けましたが、実際には明らかにそうではないため、インデックスは InterleavingVertexData ではなく VBO の一部です。

質問が更新されました:

上記のコードを動作状態にすることができた後、コードを更新しました。うまくいけば、それは将来誰かに役立つでしょう。

すべてを設定できたので、VBO にバインドされたコンテンツをレンダリングして期待される結果を得ることができません。データを OpenGL にロードするためにこれまでに取得したコードは次のとおりです。

//generate buffers
glGenBuffers(2, buffers);

//bind vertices buffer
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, (sizeof(InterleavingVertexData) * vertexBuffer.totalVertices), self.vertexData, GL_STATIC_DRAW);

//bind indices buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (sizeof(VertexIndices) * vertexBuffer.totalIndices), self.vertexIndices, GL_STATIC_DRAW);

//reset buffers
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

そして、すべてをレンダリングするためのコード:

//enable required attributes
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribNormal);
glEnableVertexAttribArray(GLKVertexAttribColor);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);

//bind buffers
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);

//set shape attributes
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(InterleavingVertexData), (void *)offsetof(InterleavingVertexData, vertices));
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_TRUE, sizeof(InterleavingVertexData), (void *)offsetof(InterleavingVertexData, normal));
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_TRUE, sizeof(InterleavingVertexData), (void *)offsetof(InterleavingVertexData, color));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_TRUE, sizeof(InterleavingVertexData), (void *)offsetof(InterleavingVertexData, texture));

//draw shape
glDrawElements(GL_TRIANGLES, vertexBuffer.totalIndices, GL_UNSIGNED_INT, (void *)0);

//reset buffers
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

//disable atttributes
glDisableVertexAttribArray(GLKVertexAttribTexCoord0);
glDisableVertexAttribArray(GLKVertexAttribColor);
glDisableVertexAttribArray(GLKVertexAttribNormal);
glDisableVertexAttribArray(GLKVertexAttribPosition);

私の iPhone は、目から虹を放つユニコーンの素晴らしいグラフィックスでまだ爆発していませんが、髪を引き裂かずに単純な形状を完全にレンダリングすることはできませんでした.

レンダリングからは、各形状の 1/3 だけが描かれているように見えます。見る角度によっては、おそらく 1/2 が描かれているように見えます。glDrawElements に渡された count パラメータがこれをいじると結果が異なるのが原因のようですが、ドキュメントを読んで値を何度も確認しましたが、実際にはインデックスの総数が予想されます (これは私が現在通過中)。

元の質問で述べたように、私は現在の VBO にかなり混乱しているか、少なくとも概念ではなく実装に混乱しています。誰かが私の実装に目を向けてくれるほど親切であれば、それは非常に素晴らしいことです。途中でどこかで新人エラーを犯したと確信していますが、何かを何時間も見つめているとどうなるか知っています進展なしで終了。

読んでくれてありがとう!

4

1 に答える 1

4

I think I see your problem.

You've got a struct, VertexIndices which contains three indices, or the indices for one triangle. When you bind your IBO (Index Buffer Object, the buffer object containing your indices), you do this:

glBufferData(GL_ELEMENT_ARRAY_BUFFER, (sizeof(VertexIndices) * vertexBuffer.totalIndices), self.vertexIndices, GL_STATIC_DRAW);

Which is fine. The size parameter in glBufferData is in bytes so you're multiplying sizeof(3 floats) by the number of groups of 3 floats that you have. Great.

But then when you actually call glDrawElements, you do this:

glDrawElements(GL_TRIANGLES, vertexBuffer.totalIndices, GL_UNSIGNED_INT, (void *)0);

However, the vertexBuffer.totalIndices is equal to the number of VertexIndices structs you've got, which is equal to the total number of indices / 3 (or total number of triangles). So you need to do one of the following:

  1. Easy fix yet stupid: glDrawElements(..., vertexBuffer.totalIndices * 3, ...);
  2. Proper yet more work: vertexBuffer.totalIndices should contain the actual total number of indices that you've got, not the total number of triangles you're rendering.

You need to do one of these because right now totalIndices contains the total number VertexIndices you've got, and each one has 3 indices. The right thing to do here is either rename totalIndices to totalTriangles, or keep track of the actual total number of indices somewhere.

于 2011-12-16T17:51:23.050 に答える