web-dev-qa-db-ja.com

OpenGL 3 / 4glVertexAttribPointerストライドとオフセットの誤算

頂点配列を正しく指すように問題があります。

_const float vertices[] = {
/* position */ 0.75f, 0.75f, 0.0f, 1.0f, /* color */ 1.0f, 0.0f, 0.0f, 1.0f,
/* position */ 0.75f, -0.75f, 0.0f, 1.0f, /* color */ 0.0f, 1.0f, 0.0f, 1.0f,
/* position */ -0.75f, -0.75f, 0.0f, 1.0f, /* color */ 0.0f, 0.0f, 1.0f, 1.0f, };

...

glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)16);

glDrawArrays(GL_TRIANGLES, 0, 3);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
_

ストライドとオフセットがどのように機能するのかわかりません。私の状況でglVertexAttribPointer()を使用する正しい方法は何ですか?

13
user2350858

GlVertexAttribPointerは問題を起こすことが多いので、ここでさらに説明しようと思います。

属性配列のi番目の属性の開始位置を計算する式は次のとおりです。

startPos(i) = offset + i * stride(From derhass'another answer

そして、以下のグラフで説明されています: tightly packed arrtibute array


コード例が必要な場合は、読み続けてください。

VBOデータのフォーマット から、頂点データを3つのフォーマットで管理できることがわかります。頂点の色とテクスチャの色を混合して三角形を描画する例を作成します。これは、頂点の属性データを準備する方法です。


#way1各属性はVBOです。

この形式は:(xyzxyz ...)(rgbrgb ...)(stst ....)のようになり、両方のsride = 0にすることができます。オフセット= 0。

void prepareVertData_moreVBO(GLuint& VAOId, std::vector<GLuint>& VBOIdVec)
{
    GLfloat vertPos[] = {
        -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,  // positon
    };
    GLfloat vertColor[] = {
      1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,   // color
    };
   GLfloat vertTextCoord[] = {
      0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f     // texture coordinate
   };

    GLuint VBOId[3];

    glGenVertexArrays(1, &VAOId);
    glBindVertexArray(VAOId);
    glGenBuffers(3, VBOId);
    // specify position attribute
    glBindBuffer(GL_ARRAY_BUFFER, VBOId[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertPos), vertPos, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(0);
    // specify color attribute
    glBindBuffer(GL_ARRAY_BUFFER, VBOId[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertColor), vertColor, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(1);
    // specify texture coordinate attribute
    glBindBuffer(GL_ARRAY_BUFFER, VBOId[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertTextCoord), vertTextCoord, GL_STATIC_DRAW);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    VBOIdVec.Push_back(VBOId[0]);
    VBOIdVec.Push_back(VBOId[1]);
    VBOIdVec.Push_back(VBOId[2]);
}

#way2:各属性はシーケンシャルであり、単一のVBOにバッチ処理されます。

この形式は次のようになります:(xyzxyzxyz ... rgbrgb ... ststst ...)、stride = 0にすることができますが、オフセットを指定する必要があります。

void prepareVertData_seqBatchVBO(GLuint& VAOId, std::vector<GLuint>& VBOIdVec)
{

    GLfloat vertices[] = {
     -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,  // position
     1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,   // color
     0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f     // texture coordinate
    };

    GLuint VBOId;
    glGenVertexArrays(1, &VAOId);
    glBindVertexArray(VAOId);

    glGenBuffers(1, &VBOId);
    glBindBuffer(GL_ARRAY_BUFFER, VBOId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // specifiy position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // stride can aslo be 3 * sizeof(GL_FLOAT)
    glEnableVertexAttribArray(0);
    // specify color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(9 * sizeof(GL_FLOAT)));
    glEnableVertexAttribArray(1);
    // specify texture coordinate
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(18 * sizeof(GL_FLOAT)));
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    VBOIdVec.Push_back(VBOId);
}

#way3:単一のVBOのインターリーブ属性

この形式は次のようになります:(xyzrgbstxyzrgbst ...)、オフセットとストライドを手動で指定する必要があります。

void prepareVertData_interleavedBatchVBO(GLuint& VAOId, std::vector<GLuint>& VBOIdVec)
{
    // interleaved data
    GLfloat vertices[] = {
       -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,  // 0
       0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,  // 1
       0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,  // 2
    };

    GLuint VBOId;
    glGenVertexArrays(1, &VAOId);
    glBindVertexArray(VAOId);
    glGenBuffers(1, &VBOId);
    glBindBuffer(GL_ARRAY_BUFFER, VBOId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // specify position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,8 * sizeof(GL_FLOAT), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // specify color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
        8 * sizeof(GL_FLOAT),(GLvoid*)(3 * sizeof(GL_FLOAT)));
    glEnableVertexAttribArray(1);
    // specify texture coordinate
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 
        8 * sizeof(GL_FLOAT), (GLvoid*)(6 * sizeof(GL_FLOAT)));
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    VBOIdVec.Push_back(VBOId);
}

そして、derhassの答えに感謝します。

37
wangdq

ストライドとオフセットはバイト単位で指定されます。位置と色の両方が4つのフロートであるインターリーブされた頂点配列を使用しています。特定の属性配列のi番目の要素から次の要素に移動するには、8つのfloatの距離があるため、ストライドは8 * sizeof(GLfloat)である必要があります。オフセットは、バッファー内の各属性配列の最初の要素のバイト位置であるため、この例では、位置の場合は0、色の場合は4 * sizeof(GLfloat)です。

22
derhass