Несколько чертежей объектов (OpenGL)

Проблема в том, что я не могу понять, как правильно рисовать два объекта, потому что мой другой объект не рисуется.

Здесь главный код:

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" перезаписывает его значения, но как мне это понять?

Ответ 1

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

Это не то, как работает графический конвейер. Вы не можете рисовать два объекта одновременно. Только последняя запись в gl_Position будет эффективной, и ваш первый объект будет полностью проигнорирован. В самом базовом варианте вы хотите нарисовать два полностью независимых объекта, и вам понадобятся два вызова для рисования - как вы делаете в своем коде.

Однако при этом вам не нужны два разных атрибута вершины. Ваш шейдер просто обрабатывает вершины, которые в вашем случае имеют verexPosition_modelspace атрибут 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, но не устанавливаете для него указатель! Вы должны повторно указать указатель для атрибута 0, чтобы указать на вашу вторую модель.

glDrawArrays(GL_TRIANGLES, 0, 4*3);

Теперь вы рисуете с включенным атрибутом 0 и 2. Атрибут 0 будет содержать данные, которые вы хотите, но шейдер игнорирует. Атрибут 2 просто указывает куда-то, и вы получаете неопределенное поведение - оно может просто аварийно завершиться, но может также отображать странные вещи или вообще ничего.

Чтобы заставить это работать, просто полностью удалите vertexPosition_modelspace2 из шейдера. Используйте только одну матрицу MVP также. При рисовании любого объекта вы должны:

  1. Установите унифицированную матрицу MVP для объекта
  2. Установить указатель атрибута для атрибута 0
  3. Включите массив атрибутов для атрибута 0 (или убедитесь, что он уже включен)
  4. Выполнить розыгрыш

Вы можете сделать это с любым количеством объектов.