3

すべてのモデル データに対して 1 つの VAO と 2 つの VBO を使用する OpenGL コードがあります。1 つ目は位置や法線などの標準の頂点属性用で、2 つ目はモデル マトリックス用です。インスタンス化された描画を使用しているため、モデル マトリックスをインスタンス化された配列 (基本的には頂点属性) としてロードします。

まず、標準の頂点属性を VBO にロードし、glVertexAttribPointer. 次に、モデル マトリックスを別の VBO に読み込みます。glVertexAttribPointerここで、描画ループを呼び出す必要があります。どうにかしてこれを防ぐことはできますか?

コードは次のようになります。

// vertex data of all models in one array
GLfloat myvertexdata[myvertexdatasize];

// matrix data of all models in one array
// (one model can have multiple matrices)
GLfloat mymatrixdata[mymatrixsize];

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, myvertexdatasize*sizeof(GLfloat), myvertexdata, GL_STATIC_DRAW);

glVertexAttribPointer(
          glGetAttribLocation(myprogram, "position"),
          3,
          GL_FLOAT,
          GL_FALSE,
          24,
          (GLvoid*)0
);
glEnableVertexAttribArray(glGetAttribLocation(myprogram, "position"));
glVertexAttribPointer(
          glGetAttribLocation(myprogram, "normal"),
          3,
          GL_FLOAT,
          GL_FALSE,
          24,
          (GLvoid*)12
);
glEnableVertexAttribArray(glGetAttribLocation(myprogram, "normal"));

GLuint matrixbuffer;
glGenBuffers(1, &matrixbuffer);
glBindBuffer(GL_ARRAY_BUFFER, matrixbuffer);
glBufferData(GL_ARRAY_BUFFER, mymatrixsize*sizeof(GLfloat), mymatrixdata, GL_STATIC_DRAW);

glUseProgram(myprogram);


draw loop:
    int vertices_offset = 0;
    int matrices_offset = 0;
    for each model i:
        GLuint loc = glGetAttribLocation(myprogram, "model_matrix_column_1");
        GLsizei matrixbytes = 4*4*sizeof(GLfloat);
        GLsizei columnbytes = 4*sizeof(GLfloat);
        glVertexAttribPointer(
              loc, 
              4, 
              GL_FLOAT, 
              GL_FALSE, 
              matrixbytes,
              (GLvoid*) (matrices_offset*matrixbytes + 0*columnbytes)
        );
        glEnableVertexAttribArray(loc);
        glVertexAttribDivisor(loc, 1); // matrices are in instanced array
        // do this for the other 3 columns too...

        glDrawArraysInstanced(GL_TRIANGLES, vertices_offset, models[i]->num_vertices(), models[i]->num_instances());

        vertices_offset += models[i]->num_vertices();
        matrices_offset += models[i]->num_matrices();

頂点データと行列を 1 つの VBO に格納するアプローチを考えました。問題は、ストライドを正しく設定する方法です。解決策を思いつきませんでした。

どんな助けでも大歓迎です。

4

1 に答える 1

4

ベース インスタンス レンダリング(GL 4.2 またはARB_base_instanceが必要) にアクセスできる場合は、これを行うことができます。インスタンス化された属性のものを、インスタンス化されていない属性のものとともにセットアップに入れます。

GLuint loc = glGetAttribLocation(myprogram, "model_matrix_column_1");

for(int count = 0; count < 4; ++count, ++loc)
{
    GLsizei matrixbytes = 4*4*sizeof(GLfloat);
    GLsizei columnbytes = 4*sizeof(GLfloat);
    glVertexAttribPointer(
          loc, 
          4, 
          GL_FLOAT, 
          GL_FALSE, 
          matrixbytes,
          (GLvoid*) (count*columnbytes)
    );
    glEnableVertexAttribArray(loc);
    glVertexAttribDivisor(loc, 1); // matrices are in instanced array
}

次に、これらのモデルをレンダリングする準備ができたら、VAO をバインドするだけです。ドローコールは次のようになります。

glDrawArraysInstancedBaseInstance​(GL_TRIANGLES, vertices_offset, models[i]->num_vertices(), models[i]->num_instances(), matrix_offset);

この機能は驚くほど広く利用可能で、GL 4.x より前のハードウェアでも使用できます (最近のドライバーがインストールされている限り)。

ただし、基本インスタンスのレンダリングがなければ、何もできません。レンダリングするインスタンスの新しいセットごとにインスタンス ポインターを調整する必要があります。実際、これがベース インスタンス レンダリングが存在する理由です。

于 2016-05-29T13:13:16.313 に答える