A seguir, apresentamos os passsos de implementação e um exemplo completo de código utilizando GLAD e GLFW.
Passos de Implementação
- 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.
- Criação do array de texturas:
- Utilizar
glTexImage3Dpara 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.
- Utilizar
- Carregamento de dados de textura:
- Utilizar
stb_image.hpara carregar dados de imagem. - Copiar os dados de diferentes imagens para camadas distintas do array de texturas.
- Utilizar
- Código do shader:
- Utilizar
sampler2DArrayno shader de fragmento para acessar o array de texturas. - Selecionar a textura específica baseada no índice da camada.
- Utilizar
- 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.