Técnicas de Arrays de Texturas no OpenGL

A seguir, apresentamos os passsos de implementação e um exemplo completo de código utilizando GLAD e GLFW.

Passos de Implementação

  1. Configuração do ambiente com GLAD e GLFW:
    • Criar uma janela com GLFW e inicializar o contexto OpenGL.
    • Carregar as funções OpenGL utilizando GLAD.
  2. Criação do array de texturas:
    • Utilizar glTexImage3D para criar um array de texturas.
    • O array de texturas pode ser visualizado como uma textura 3D composta por múltiplas texturas 2D, onde acessamos as "camadas" sem envolver coordenadas 3D reais.
  3. Carregamento de dados de textura:
    • Utilizar stb_image.h para carregar dados de imagem.
    • Copiar os dados de diferentes imagens para camadas distintas do array de texturas.
  4. Código do shader:
    • Utilizar sampler2DArray no shader de fragmento para acessar o array de texturas.
    • Selecionar a textura específica baseada no índice da camada.
  5. Renderização da cena:
    • Realizar o binding e renderização utilizando o array de texturas.

Exemplo de Código Completo

A seguir, apresentamos um exemplo completo demonstrando como utilizar arrays de texturas no OpenGL.

1. Arquivo Principal (principal.cpp)

#include <glad>
#include <glfw>
#include <stb_image.h>
#include <iostream>

// Dimensões da janela
const unsigned int LARGURA = 800;
const unsigned int ALTURA = 600;

// Dados dos vértices
float dadosVertices[] = {
    // posições      // coordenadas de textura  // camada de textura
    -0.5f, -0.5f, 0.0f,  0.0f, 0.0f,       0.0f,  // canto inferior esquerdo
     0.5f, -0.5f, 0.0f,  1.0f, 0.0f,       1.0f,  // canto inferior direito
     0.5f,  0.5f, 0.0f,  1.0f, 1.0f,       2.0f,  // canto superior direito
    -0.5f,  0.5f, 0.0f,  0.0f, 1.0f,       0.0f   // canto superior esquerdo
};
unsigned int indices[] = {
    0, 1, 2,
    2, 3, 0
};

// Callback para redimensionamento da janela
void callbackRedimensionamento(GLFWwindow* janela, int largura, int altura) {
    glViewport(0, 0, largura, altura);
}

// Processamento de entrada do usuário
void processarEntrada(GLFWwindow* janela) {
    if (glfwGetKey(janela, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(janela, true);
}

// Função para carregar array de texturas
unsigned int carregarArrayTexturas(const char* caminhos[], int numeroCamadas) {
    unsigned int idTextura;
    glGenTextures(1, &idTextura);
    glBindTexture(GL_TEXTURE_2D_ARRAY, idTextura);

    // Configuração dos parâmetros de textura
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // Obter dimensões e canais da textura
    int largura, altura, canais;
    stbi_set_flip_vertically_on_load(true); // Inverter imagem verticalmente

    for (int i = 0; i < numeroCamadas; ++i) {
        unsigned char* dados = stbi_load(caminhos[i], &largura, &altura, &canais, 0);
        if (dados) {
            if (i == 0) {
                // Inicializar o espaço de armazenamento do array de texturas
                glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, largura, altura, numeroCamadas, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
            }
            // Carregar a imagem atual na camada i do array de texturas
            glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, largura, altura, 1, GL_RGBA, GL_UNSIGNED_BYTE, dados);
            stbi_image_free(dados);
        } else {
            std::cout << "Falha ao carregar textura: " << caminhos[i] << std::endl;
            stbi_image_free(dados);
        }
    }

    glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
    return idTextura;
}

int main() {
    // Inicialização do GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Criação da janela
    GLFWwindow* janela = glfwCreateWindow(LARGURA, ALTURA, "Exemplo de Array de Texturas", NULL, NULL);
    if (janela == NULL) {
        std::cout << "Falha ao criar janela GLFW" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(janela);
    glfwSetFramebufferSizeCallback(janela, callbackRedimensionamento);

    // Inicialização do GLAD
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        std::cout << "Falha ao inicializar GLAD" << std::endl;
        return -1;
    }

    // Criação de VAO, VBO e EBO
    unsigned int VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(dadosVertices), dadosVertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // Atributos dos vértices
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(5 * sizeof(float)));
    glEnableVertexAttribArray(2);

    // Carregamento do array de texturas
    const char* caminhos[] = {
        "textura1.png",
        "textura2.png",
        "textura3.png"
    };
    unsigned int arrayTextura = carregarArrayTexturas(caminhos, 3);

    // Criação e compilação dos shaders
    unsigned int programaShader = glCreateProgram();
    // Certifique-se de carregar e compilar os shaders de vértice e fragmento aqui (código abaixo)

    // Loop de renderização
    while (!glfwWindowShouldClose(janela)) {
        processarEntrada(janela);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(programaShader);
        glBindTexture(GL_TEXTURE_2D_ARRAY, arrayTextura);

        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(janela);
        glfwPollEvents();
    }

    // Limpeza de recursos
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(programaShader);

    glfwTerminate();
    return 0;
}
</iostream></stb_image.h></glfw></glad>
2. Código dos Shaders
Shader de Vértice (vertice.glsl)

#version 330 core
layout (location = 0) in vec3 posicao;
layout (location = 1) in vec2 coordTextura;
layout (location = 2) in float camadaTextura;

out vec2 TexCoord;
flat out int CamadaTextura;

void main() {
    gl_Position = vec4(posicao, 1.0);
    TexCoord = coordTextura;
    CamadaTextura = int(camadaTextura);
}

Shader de Fragmento (fragmento.glsl)

#version 330 core
out vec4 CorFragmento;

in vec2 TexCoord;
flat in int CamadaTextura;

uniform sampler2DArray arrayTextura;

void main() {
    CorFragmento = texture(arrayTextura, vec3(TexCoord, CamadaTextura));
}

Dependências

  • GLFW: Para gerenciamento de janela e criação de contexto.
  • GLAD: Para carregamento de funções OpenGL.
  • stb_image.h: Para carregamento de imagens de textura.

Certifique-se de incluir o arquivo stb_image.h no seu projeto e definir STB_IMAGE_IMPLEMENTATION.


#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
</stb_image.h>

Ao executar este código, você verá um array de texturas com múltiplas camadas, capaz de acessar cada camada através de seu respectivo índice.

Tags: OpenGL texturas GLSL array de texturas GLFW

Publicado em 6-9 07:53 por Thomas