#include "particlesystem.h" #include particlesystem::particlesystem() { } std::pair sample_complex_gaussian(){ double uniform_1 = (double)rand() / (RAND_MAX); double uniform_2 = (double)rand() / (RAND_MAX); // set a lower bound on zero to avoid undefined log(0) if (uniform_1 == 0) { uniform_1 = 1e-10; } if (uniform_2 == 0) { uniform_2 = 1e-10; } // real and imaginary parts of the complex number double real = sqrt(-2*log(uniform_1)) * cos(2*M_PI*uniform_2); double imag = sqrt(-2*log(uniform_1)) * sin(2*M_PI*uniform_2); return std::make_pair(real, imag); } float getRandomInRange(float max, float min){ return min + static_cast (rand()) /( static_cast (RAND_MAX/(max-min))); } float getRandomY(){ return getRandomInRange(.001,.2); } Eigen::Vector3f particlesystem::getRandomInitialVel(){ std::pair r = sample_complex_gaussian(); return factor*Eigen::Vector3f(r.first, getRandomY(), r.second); } Eigen::Vector3f getInitVel(OceanSpray s){ float x = getRandomInRange(.6,4); float y = getRandomInRange(0.5, 1.5); Eigen::Vector3f v = Eigen::Vector3f(s.slope_vector[0], y, s.slope_vector[1]) + Eigen::Vector3f(x,0,0); return v*300.f; //p.vel[1] = 0.1; } void particlesystem::init(std::vector verts){ // make sure to set m_verts setVerts(verts); m_particles.reserve(4000); for (auto v : m_verts){ Particle p; p.pos = Eigen::Vector3f(v.height); p.life = getRandomInRange(.6,1); // p.vel = v.slope*factor; //p.vel = getRandomInitialVel(); p.vel = getInitVel(v); m_particles.push_back(p); } glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, m_vertices.size()*sizeof(float), m_vertices.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)0); // unbind glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); } void particlesystem::update(double deltaTime){ // add new particles for (int i=0; i= m_particles.size() - 1 || particle_index >= m_verts.size() - 1) continue; respawn_particle(m_particles[particle_index], m_verts[particle_index]); } float dt = deltaTime; // update all particles values for (Particle &p : m_particles){ p.life -= deltaTime * getRandomInRange(.1f, .9f); // if particle is still alive, update pos if (p.life >= 0.f){ float r = getRandomInRange(30, 80.f); p.vel += gravity*dt*r; p.pos += p.vel * dt; // p.vel[1] -= (p.vel.dot(p.vel) / 2 + gravity[0]) * dt; // p.pos += p.vel * dt * 10.f; } if (p.pos[1] < 0.f) p.life = 0.f; } } // finds the first instance of a particle that is dead, and returns its index so it can be replaced int particlesystem::getUnusedParticleIndex(){ // search from last used index for (int i=lastUsedIndex; ibind(); glBlendFunc(GL_SRC_ALPHA, GL_ONE); // activate texture glActiveTexture(GL_TEXTURE10); glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(glGetUniformLocation(shader->id(), "particle_texture"), 10); // manually set view and projection, for non-translating view Eigen::Matrix4f projection = m_camera.getProjection(); Eigen::Matrix4f view = m_camera.getView(); // view.col(3) = Eigen::Vector4f(0, 0, 0, 0); glUniformMatrix4fv(glGetUniformLocation(shader->id(), "view"), 1, GL_FALSE, view.data()); glUniformMatrix4fv(glGetUniformLocation(shader->id(), "projection"), 1, GL_FALSE, projection.data()); // shader->setUniform("model", model); int i = 0; for (Particle p : m_particles){ if (p.life >= 0.f){ shader->setUniform("offset", p.pos); shader->setUniform("alpha", p.life); glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, m_vertices.size()); glBindVertexArray(0); i++; } } shader->unbind(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); }