web-dev-qa-db-ja.com

複数のオブジェクトの描画(OpenGL)

問題は、別のオブジェクトが描画されていないため、2つのオブジェクトを適切に描画する方法を理解できないことです。

ここにメインコードがあります:

GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint VertexArrayID2;
glGenVertexArrays(1, &VertexArrayID2);
glBindVertexArray(VertexArrayID2);

GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" );

GLuint MatrixID = glGetUniformLocation(programID, "MVP");
GLuint MatrixID2 = glGetUniformLocation(programID, "MVP2");

glm::mat4 Projection = glm::perspective(45.0f, 5.0f / 4.0f, 0.1f, 100.0f);
glm::mat4 View       = glm::lookAt(
    glm::vec3(4*2,3*2,8*2),
    glm::vec3(0,0,0),
    glm::vec3(0,1,0)
);
glm::mat4 Model      = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
glm::mat4 MVP        = Projection * View * Model;

glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);

glm::mat4 Model2      = glm::translate(glm::mat4(1.0f), glm::vec3(-5.0f, 0.0f, 0.0f));
glm::mat4 MVP2        = Projection * View * Model2;

glUniformMatrix4fv(MatrixID2, 1, GL_FALSE, &MVP2[0][0]);

static const GLfloat g_vertex_buffer_data[] = {
    -1.0f,-1.0f,-1.0f,
    -1.0f,-1.0f, 1.0f,
             (plenty of floats) 
     1.0f,-1.0f, 1.0f
};

static const GLfloat g_vertex_buffer_data2[] = { 
    -1.0f, -1.0f, 3.0f,
     (plenty of floats)
     0.0f,  1.0f, 2.0f,
};


GLuint vertexbuffer; 
glGenBuffers(1, &vertexbuffer); 
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); 
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

GLuint vertexbuffer2;
glGenBuffers(1, &vertexbuffer2);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data2), g_vertex_buffer_data2, GL_STATIC_DRAW);

do{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(programID);

    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
    glUniformMatrix4fv(MatrixID2, 1, GL_FALSE, &MVP2[0][0]);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);

    glDrawArrays(GL_TRIANGLES, 0, 12*3);        

    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
    glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,0,(void*)0);

    glDrawArrays(GL_TRIANGLES, 0, 4*3);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(2);

    glfwSwapBuffers(window);
    glfwPollEvents();

  }

そしてシェーダー:

layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 2) in vec3 vertexPosition_modelspace2;

uniform mat4 MVP;
uniform mat4 MVP2;

void main(){

gl_Position =  MVP * vec4(vertexPosition_modelspace,1);
gl_Position =  MVP2 * vec4(vertexPosition_modelspace2,1);
}

最後のオブジェクトのみが描画されていることに気付いたので、問題は「gl_Position」がその値を上書きすることですが、どのようにそれを理解する必要がありますか?

15
RevanReborn
gl_Position =  MVP * vec4(vertexPosition_modelspace,1);
gl_Position =  MVP2 * vec4(vertexPosition_modelspace2,1);

それはグラフィックスパイプラインの動作方法ではありません。 できない同時に2つのオブジェクトを描画します。 gl_Positionへの最後の書き込みだけが有効になり、最初のオブジェクトは完全に無視されます。最も基本的なバリアントでは、2つの完全に独立したオブジェクトを描画する必要があり、コードで行うように、2つの描画呼び出しが必要になります。

ただし、その場合、2つの異なる頂点属性は必要ありません。シェーダーは頂点を処理するだけです。頂点には、verexPosition_modelspace属性しかありません。したがって、描画するすべてのオブジェクトにその属性を使用できます。属性が同じことを意味する場合は、オブジェクトごとに異なる属性を使用しても意味がありません。

描画コードを見てみましょう:

glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);

ここでは、最初のバッファーの頂点データを指すように頂点属性0を設定し、属性配列を有効にします。したがって、データはvertexPosition_modelspaceのソースとして使用されません。

glDrawArrays(GL_TRIANGLES, 0, 12*3);        

次に、オブジェクトを描画します。ただし、すでに説明したように、実際のシェーダーは実際にvertexPosition_modelspace2のみを使用します。これは、ポインターを設定していないか、配列を有効にしていないためです。配列が無効になっているため、GLはすべての頂点に対して属性2の現在の値を使用します。したがって、三角形の場合、すべての点が同じである三角形を作成します-表面積が0であり、属性2の現在の実際の値に関係なく、とにかく見えません。

glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);

ここで奇妙なことを行います。属性2の配列を有効にしますが、そのためのポインターを設定しないでください。 2番目のモデルを指すように、属性0のポインターを再指定する必要があります。

glDrawArrays(GL_TRIANGLES, 0, 4*3);

次に、属性0と2の両方を有効にして描画します。属性0には必要なデータが含まれますが、シェーダーでは無視されます。属性2はどこかを指しているだけであり、定義されていない動作が発生します-クラッシュするだけかもしれませんが、奇妙なものを表示したり、まったく表示しないこともあります。

これを機能させるには、シェーダーからvertexPosition_modelspace2を完全に削除します。 MVP行列も1つだけ使用します。オブジェクトを描画するときは、次のことを行う必要があります。

  1. オブジェクトのMVP均一行列を設定します
  2. 属性0の属性ポインターを設定する
  3. 属性0の属性配列を有効にします(または既に有効になっていることを確認します)
  4. ドローコールを発行する

これは、必要な数のオブジェクトで実行できます。

15
derhass