diff options
author | jjesswan <90643397+jjesswan@users.noreply.github.com> | 2024-05-10 03:41:50 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-10 03:41:50 -0400 |
commit | b4ca8b708587c540233284beae8d42ff43092580 (patch) | |
tree | 05e7902207c5d22044a76d6374dd220a073c8f69 | |
parent | 80650ec974d661652eceb08616e8659febe2140d (diff) | |
parent | 7c0cd109b098b24279fb17b9a05ab846405d169b (diff) |
Merge pull request #4 from Seb-Park/new_parti
New parti
-rw-r--r-- | .DS_Store | bin | 12292 -> 10244 bytes | |||
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | resources/shaders/particles.frag | 15 | ||||
-rw-r--r-- | resources/shaders/particles.vert | 21 | ||||
-rw-r--r-- | src/arap.h | 4 | ||||
-rwxr-xr-x | src/glwidget.cpp | 11 | ||||
-rwxr-xr-x | src/glwidget.h | 4 | ||||
-rw-r--r-- | src/ocean/ocean_alt.cpp | 17 | ||||
-rw-r--r-- | src/ocean/ocean_alt.h | 19 | ||||
-rw-r--r-- | src/particlesystem.cpp | 199 | ||||
-rw-r--r-- | src/particlesystem.h | 84 |
11 files changed, 373 insertions, 6 deletions
Binary files differ diff --git a/CMakeLists.txt b/CMakeLists.txt index b72cde6..b7bd5ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,8 @@ add_executable(${PROJECT_NAME} src/ocean/halftone.h src/ocean/halftone.cpp src/skybox.h src/skybox.cpp + + src/particlesystem.h src/particlesystem.cpp ) # GLEW: this creates its library and allows you to `#include "GL/glew.h"` @@ -131,6 +133,9 @@ qt6_add_resources(${PROJECT_NAME} "Resources" resources/shaders/caustics.vert resources/shaders/caustics.frag + + resources/shaders/particles.vert + resources/shaders/particles.frag ) # GLEW: this provides support for Windows (including 64-bit) diff --git a/resources/shaders/particles.frag b/resources/shaders/particles.frag new file mode 100644 index 0000000..99373e7 --- /dev/null +++ b/resources/shaders/particles.frag @@ -0,0 +1,15 @@ +#version 330 core +in vec2 TexCoords; +in vec4 ParticleColor; + +out vec4 fragColor; + +uniform sampler2D sprite; +uniform float alpha; + + +void main() +{ + // color = (texture(sprite, TexCoords) * ParticleColor); + fragColor = vec4(1,1,1,alpha); +} diff --git a/resources/shaders/particles.vert b/resources/shaders/particles.vert new file mode 100644 index 0000000..7b49a46 --- /dev/null +++ b/resources/shaders/particles.vert @@ -0,0 +1,21 @@ +#version 330 core +layout (location = 0) in vec2 pos; // <vec2 position, vec2 texCoords> + +out vec2 TexCoords; +out vec4 ParticleColor; + +uniform mat4 view, projection, model; +uniform vec3 offset; +uniform vec4 color; +uniform float alpha; + + +void main() +{ + float scale = 1.f;//2000.0f; + //TexCoords = vertex.zw; + ParticleColor = color; + // gl_Position = projection *view* vec4((pos * scale) + vec2(offset), 0.0, 1.0); + gl_Position = (vec4(pos.x*alpha, pos.y*alpha, 0, 1) + projection*view*vec4(vec3(offset), 1))*scale; + +} @@ -32,6 +32,9 @@ public: void move(int vertex, Eigen::Vector3f pos); void update(double seconds); + ocean_alt m_ocean; + + // ================== Students, If You Choose To Modify The Code Below, It's On You @@ -96,7 +99,6 @@ public: int m_num_iterations; const char * m_mesh_path; - ocean_alt m_ocean; double m_time = 0.00; double m_timestep = 0.3; diff --git a/src/glwidget.cpp b/src/glwidget.cpp index 6466e24..f8547a6 100755 --- a/src/glwidget.cpp +++ b/src/glwidget.cpp @@ -97,6 +97,8 @@ void GLWidget::initializeGL() m_colorShader = new Shader(":resources/shaders/color.vert", ":resources/shaders/color.frag"); m_foamShader = new Shader(":resources/shaders/foam.vert", ":resources/shaders/foam.frag"); m_skyboxShader = new Shader(":resources/shaders/skybox.vert", ":resources/shaders/skybox.frag"); + m_particleShader = new Shader(":resources/shaders/particles.vert", ":resources/shaders/particles.frag"); + m_halftone_tex = loadTextureFromFile(":resources/images/halftone.png").textureID; @@ -198,6 +200,10 @@ void GLWidget::initializeGL() m_deltaTimeProvider.start(); m_intervalTimer.start(1000 / 60); + // OCEAN SPRAY + m_arap.update(0); // important to get initial heights + m_particles.init(m_arap.m_ocean.m_heights); + } void GLWidget::paintCaustics() { @@ -458,6 +464,8 @@ void GLWidget::paintGL() m_skybox.draw(m_skyboxShader, m_camera); + m_particles.draw(m_particleShader, m_camera); + @@ -684,7 +692,10 @@ void GLWidget::tick() float deltaSeconds = m_deltaTimeProvider.restart() / 1000.f; m_arap.update(deltaSeconds); // rotate skybox + m_particles.setVerts(m_arap.m_ocean.m_heights); m_skybox.update(deltaSeconds); + m_particles.update(deltaSeconds); + // Move camera auto look = m_camera.getLook(); diff --git a/src/glwidget.h b/src/glwidget.h index 60cca66..50d6347 100755 --- a/src/glwidget.h +++ b/src/glwidget.h @@ -1,6 +1,8 @@ #pragma once #include "skybox.h" +#include "particlesystem.h" + #include <GL/glew.h> @@ -70,6 +72,7 @@ private: Shader *m_colorShader; Shader *m_foamShader; Shader *m_skyboxShader; + Shader *m_particleShader; @@ -122,4 +125,5 @@ private: int m_lastSelectedVertex = -1; skybox m_skybox; + particlesystem m_particles; }; diff --git a/src/ocean/ocean_alt.cpp b/src/ocean/ocean_alt.cpp index 7523c94..751fca5 100644 --- a/src/ocean/ocean_alt.cpp +++ b/src/ocean/ocean_alt.cpp @@ -319,6 +319,7 @@ void ocean_alt::update_ocean() // reset normals & vertices arrays for the single tile m_vertices = std::vector<Eigen::Vector3f>(N); m_normals = std::vector<Eigen::Vector3f>(N); + m_heights.clear(); for (int i = 0; i < N; i++){ Eigen::Vector2d horiz_pos = spacing*m_waveIndexConstants[i].base_horiz_pos; Eigen::Vector2d amplitude = m_current_h[i]; @@ -357,15 +358,20 @@ void ocean_alt::update_ocean() Eigen::Vector2d disp = lambda*Eigen::Vector2d(m_displacements_x[i][0], m_displacements_z[i][0]) + Eigen::Vector2d(vertex_displacement, vertex_displacement); // set corner at 0,0 for retiling + Eigen::Vector3f v = Eigen::Vector3f(horiz_pos[0] + disp[0], height, horiz_pos[1] + disp[1]); // for final vertex position, use the real number component of amplitude vector - m_vertices[i] = {horiz_pos[0] + disp[0], height, horiz_pos[1] + disp[1]}; + m_vertices[i] = v; m_normals[i] = norm.normalized();//Eigen::Vector3f(-slope[0], 1.0, -slope[1]).normalized(); //std::cout << "normal: " << m_normals[i] << std::endl Eigen::Vector2i m_n = index_1d_to_2d(i); // m_foam_constants.wavelengths[i] = 2.f* M_PI * m_slopes[i].dot(m_slopes[i]) / Lx; +// float h_0 = m_waveIndexConstants[i].h0_prime[0]; // min*.2f; +// float h_max = max*.001f; // the smaller the constant, the more foam there is +// float waveheight = (height - h_0 ) / (h_max - h_0); +// m_foam_constants.wavelengths[i] = waveheight; float h_0 = 0; // min*.2f; float h_max = max*.35f; // the smaller the constant, the more foam there is m_foam_constants.wavelengths[i] = (height - h_0 ) / (h_max - h_0); @@ -375,6 +381,15 @@ void ocean_alt::update_ocean() // std::cout << m_foam_constants.wavelengths[i] << std::endl; // } + if (m_foam_constants.wavelengths[i] >= height_threshold){ + //std::cout << "push" << std::endl; + OceanSpray s; + s.height = v; + s.slope = norm; + s.slope_vector = Eigen::Vector2f(m_slopes_x[i][0], m_slopes_z[i][0]); + //std::cout << s.slope_vector << std::endl; + m_heights.push_back(s); + } } diff --git a/src/ocean/ocean_alt.h b/src/ocean/ocean_alt.h index 9c5e4e2..7e293f9 100644 --- a/src/ocean/ocean_alt.h +++ b/src/ocean/ocean_alt.h @@ -27,6 +27,13 @@ struct FoamConstants{ std::vector<Eigen::Vector2f> texCoords; }; +struct OceanSpray{ + Eigen::Vector3f height; + Eigen::Vector3f slope; + Eigen::Vector2f slope_vector; + +}; + class ocean_alt { public: @@ -43,6 +50,8 @@ public: } std::vector<Eigen::Vector3f> m_vertices; // current displacement vector for each K + std::vector<OceanSpray> m_heights; // stores height above threshold + @@ -71,8 +80,8 @@ private: const double Lx = 512.0; const double Lz = 512.0; - const int num_rows = 256; - const int num_cols = 256; + const int num_rows = 256; + const int num_cols = 256; const int num_tiles_x = 1; const int num_tiles_z = 1; @@ -83,8 +92,8 @@ private: const double lambda = .5; // how much displacement matters const double spacing = 1.0; // spacing between grid points - const double A = 10000; // numeric constant for the Phillips spectrum - const double V = 500; // wind speed + const double A = 10000; // numeric constant for the Phillips spectrum + const double V = 100; // wind speed const double gravity = 9.81; const double L = V*V/gravity; const Eigen::Vector2d omega_wind = Eigen::Vector2d(1.0, 0.0); // wind direction, used in Phillips equation @@ -102,6 +111,8 @@ private: // FOR FOAM: FoamConstants m_foam_constants; + float height_threshold = 2.f; + float max = 0; diff --git a/src/particlesystem.cpp b/src/particlesystem.cpp new file mode 100644 index 0000000..566667f --- /dev/null +++ b/src/particlesystem.cpp @@ -0,0 +1,199 @@ +#include "particlesystem.h" +#include <iostream> + +particlesystem::particlesystem() +{ + +} + +std::pair<double,double> 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 <float> (rand()) /( static_cast <float> (RAND_MAX/(max-min))); + +} + +float getRandomY(){ + return getRandomInRange(.001,.2); +} + + +Eigen::Vector3f particlesystem::getRandomInitialVel(){ + + + std::pair<float, float> r = sample_complex_gaussian(); + return factor*Eigen::Vector3f(r.first, getRandomY(), r.second); +} + +Eigen::Vector3f getInitVel(OceanSpray s){ + float x = getRandomInRange(0,1); + float y = getRandomInRange(0.1, .9); + Eigen::Vector3f v = Eigen::Vector3f(s.slope_vector[0], y, s.slope_vector[1]) + Eigen::Vector3f(x,0,0); + return v*10.f; + //p.vel[1] = 0.1; + + +} + +void particlesystem::init(std::vector<OceanSpray> 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(.1,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, 2, GL_FLOAT, GL_FALSE, 2*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(); i++){ + int particle_index = getUnusedParticleIndex(); + if (particle_index == -1) continue; + if (particle_index >= 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, .5f); + + // if particle is still alive, update pos + if (p.life >= 0.f){ + float r = getRandomInRange(.5, 1.6f); + p.vel += gravity*dt*r; + p.pos += p.vel * dt * 10.f; +// 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; i<m_verts.size(); ++i){ + if (m_particles[i].life <= 0.f){ + lastUsedIndex = i; + return i; + } + } + + // otherwise do linear search up to last used + for (int i=0; i<lastUsedIndex; ++i){ + if (m_particles[i].life <= 0.f){ + lastUsedIndex = i; + return i; + } + } + + // if no dead ones found, don't respawn + lastUsedIndex = 0; + //std::cout << "first particle override!" << std::endl; + return -1; +} + +void particlesystem::respawn_particle(Particle &p, OceanSpray s){ + + p.pos = Eigen::Vector3f(s.height); + p.vel = getInitVel(s); + + + // reset life + p.life = 1.f; + +} + +void particlesystem::draw(Shader *shader, Camera m_camera){ + + shader->bind(); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + + // activate texture +// glActiveTexture(GL_TEXTURE10); +// glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex); +// glUniform1i(glGetUniformLocation(shader->id(), "cubeMap"), 9); // bind texture at slot 9 + + + // 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); + + +} diff --git a/src/particlesystem.h b/src/particlesystem.h new file mode 100644 index 0000000..d3b0b8f --- /dev/null +++ b/src/particlesystem.h @@ -0,0 +1,84 @@ + +#ifndef PARTICLESYSTEM_H +#define PARTICLESYSTEM_H + +#include "ocean/ocean_alt.h" +#include <iostream> +#define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT +#define EIGEN_DONT_VECTORIZE +#include "graphics/shader.h" +#include "graphics/camera.h" + +#include <Eigen/Core> +#include <Eigen/Dense> +#include <Eigen/Sparse> +#include <Eigen/Geometry> + +struct Particle{ + Eigen::Vector3f pos = Eigen::Vector3f(0,0,0); + Eigen::Vector3f vel = Eigen::Vector3f(0,2000,0); + + Eigen::Vector4f color = Eigen::Vector4f(1,1,1,1); + float life = 1.f; + +}; + +class particlesystem +{ +public: + particlesystem(); + + void update(double deltaTime); + void draw(Shader *skybox_shader, Camera m_camera); + void draw(Shader *shader, Camera m_camera, std::vector<Eigen::Vector3f> verts, Eigen::Matrix4f model); + + void init(std::vector<OceanSpray> verts); + + void setVerts(std::vector<OceanSpray> verts){ + //std::cout << "VERTS SIZE:" << verts.size() << std::endl; + m_verts = verts; + + } + + + +private: + int m_amount = 500; + int m_new_amount = 100; // new particles per frame + int lastUsedIndex = 0; + Eigen::Vector3f gravity = Eigen::Vector3f(0,-9.81f,0); + float factor = 40.f; // velocity multiplier + + + + void respawn_particle(Particle &p, OceanSpray new_pos); + int getUnusedParticleIndex(); + Eigen::Vector3f getRandomInitialVel(); + + + + + float d = 2.f; + std::vector<float> m_vertices = { + -d, d, + d,d, + -d, -d, + d, d, + d, -d, + -d, -d + }; + + GLuint VAO, VBO; // holds quad shape + + + + + + + std::vector<Particle> m_particles; + + std::vector<OceanSpray> m_verts; + +}; + +#endif // PARTICLESYSTEM_H |