grafika_komputerowa/grk/project/ParticleSystem.h
2024-01-30 21:15:07 +01:00

143 lines
4.4 KiB
C++
Raw Permalink Blame History

#pragma once
#include "glew.h"
#include <GLFW/glfw3.h>
#include "glm.hpp"
#include <list>
#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<Particle> 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 <float> (rand()) / static_cast <float> (RAND_MAX/sourceRadius);
float radians = static_cast <float> (rand()) / static_cast <float> (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<68>k<EFBFBD>w tr<74>jk<6A>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);
}
};