diff --git a/include/particle.h b/include/particle.h index 83c5bc4..c5a5d83 100644 --- a/include/particle.h +++ b/include/particle.h @@ -1,12 +1,13 @@ #ifndef PARTICLE_H #define PARTICLE_H +#include #include +#include #include #include -#include -#define G_CONSTANT 0.207f +#define G_CONSTANT 0.65f typedef struct { float x, y, z; @@ -23,7 +24,7 @@ typedef struct { float dampening; float life; - float size; + float radius; } Particle; typedef struct { @@ -36,7 +37,8 @@ typedef struct { pthread_mutex_t *mutex; pthread_cond_t *cond; - int *barrier; + pthread_barrier_t *barrier; + volatile int run; atomic_int exit; } Physics_params; @@ -47,14 +49,23 @@ void vec_add(Vec3 &out, Vec3 adder) { out.z += adder.z; } +float vec_length(Vec3 v) { + return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); +} + +float vec_dot(Vec3 a, Vec3 b) { + return a.x * b.x + a.y * b.y + a.z * b.z; +} + Particle particle_init(Vec3 position, Color color) { Particle p; p.position = position; p.color = color; p.velocity = {0.0f, 0.0f, 0.0f}; - p.life = 10; - p.dampening = 0.97f; + p.life = -2.0f; // INFO: Imorta + p.dampening = 0.9f; + p.radius = 0.05f; return p; } @@ -89,16 +100,62 @@ int particle_update(Particle *particles, unsigned long long size, float time) { return alive_count; } +void collision_update(Particle *particles, unsigned long long count, float restitution) { + for (unsigned long long i = 0; i < count; i++) { + for (unsigned long long j = i + 1; j < count; j++) { + Particle &p1 = particles[i]; + Particle &p2 = particles[j]; + + if (p1.life == 0 || p2.life == 0) { + continue; + } + + Vec3 diff = {p2.position.x - p1.position.x, p2.position.y - p1.position.y, p2.position.z - p1.position.z}; + float dist = vec_length(diff); + + float overlap = p1.radius + p2.radius - dist; + Vec3 normal; + if (overlap > 0 && dist > 0.00001f) { + normal = {diff.x / dist, diff.y / dist, diff.z / dist}; + p1.position.x -= normal.x * overlap * 0.5f; + p1.position.y -= normal.y * overlap * 0.5f; + p1.position.z -= normal.z * overlap * 0.5f; + + p2.position.x += normal.x * overlap * 0.5f; + p2.position.y += normal.y * overlap * 0.5f; + p2.position.z += normal.z * overlap * 0.5f; + + float velocity_relative_x = p1.velocity.x - p2.velocity.x; + float velocity_relative_y = p1.velocity.y - p2.velocity.y; + float velocity_relative_z = p1.velocity.z - p2.velocity.z; + + float v_rel = vec_dot({velocity_relative_x, velocity_relative_y, velocity_relative_z}, normal); + if (v_rel < 0) { + float impulse = -(1 + restitution) * v_rel / 2.0f; + + p1.velocity.x -= impulse * normal.x; + p1.velocity.y -= impulse * normal.y; + p1.velocity.z -= impulse * normal.z; + + p2.velocity.x += impulse * normal.x; + p2.velocity.y += impulse * normal.y; + p2.velocity.z += impulse * normal.z; + } + } + } + } +} + void *t_update(void *args) { Physics_params *params = (Physics_params *)args; while (params->exit != 1) { - pthread_mutex_lock(params->mutex); - if (params->(missing) == 0) { - sleep(100); + pthread_mutex_lock(params->mutex); + while (params->run == 0) { + pthread_cond_wait(params->cond, params->mutex); // sleeps here } - pthread_mutex_unlock(params->mutex); + pthread_mutex_unlock(params->mutex); - params->alive_count = 0; + params->alive_count = 0; for (unsigned long long i = params->interval_start; i < params->interval_end; i++) { Particle p = params->particle[i]; @@ -123,6 +180,7 @@ void *t_update(void *args) { p.life = 0; // DEBUG + /* if (params->thread_id == 0) { p.color = {1.0f, 1.0f, 1.0f, 1.0f}; } else if (params->thread_id == 1) { @@ -135,10 +193,13 @@ void *t_update(void *args) { p.color = {0.7f, 0.7f, 0.7f, 1.0f}; ; } + */ params->particle[i] = p; params->alive_count++; } + params->run = 0; + pthread_barrier_wait(params->barrier); } return NULL; diff --git a/psystem b/psystem index 4d84863..c4e8b21 100755 Binary files a/psystem and b/psystem differ diff --git a/source/main.cpp b/source/main.cpp index 0a46a60..416ca54 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -20,13 +20,13 @@ const char FRAGMENT_SHADER_SOURCE[] = "./source/shader/fragment.glsl"; const char VERTEX_SHADER_SOURCE[] = "./source/shader/vertex.glsl"; const char PROGRAM_NAME[] = "Particle Sim"; -const unsigned int THREAD_COUNT = 4; +const unsigned int THREAD_COUNT = 8; const unsigned int SCR_WIDTH = 1920; const unsigned int SCR_HEIGHT = 1080; const char *glsl_version; -const unsigned int PARTICLE_COUNT = 100000; +const unsigned int PARTICLE_COUNT = 2000; GLFWwindow *window; unsigned int VBO, VAO; @@ -100,6 +100,7 @@ __attribute__((constructor)) static void init_glfw(void) { glBindBuffer(GL_ARRAY_BUFFER, VBO); glEnable(GL_PROGRAM_POINT_SIZE); glEnable(GL_BLEND); + glEnable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glGenVertexArrays(1, &VAO); @@ -220,16 +221,11 @@ int main() { snprintf(errLog, 128, "There was a issue allocating memory for the particle list\n"); } else { for (unsigned long long i = 0; i < PARTICLE_COUNT; i++) { + float x = ((float)rand() / RAND_MAX) * 2.0f - 1.0f; // Random x between -1 and 1 + float y = ((float)rand() / RAND_MAX) * 2.0f - 1.0f; // Random y between -1 and 1 + float z = ((float)rand() / RAND_MAX) * 2.0f - 1.0f; // Random z between -1 and 1 - float x, y, z; - - x = (float)(rand() % 200) / 100; // [0.0 , 2.0] - y = (float)(rand() % 200) / 100; // [0.0 , 2.0] - z = (float)(rand() % 200) / 100; // [0.0 , 2.0] - - particles[i] = particle_init({x, y, z}, {x, y, z, 1.0}); - particles[i].life = -2.0f; // Start with imortal particles - particles[i].size = 20; + particles[i] = particle_init({x, 2, z}, {1.0f, 0.5f, 0.2f, 1.0f}); } } @@ -249,10 +245,13 @@ int main() { thread_params[i].time = 0; thread_params[i].exit = 0; + thread_params[i].run = 0; thread_params[i].alive_count = 0; thread_params[i].thread_id = i; - thread_params[i].mutex = global_mutex; + thread_params[i].mutex = &mutex; + thread_params[i].cond = &cond; + thread_params[i].barrier = &barrier; pthread_create(&threads[i], NULL, t_update, &thread_params[i]); } @@ -284,15 +283,25 @@ int main() { glm::mat4 projection = camera_projection(camera, aspect); glm::mat4 mvp = projection * view; // model is identity - alive_count = 0; + pthread_mutex_lock(&mutex); for (int i = 0; i < THREAD_COUNT; i++) { - thread_params->time = delta_time; - thread_params->run = 1; + thread_params[i].time = delta_time; + thread_params[i].run = 1; } + pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mutex); + + pthread_barrier_wait(&barrier); + + alive_count = 0; + for (int i = 0; i < THREAD_COUNT; i++) + alive_count += thread_params[i].alive_count; + + collision_update(particles, alive_count, 0.06f); // Render glClearColor(0.03f, 0.03f, 0.03f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); grid_draw(g_grid, mvp); axis_draw(g_axis, mvp); @@ -318,7 +327,7 @@ int main() { ImGui::Text("Alive particles: %d", alive_count); if (particles) ImGui::Text("P[0]: %3.2f %3.2f %3.2f, Life: %0.2f", (double)particles[0].position.x, (double)particles[0].position.y, (double)particles[0].position.z, - (double)particles[0].life); + (double)particles[0].life); ImGui::Separator(); ImGui::Text("Left-click to capture mouse"); ImGui::Text("ESC = release mouse / quit"); diff --git a/source/shader/vertex.glsl b/source/shader/vertex.glsl index 63e50aa..45e047e 100644 --- a/source/shader/vertex.glsl +++ b/source/shader/vertex.glsl @@ -21,6 +21,6 @@ void main() { vec4 clip_pos = uMVP * vec4(aPos, 1.0); gl_Position = clip_pos; - float base_size = 0.2 + size; + float base_size = 0.5 + (size * 2000); gl_PointSize = max(1.0, base_size / clip_pos.w); }