2016-05-29 2 views
2

すべてのモデルデータと2つのVBOに1つのVAOを使用するOpenGLコードがあります。最初のものは、位置と法線のような標準的な頂点属性、モデル行列の2番目の属性です。私はインスタンス化された描画を使用しているので、モデル行列をインスタンス化された配列(基本的に頂点属性です)として読み込みます。インスタンス化された配列を使用しているときにglVertexAttribPointer呼び出しを最小限に抑える方法は?

最初に標準頂点属性を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で頂点データや行列を格納するアプローチを考えました。問題は、ストライドを正しく設定する方法です。私は解決策を考え出すことができませんでした。

ご協力いただければ幸いです。

答えて

3

base-instance rendering(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のハードウェア上で、surprisingly widely availableです。

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

+0

場所は常に後続番号ですか? – mak

+0

@mak:あなたはコードのすべてを投稿していないので、あなたの行列属性が実際には完全に受け入れられる 'mat4'だと仮定しました。そうであれば、4つの場所が順番に割り当てられます(https://www.opengl.org/wiki/Vertex_Attribute)。実際には、これらの場所をまったく取得するべきではありません。それらをシェーダで直接指定する必要があります。 –

+0

場所を1回だけ取り出すときに場所を取得すると何が問題になりますか? – mak

関連する問題