#pragma once #include "glew.h" #include #include "glm.hpp" #include #include "ext.hpp" struct Particle { public: float birthTime; glm::vec3 startPosition; glm::vec3 direction; glm::vec3 randomPointOnCircle; float getAge(float time) { return time - birthTime; } }; class ParticleSystem { private: std::list particles; GLuint VBO; GLuint VAO; GLfloat vertices[9]; float lastGenerated = -1.f; bool shouldGenerateNewParticle(float time) { return lastGenerated == -1.f || time - lastGenerated > generationInterval; } glm::vec3 generateRandomPointOnCircle() { float distanceFromCenter = static_cast (rand()) / static_cast (RAND_MAX/sourceRadius); float radians = static_cast (rand()) / static_cast (RAND_MAX / 6.28f); glm::vec3 referenceVector(0.0f, 1.0f, 0.0f); glm::vec3 output = glm::normalize(glm::cross(sourceDirection, referenceVector)) * distanceFromCenter; glm::mat4 rotationMatrix = glm::rotate(glm::mat4(1.0f), radians, sourceDirection); output = glm::vec3(rotationMatrix * glm::vec4(output, 1.0f)); return output; } void generateNewParticle(float time) { Particle newParticle; newParticle.birthTime = time; newParticle.startPosition = sourcePosition; newParticle.randomPointOnCircle = generateRandomPointOnCircle(); newParticle.direction = sourceDirection; particles.push_back(newParticle); lastGenerated = time; } void deleteOld(float time) { auto it = particles.begin(); while (it != particles.end()) { if ((*it).getAge(time) > lifetime) { it = particles.erase(it); } else { ++it; } } } glm::vec3 calculateParticleColor(float age) { float rate = glm::clamp(age / lifetime, 0.f, 1.f); glm::vec3 mixedColor = (1.0f - rate) * startColor + rate * endColor; return mixedColor; } public: glm::vec3 sourcePosition; float sourceRadius = 0.02f; glm::vec3 sourceDirection = glm::vec3(1.f, 0.f, 0.f); float generationInterval = 0.0025f; float lifetime = 0.5f; float speed = 100.f; glm::vec3 startColor = glm::vec3(1.f, 0.f, 0.f); glm::vec3 endColor = glm::vec3(1.f, 1.f, 0.f); ParticleSystem() { // Inicjalizacja wierzchołków trójkąta w 3D vertices[0] = -0.5f; vertices[1] = -0.5f; vertices[2] = 0.0f; vertices[3] = 0.5f; vertices[4] = -0.5f; vertices[5] = 0.0f; vertices[6] = 0.0f; vertices[7] = 0.5f; vertices[8] = 0.0f; glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0); glEnableVertexAttribArray(0); glBindVertexArray(0); } void drawParticles(GLuint program, glm::mat4 view, glm::mat4 projection, float time) { if (shouldGenerateNewParticle(time)) { generateNewParticle(time); } deleteOld(time); glUseProgram(program); GLuint modelLoc = glGetUniformLocation(program, "model"); GLuint viewLoc = glGetUniformLocation(program, "view"); GLuint projectionLoc = glGetUniformLocation(program, "projection"); GLuint colorLoc = glGetUniformLocation(program, "color"); int i = 0; for (auto particle : particles) { glm::vec3 color = calculateParticleColor(particle.getAge(time)); glUniform3f(colorLoc, color.x, color.y, color.z); glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); glm::mat4 model = glm::translate(glm::mat4(1.0f), sourcePosition + particle.randomPointOnCircle); model = glm::scale(model, glm::vec3(0.005f, 0.005f, 0.005f)); model = glm::translate(model, particle.direction * speed * (time - particle.birthTime)); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 3); i++; } glBindVertexArray(0); } };