OpenGL: как я могу передать несколько текстур шейдеру с одной переменной?

#c #opengl #glsl #shader

#c #opengl #glsl #шейдер

Вопрос:

Я загрузил информацию о материале и текстуре из Obj-файла на основе этого кода (https://github.com/Bly7/OBJ-Loader ). Теперь я хочу загрузить Sponza и отобразить его. Однако существует 10 или более текстур, и даже если все они передаются шейдеру, необходимо, чтобы они соответствовали соответствующим вершинам. Глядя на результат загрузки из Obj-файла, текстуры назначаются каждой части.

Пример.

 Mesh 0 : Pillar
position0(x, y, z), position1(x, y, z), uv0(x, y) ... 
diffuse texture : tex0.png

Mesh 1 : Wall
position0(x, y, z), position1(x, y, z), uv0(x, y) ... 
diffuse texture : tex1.png
.
. 
.
  

Текстуры хранятся в виде массива, и каждая из них имеет соответствующий индекс сетки. На мой взгляд, при передаче информации о вершинах шейдеру хорошо работает, если вы делите ее на количество сеток и одновременно передаете текстуру. Однако я не уверен, верна ли эта идея, и я пробовал несколько методов, но это не работает.

Это текущий простой код.

 main.cpp :
do {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture[i]);  // texture[] : Array of textures loaded from obj file.
    glUniform1i(glGetUniformLocation(shaderID, "myTex"), 0);

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

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, texCoord);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);    

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element);
    glDrawElements(GL_TRIANGLES, element_indices.size(), GL_UNSIGNED_INT, (void*)0);

} while(glfwWindowShouldClose(window) == 0);

Fragment shader :
layout(location = 0) out vec4 out_color;
// from vertex shader
in vec2 texCoord; 

uniform sampler2D myTex;

void main() {
    out_color = texture(myTex, texCoord);
}
  

Я хочу соответствовать индексу сетки, загруженному с помощью «i» в приведенном выше коде. Пожалуйста, дайте мне знать, если моя идея неверна или есть другой способ.

Комментарии:

1. Вы должны визуализировать Mesh 0 с tex0.png помощью, Mesh 1 с tex1.png помощью и т.д. Для этого вы загружаете все текстуры и привязываете соответствующий идентификатор текстуры для соответствующей сетки, прежде чем рисовать ее буферы. Существует также возможность привязать несколько текстур к одной сетке, но ИМХО это не то, что вы собираетесь делать. Посмотрите на Learn OpenGL — Текстуры , как это делается в деталях.

2. Я бы порекомендовал вам взглянуть на Model — LearnOpenGL . На это должен быть ваш ответ.

3. @Scheff, снова посмотрев на ваши ссылки, дал мне несколько советов о том, как действовать дальше. Спасибо.

Ответ №1:

Поскольку ваша модель имеет только одну текстуру на сетку, я могу предложить этот простой код для использования:

 do {
    glActiveTexture(GL_TEXTURE0);
    glUniform1i(glGetUniformLocation(shaderID, "myTex"), 0);
    
    for (unsigned int i = 0; i < mesh_count; i  ) {
        glcall(glBindTexture(type, texture[i]));
        
        // Bind vertex and index (or element) buffer and setup vertex attribute pointers
        
        // Draw mesh
    }
} while (window_open);
  

Код очень понятен. Сначала он активирует слот текстуры 0, затем для каждой сетки он связывает текстуру, буфер вершин, индекс или буфер элементов и выполняет какую-либо подготовку для рисования сетки. Затем он выдает вызов рисования.

Обратите внимание, что это очень простой пример. Большинство моделей выглядели бы странно с этим кодом. Я бы рекомендовал этот учебник из LearnOpenGL, который объясняет это более широко, но простым способом.

Комментарии:

1. Я решил эту проблему, передав массив, содержащий индекс каждой сетки, в glDrawElements. Спасибо, что подумали вместе.