24

私は最近、Vertex Array Objects (VAO) を使用して OpenGL 3.3 コードをいくつか書いていて、後で Intel グラフィックス アダプターでテストしましたが、残念なことに、要素配列バッファー バインディングは明らかに VAO 状態の一部ではないことがわかりました。

glBindVertexArray(my_vao);
glDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_INTEGER, 0);

効果はありませんでしたが、

glBindVertexArray(my_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, my_index_buffer); // ?
glDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_INTEGER, 0);

ジオメトリをレンダリングしました。私はそれが OpenGL の Intel 実装の単なるバグだと思っていました (GL_ARB_vertex_array_object (および GL_OES_vertex_array_object でさえも) 要素配列保存された状態の一部であることが明確に述べられているため) が、モバイル NVIDIA Quadro 4200 で発生しました。 .

ドライバーのバグですか、仕様のバグですか、それともコードのどこかにバグがありますか? コードは GeForce 260 および 480 で問題なく動作します。

似たような経験をした人はいますか?

また、GL_EXT_direct_state_access には、要素配列バッファーを VAO にバインドする関数がないことも奇妙です (ただし、頂点属性配列、つまり配列バッファーを指定する関数はあります)。GPU メーカーは仕様を台無しにして、私たちをごまかしていますか、それとも何ですか?

編集

ここでは必要ないと思ったので、最初はソース コードを表示するつもりはありませんでした。ただし、要求に応じて、問題を再現する最小限のテスト ケースを次に示します。

static GLuint n_vertex_buffer_object, p_index_buffer_object_list[3];
static GLuint p_vao[2];

bool InitGLObjects()
{
    const float p_quad_verts_colors[] = {
        1, 0, 0, -1, 1, 0,
        1, 0, 0, 1, 1, 0,
        1, 0, 0, 1, -1, 0,
        1, 0, 0, -1, -1, 0, // red quad
        0, 0, 1, -1, 1, 0,
        0, 0, 1, 1, 1, 0,
        0, 0, 1, 1, -1, 0,
        0, 0, 1, -1, -1, 0, // blue quad
        0, 0, 0, -1, 1, 0,
        0, 0, 0, 1, 1, 0,
        0, 0, 0, 1, -1, 0,
        0, 0, 0, -1, -1, 0 // black quad
    };
    const unsigned int p_quad_indices[][6] = {
        {0, 1, 2, 0, 2, 3},
        {4, 5, 6, 4, 6, 7},
        {8, 9, 10, 8, 10, 11}
    };
    glGenBuffers(1, &n_vertex_buffer_object);
    glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
    glBufferData(GL_ARRAY_BUFFER, sizeof(p_quad_verts_colors), p_quad_verts_colors, GL_STATIC_DRAW);
    glGenBuffers(3, p_index_buffer_object_list);
    for(int n = 0; n < 3; ++ n) {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[n]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(p_quad_indices[n]), p_quad_indices[n], GL_STATIC_DRAW);
    }

    glGenVertexArrays(2, p_vao);
    glBindVertexArray(p_vao[0]);
    {
        glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(3 * sizeof(float)));
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[0]); // red
    }
    glBindVertexArray(0);

    glBindVertexArray(p_vao[1]);
    {
        glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(3 * sizeof(float)));
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[1]); // blue
    }
    glBindVertexArray(0);

#ifdef BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[2]);
    // bind the buffer with the black quad (not inside VAO, should NOT be seen)
#endif // BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER

    // [compile shaders here]

    return true; // success
}

上記のコードは、赤、青、黒の 3 つのクワッドを含む頂点バッファーを作成します。次に、個々のクワッドを指す 3 つのインデックス バッファーを作成します。次に、2 つの VAO が作成され、設定されます。1 つには赤いクワッド インデックスが含まれ、もう 1 つには青いクワッド インデックスが含まれます。黒のクワッドはまったくレンダリングしないでください (BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER定義されていると仮定します)。

void onDraw()
{
    glClearColor(.5f, .5f, .5f, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);

    glUseProgram(n_program_object);

    static int n_last_color = -1;
    int n_color = (clock() / 2000) % 2;
    if(n_last_color != n_color) {
        printf("now drawing %s quad\n", (n_color)? "blue" : "red");
        n_last_color = n_color;
    }

    glBindVertexArray(p_vao[n_color]);
#ifdef VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[n_color]); // fixes the problem
#endif // VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

これにより、ビューポートがクリアされて灰色になり、青または赤の四角形が繰り返しレンダリングされます (どちらも印刷されます)。これはデスクトップ GPU では機能しますが、ノートブック GPU では機能しません (VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER マクロが定義されていない限り、黒いクワッドがレンダリングされます。BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER マクロを未定義にすると、青色のインデックス バッファーが最後にバインドされるため、クワッドが青色になります。しかし、そうではありません。何があっても赤いクワッドをレンダリングします。

私の見方では、これは、VAO がどのように機能するかについての私の理解における致命的な誤解、コードのバグ、またはドライバーのバグのいずれかです。

完全なソース
バイナリ (Windows、32 ビット)

4

5 に答える 5

26

しばらくして、これは実際には私の悪いことであることがわかりました。モバイル NVIDIA Quadro 4200 グラフィックス カードを搭載したラップトップは、ラップトップがパフォーマンス モードの場合でも、デフォルトですべてのアプリが Intel グラフィックスで実行されるように設定されました。アプリケーションが OpenGL からより強力な GPU を使用する方法がなかったので、なぜ誰かがそれをしたいのかわかりません (明示的なデバイス選択があるため、OpenCL に使用することはまだ可能でした。 DirectX - 一部のゲームがスムーズに動作する理由はこれで説明できます)。

それにもかかわらず、説明されているエラーのある動作は、Intel ドライバーの単なるバグであり、それだけです。Intel ドライバーは ELEMENT_ARRAY_BUFFER_BINDING を保存しません。そこには。

上記を知らずに良い回答をする方法がなかったので、質問をしてしまい、誠に申し訳ありません。

于 2012-06-29T12:37:50.297 に答える
19
于 2012-02-06T09:06:11.510 に答える
0

これの原因として考えられるのは、Intel アダプタが OpenGL 3.3 コンテキストを提供できず、代わりに 2.1 などにデフォルト設定されていることです。他の人が指摘したように、以前のバージョンの OpenGL では、要素配列のバッファー状態は VAO の一部ではありませんでした。

于 2012-06-27T09:45:59.207 に答える
-1

ELEMENTバッファーがキャッシュされていないことが想像できます。もしあなたがそうするなら:

glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));

それは次のように言っているようなものです:

gBoundBuffer_GL_ARRAY_BUFFER=n_vertex_buffer_object;
currentVAO->enable|=(1<<0);
currentVAO->vertexBuffer=IndexToPointer(gBoundBuffer_GL_ARRAY_BUFFER);

つまり、glBindBuffer()の値を設定するだけで何もしませんGL_ARRAY_BUFFERglVertexAttribPointer()VAO を変更する場所です。

だからあなたがするとき:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[0]);
glBindVertexArray(0);

あなたは本当にそうします:

gBoundBuffer_GL_ELEMENT_ARRAY_BUFFER=p_index_buffer_object_list[0];
currentVAO=0;

GL_ELEMENT_ARRAY_BUFFERバインディングが何もしていないことが理にかなっている場合。ただし、実際にVAOに作用するglVertexAttribPointer()要素のようなバリアント( など)があるかどうかはわかりません。glElementPointer()

于 2013-09-23T09:55:15.057 に答える