Introducció

En aquest tema, aprendrem sobre les textures i com utilitzar-les per millorar la qualitat visual dels nostres objectes renderitzats en OpenGL. Les textures són imatges aplicades a superfícies geomètriques per donar-los més detall i realisme.

Conceptes Clau

  1. Textures: Imatges que es poden aplicar a superfícies geomètriques.
  2. Mapeig de Textures: El procés d'assignar coordenades de textura a vèrtexs d'un objecte.
  3. Coordenades de Textura: Coordenades (u, v) que determinen com es mapeja la textura sobre la superfície.

Passos per Utilitzar Textures en OpenGL

  1. Carregar la Imatge de la Textura

Primer, necessitem carregar la imatge de la textura des d'un fitxer. Podem utilitzar llibreries com stb_image.h per facilitar aquesta tasca.

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

// Carregar la imatge de la textura
int width, height, nrChannels;
unsigned char *data = stbi_load("path/to/your/texture.jpg", &width, &height, &nrChannels, 0);
if (!data) {
    std::cerr << "Failed to load texture" << std::endl;
}

  1. Crear i Configurar la Textura en OpenGL

Després de carregar la imatge, hem de crear una textura en OpenGL i configurar els seus paràmetres.

unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

// Configurar els paràmetres de la textura
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// Assignar la imatge a la textura
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);

// Alliberar la memòria de la imatge carregada
stbi_image_free(data);

  1. Assignar Coordenades de Textura als Vèrtexs

Hem d'assignar coordenades de textura als vèrtexs del nostre objecte. Les coordenades de textura (u, v) van de 0.0 a 1.0.

float vertices[] = {
    // posicions        // colors         // coordenades de textura
    0.5f,  0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  1.0f, 1.0f, // superior dret
    0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  1.0f, 0.0f, // inferior dret
   -0.5f, -0.5f, 0.0f,  0.0f, 0.0f, 1.0f,  0.0f, 0.0f, // inferior esquerre
   -0.5f,  0.5f, 0.0f,  1.0f, 1.0f, 0.0f,  0.0f, 1.0f  // superior esquerre
};

  1. Modificar els Shaders per Utilitzar Textures

Hem de modificar els nostres shaders per utilitzar les textures. Això implica afegir un sampler2D al fragment shader i utilitzar la funció texture per obtenir el color de la textura.

Vertex Shader:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

out vec3 ourColor;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    ourColor = aColor;
    TexCoord = aTexCoord;
}

Fragment Shader:

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

uniform sampler2D ourTexture;

void main()
{
    FragColor = texture(ourTexture, TexCoord);
}

  1. Renderitzar l'Objecte amb la Textura

Finalment, hem de lligar la textura abans de dibuixar l'objecte.

// Lligar la textura
glBindTexture(GL_TEXTURE_2D, texture);

// Dibuixar l'objecte
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

Exercici Pràctic

Exercici 1: Aplicar una Textura a un Quadrat

  1. Carrega una imatge de textura des d'un fitxer.
  2. Crea una textura en OpenGL i configura els seus paràmetres.
  3. Assigna coordenades de textura als vèrtexs d'un quadrat.
  4. Modifica els shaders per utilitzar la textura.
  5. Renderitza el quadrat amb la textura aplicada.

Solució

// Incloure les llibreries necessàries
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>
#include <iostream>

// Funcions de callback i inicialització
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

// Variables globals
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main()
{
    // Inicialitzar GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Crear la finestra
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // Inicialitzar GLAD
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // Compilar i enllaçar els shaders (codi no mostrat per brevetat)

    // Configurar els vèrtexs i els buffers
    float vertices[] = {
        // posicions        // colors         // coordenades de textura
        0.5f,  0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  1.0f, 1.0f, // superior dret
        0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  1.0f, 0.0f, // inferior dret
       -0.5f, -0.5f, 0.0f,  0.0f, 0.0f, 1.0f,  0.0f, 0.0f, // inferior esquerre
       -0.5f,  0.5f, 0.0f,  1.0f, 1.0f, 0.0f,  0.0f, 1.0f  // superior esquerre
    };
    unsigned int indices[] = {
        0, 1, 3,
        1, 2, 3
    };

    unsigned int VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

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

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

    // Posicions
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // Colors
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // Coordenades de textura
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    // Carregar i crear la textura
    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    // Configurar els paràmetres de la textura
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // Carregar la imatge de la textura
    int width, height, nrChannels;
    unsigned char *data = stbi_load("path/to/your/texture.jpg", &width, &height, &nrChannels, 0);
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);

    // Render loop
    while (!glfwWindowShouldClose(window))
    {
        // Processar la entrada
        processInput(window);

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

        // Lligar la textura
        glBindTexture(GL_TEXTURE_2D, texture);

        // Dibuixar el quadrat
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        // Intercanviar els buffers
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // Alliberar els recursos
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);

    glfwTerminate();
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

Conclusió

En aquest tema, hem après com carregar i aplicar textures a objectes en OpenGL. Hem vist com configurar els paràmetres de la textura, assignar coordenades de textura als vèrtexs i modificar els shaders per utilitzar les textures. Aquestes tècniques són fonamentals per crear escenes visuals més realistes i detallades.

En el següent tema, explorarem la il·luminació i els materials, que ens permetran afegir encara més realisme als nostres objectes renderitzats.

© Copyright 2024. Tots els drets reservats