Els sistemes de partícules són una tècnica utilitzada en gràfics per ordinador per simular fenòmens complexos com el foc, la fum, la pluja, les explosions, entre d'altres. En aquest tema, aprendrem com crear i gestionar un sistema de partícules utilitzant OpenGL.

Objectius del Tema

  • Entendre què és un sistema de partícules.
  • Aprendre a crear un sistema de partícules bàsic.
  • Implementar la física bàsica per a les partícules.
  • Renderitzar partícules utilitzant OpenGL.

Què és un Sistema de Partícules?

Un sistema de partícules és una col·lecció de petits elements gràfics (partícules) que es comporten de manera individual però que, en conjunt, creen un efecte visual complex. Cada partícula té propietats com la posició, velocitat, color, vida útil, etc.

Crear un Sistema de Partícules Bàsic

  1. Estructura de Dades per a les Partícules

Primer, definirem una estructura per a les partícules. Aquesta estructura contindrà les propietats bàsiques de cada partícula.

struct Particle {
    glm::vec3 position;
    glm::vec3 velocity;
    glm::vec4 color;
    float life;
};

  1. Inicialitzar les Partícules

Crearem una funció per inicialitzar les partícules. Aquesta funció assignarà valors inicials a les propietats de cada partícula.

void initParticle(Particle &p) {
    p.position = glm::vec3(0.0f);
    p.velocity = glm::vec3(
        (rand() % 100 - 50) / 50.0f,
        (rand() % 100 - 50) / 50.0f,
        (rand() % 100 - 50) / 50.0f
    );
    p.color = glm::vec4(1.0f);
    p.life = 1.0f;
}

  1. Actualitzar les Partícules

Crearem una funció per actualitzar les partícules. Aquesta funció actualitzarà la posició de cada partícula en funció de la seva velocitat i reduirà la seva vida útil.

void updateParticles(std::vector<Particle> &particles, float deltaTime) {
    for (auto &p : particles) {
        p.position += p.velocity * deltaTime;
        p.life -= deltaTime;
        if (p.life <= 0.0f) {
            initParticle(p);
        }
    }
}

  1. Renderitzar les Partícules

Finalment, crearem una funció per renderitzar les partícules utilitzant OpenGL.

void renderParticles(const std::vector<Particle> &particles, GLuint shaderProgram) {
    glUseProgram(shaderProgram);
    for (const auto &p : particles) {
        // Configurar les propietats de la partícula en el shader
        glUniform3fv(glGetUniformLocation(shaderProgram, "particlePosition"), 1, glm::value_ptr(p.position));
        glUniform4fv(glGetUniformLocation(shaderProgram, "particleColor"), 1, glm::value_ptr(p.color));
        
        // Renderitzar la partícula (per exemple, com un punt)
        glDrawArrays(GL_POINTS, 0, 1);
    }
}

Exemple Complet

A continuació, es mostra un exemple complet que integra totes les funcions anteriors.

#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

struct Particle {
    glm::vec3 position;
    glm::vec3 velocity;
    glm::vec4 color;
    float life;
};

void initParticle(Particle &p) {
    p.position = glm::vec3(0.0f);
    p.velocity = glm::vec3(
        (rand() % 100 - 50) / 50.0f,
        (rand() % 100 - 50) / 50.0f,
        (rand() % 100 - 50) / 50.0f
    );
    p.color = glm::vec4(1.0f);
    p.life = 1.0f;
}

void updateParticles(std::vector<Particle> &particles, float deltaTime) {
    for (auto &p : particles) {
        p.position += p.velocity * deltaTime;
        p.life -= deltaTime;
        if (p.life <= 0.0f) {
            initParticle(p);
        }
    }
}

void renderParticles(const std::vector<Particle> &particles, GLuint shaderProgram) {
    glUseProgram(shaderProgram);
    for (const auto &p : particles) {
        glUniform3fv(glGetUniformLocation(shaderProgram, "particlePosition"), 1, glm::value_ptr(p.position));
        glUniform4fv(glGetUniformLocation(shaderProgram, "particleColor"), 1, glm::value_ptr(p.color));
        glDrawArrays(GL_POINTS, 0, 1);
    }
}

int main() {
    // Inicialitzar GLFW i GLEW, crear una finestra, etc.
    // ...

    GLuint shaderProgram = // Compilar i enllaçar el shader program
    // ...

    std::vector<Particle> particles(1000);
    for (auto &p : particles) {
        initParticle(p);
    }

    while (!glfwWindowShouldClose(window)) {
        float deltaTime = // Calcular el temps transcorregut
        // ...

        updateParticles(particles, deltaTime);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        renderParticles(particles, shaderProgram);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

Exercicis Pràctics

  1. Afegir Gravetat: Modifica el sistema de partícules per afegir un efecte de gravetat que faci que les partícules caiguin cap avall amb el temps.
  2. Canvi de Color: Fes que les partícules canviïn de color a mesura que la seva vida útil disminueix.
  3. Texturització de Partícules: Utilitza textures per a les partícules en lloc de punts simples.

Solucions

  1. Afegir Gravetat:
void updateParticles(std::vector<Particle> &particles, float deltaTime) {
    glm::vec3 gravity(0.0f, -9.81f, 0.0f);
    for (auto &p : particles) {
        p.velocity += gravity * deltaTime;
        p.position += p.velocity * deltaTime;
        p.life -= deltaTime;
        if (p.life <= 0.0f) {
            initParticle(p);
        }
    }
}
  1. Canvi de Color:
void updateParticles(std::vector<Particle> &particles, float deltaTime) {
    for (auto &p : particles) {
        p.position += p.velocity * deltaTime;
        p.life -= deltaTime;
        p.color = glm::vec4(1.0f, p.life, p.life, 1.0f); // Canvi de color
        if (p.life <= 0.0f) {
            initParticle(p);
        }
    }
}
  1. Texturització de Partícules:
void renderParticles(const std::vector<Particle> &particles, GLuint shaderProgram, GLuint texture) {
    glUseProgram(shaderProgram);
    glBindTexture(GL_TEXTURE_2D, texture);
    for (const auto &p : particles) {
        glUniform3fv(glGetUniformLocation(shaderProgram, "particlePosition"), 1, glm::value_ptr(p.position));
        glUniform4fv(glGetUniformLocation(shaderProgram, "particleColor"), 1, glm::value_ptr(p.color));
        glDrawArrays(GL_POINTS, 0, 1);
    }
    glBindTexture(GL_TEXTURE_2D, 0);
}

Conclusió

En aquest tema, hem après a crear un sistema de partícules bàsic utilitzant OpenGL. Hem vist com inicialitzar, actualitzar i renderitzar partícules, així com algunes millores i exercicis pràctics per aprofundir en el tema. Els sistemes de partícules són una eina poderosa per crear efectes visuals realistes i dinàmics en aplicacions gràfiques.

© Copyright 2024. Tots els drets reservats