Как отобразить 2 или более объектов в openGL (матрицы и шейдеры модели - представления - проекции)

все в порядке, когда я хочу нарисовать один объект,например куб. Я создаю вершины для куба, я создаю буфер, я создаю матрицу MVP и отправляю ее шейдеру, и она хорошо работает.

а, что делать, когда я хочу нарисовать 2 или более объектов, например, куб и треугольник? Я считаю, что матрицы представления и проекции должны быть одинаковыми как для треугольника, так и для куба, мне нужна только другая матрица модели, верно? Это значит, что у меня будет два Мвпс?

//Example (using GLM):

glm::mat4 MVPC = Projection * View * ModelCube; 
glm::mat4 MVPT = Projection * View * ModelTriangle; 

Так что мне теперь делать с этими двумя? Это вершинный шейдер, который хорошо работает для cube

//vertex shader
#version 330 core

layout(location = 0) in vec3 verticesCube;

uniform mat4 MVPC;

void main(){

     gl_Position =  MVPC * vec4(verticesCube,1);

}

и что мне делать с MVPT (треугольником) в шейдере, я пытался возиться с разными вещами, но я не могу заставить его работать, я не могу одновременно отображать куб и треугольник.

4 ответов


путаница возникает из-за того, что шейдер управляет сразу несколькими массивами вершин, когда его следует рассматривать как универсальную сущность. Массив вершин передается шейдеру,затем объект рисуется. И процесс повторяется.

например, допустим, мы назначаем переменную matrixID Единой MVP:

    // get handle for our "MVP" uniform
    GLuint matrixID = glGetUniformLocation(programID, "MVP");

когда мы будем готовы нарисовать объект, мы установим matrixID к объекту MVP:

    glUniformMatrix4fv(matrixID, 1, GL_FALSE, &cubeMVP[0][0]);

затем свяжите буфер вершин, установите указатель атрибута и нарисуйте его:

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVerteciesBuffer);

    glVertexAttribPointer(
            0,      // shader layout location
            3,
            GL_FLOAT,
            GL_FALSE,
            0,
            (void *)0
    );
    glDrawArrays(GL_TRIANGLES, 0, 12*3);    // draw cube

теперь перейдем к треугольнику и повторим процесс-set matrixID к MVP объекта, свяжите буфер вершин, установите указатель атрибута и нарисуйте его:

    glUniformMatrix4fv(matrixID, 1, GL_FALSE, &triMVP[0][0]);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, triangleVerteciesBuffer);

    glVertexAttribPointer(
            0,      // shader layout location
            3,
            GL_FLOAT,
            GL_FALSE,
            0,
            (void *)0
    );
    glDrawArrays(GL_TRIANGLES, 0, 3);   // draw triangle

соответствующий код вершинного шейдера:

#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertecies_modelspace;

uniform mat4 MVP;

void main(){
    gl_Position = MVP * vec4(vertecies_modelspace, 1);
}

OpenGL не является графиком сцены. Он рисует вещи в соответствии с текущим состоянием, а затем забывает об этом.

поэтому, если вы хотите нарисовать разные геометрии, с разными преобразованиями просто установите соответствующую матрицу преобразования (равномерную), нарисуйте объект и повторите это для каждого объекта, который вы хотите нарисовать. После того, как геометрия была нарисована, следующие операции не будут иметь никакого дальнейшего влияния на нее, кроме как это может быть перерасход.


альтернативой, которая также может работать, было бы выполнение вычисления матрицы "ModelViewProjection" в шейдере вершин. Вы можете сделать это, сделав uniform модель, посмотреть и проекция матричные переменные в шейдере вершин. Потом можно глобально calcluate посмотреть и проекция матрицы и отправьте их в шейдер. Затем вы можете просто вычислить матрицу модели для вашего Куба и треугольника (или любых объектов, которые вы необходимо выполнить рендеринг) индивидуально и отправить эти матрицы моделей в шейдер.


просмотр и вычисления матрицы проекции; это может быть в отдельном классе "камера":

glm::mat4 viewMatrix = glm::lookAt(
  glm::vec3(0, -5, 0), // camera location in world
  glm::vec3(0, 0, 0), // point camera is looking at
  glm::vec3(0, 1, 0) // orientation of camera, change 1 to -1 to flip camera upside down
);

glm::mat4 projectionMatrix = glm::perspective(35.0f, displayWidth / displayHeight, 0.1f, 100.0f);

// send view and projection matrices to the shader
glUseProgram(shaderProgram);
GLint viewMatrixId = glGetUniformLocation(shaderProgram, "view");
GLint projectionMatrixId = glGetUniformLocation(shaderProgram, "projection");

glUniformMatrix4fv(viewMatrixId, 1, GL_FALSE, &viewMatrix[0][0]);
            glUniformMatrix4fv(projectionMatrixId, 1, GL_FALSE, &projectionMatrix[0][0]);
glUseProgram(0);

расчет матрицы модели; этот код может идти в отдельном классе, и вы можете создать его экземпляр для каждого объекта, который вы хотите отобразить:

// this can go after where you initialize your cube or triangle vertex information
glUseProgram(shaderProgram);
modelMatrixId = glGetUniformLocation(shaderProgram, "model"); //modelMatrixId can be a global GLint
glUniformMatrix4fv(modelMatrixId, 1, GL_FALSE, &modelMatrix[0][0]); //modelMatrix can be a global glm::mat4
glUseProgram(0);

//use this for every render frame
glUseProgram(shaderProgram);
glUniformMatrix4fv(modelMatrixId, 1, GL_FALSE, &modelMatrix[0][0]);

// code to bind vertices and draw you objects goes here

glUseProgram(0);

новый вершинный шейдер:

//vertex shader
#version 330 core

layout(location = 0) in vec3 vertices;

uniform mat4 model, view, projection;

void main(){

     gl_Position =  projection * view * model * vec4(vertices, 1.0);

}

есть два массива вершин. Скажем, array1 для куба, array2 для круга. Создайте 2 vaos и 2 vbos. vao1 и vbo1 для куба. vao2 и vbo2 для круга.

Bind vao1, bind vbo1, заполнить буфер vbo1 с array1. glUserProgram (программа), которая является программой для шейдеров, настройте vertexattripointer.

вызов glDrawArray()

сделайте то же самое для других ВАО и vbo.