144 lines
4.5 KiB
C++
144 lines
4.5 KiB
C++
#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, glm::mat4 modelSrc, 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), sourcePosition + particle.randomPointOnCircle);
|
||
model = model * modelSrc;
|
||
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);
|
||
}
|
||
};
|
||
|
||
|
||
|