feat: COLISIONS

This commit is contained in:
AfonsoCMSousa 2026-03-24 00:49:09 +00:00
parent 2b9aa3922e
commit 45ed43a968
No known key found for this signature in database
4 changed files with 99 additions and 29 deletions

View File

@ -1,12 +1,13 @@
#ifndef PARTICLE_H #ifndef PARTICLE_H
#define PARTICLE_H #define PARTICLE_H
#include <math.h>
#include <pthread.h> #include <pthread.h>
#include <stdatomic.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <stdatomic.h>
#define G_CONSTANT 0.207f #define G_CONSTANT 0.65f
typedef struct { typedef struct {
float x, y, z; float x, y, z;
@ -23,7 +24,7 @@ typedef struct {
float dampening; float dampening;
float life; float life;
float size; float radius;
} Particle; } Particle;
typedef struct { typedef struct {
@ -36,7 +37,8 @@ typedef struct {
pthread_mutex_t *mutex; pthread_mutex_t *mutex;
pthread_cond_t *cond; pthread_cond_t *cond;
int *barrier; pthread_barrier_t *barrier;
volatile int run;
atomic_int exit; atomic_int exit;
} Physics_params; } Physics_params;
@ -47,14 +49,23 @@ void vec_add(Vec3 &out, Vec3 adder) {
out.z += adder.z; 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 particle_init(Vec3 position, Color color) {
Particle p; Particle p;
p.position = position; p.position = position;
p.color = color; p.color = color;
p.velocity = {0.0f, 0.0f, 0.0f}; p.velocity = {0.0f, 0.0f, 0.0f};
p.life = 10; p.life = -2.0f; // INFO: Imorta
p.dampening = 0.97f; p.dampening = 0.9f;
p.radius = 0.05f;
return p; return p;
} }
@ -89,16 +100,62 @@ int particle_update(Particle *particles, unsigned long long size, float time) {
return alive_count; 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) { void *t_update(void *args) {
Physics_params *params = (Physics_params *)args; Physics_params *params = (Physics_params *)args;
while (params->exit != 1) { while (params->exit != 1) {
pthread_mutex_lock(params->mutex); pthread_mutex_lock(params->mutex);
if (params->(missing) == 0) { while (params->run == 0) {
sleep(100); 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++) { for (unsigned long long i = params->interval_start; i < params->interval_end; i++) {
Particle p = params->particle[i]; Particle p = params->particle[i];
@ -123,6 +180,7 @@ void *t_update(void *args) {
p.life = 0; p.life = 0;
// DEBUG // DEBUG
/*
if (params->thread_id == 0) { if (params->thread_id == 0) {
p.color = {1.0f, 1.0f, 1.0f, 1.0f}; p.color = {1.0f, 1.0f, 1.0f, 1.0f};
} else if (params->thread_id == 1) { } 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}; p.color = {0.7f, 0.7f, 0.7f, 1.0f};
; ;
} }
*/
params->particle[i] = p; params->particle[i] = p;
params->alive_count++; params->alive_count++;
} }
params->run = 0;
pthread_barrier_wait(params->barrier);
} }
return NULL; return NULL;

BIN
psystem

Binary file not shown.

View File

@ -20,13 +20,13 @@ const char FRAGMENT_SHADER_SOURCE[] = "./source/shader/fragment.glsl";
const char VERTEX_SHADER_SOURCE[] = "./source/shader/vertex.glsl"; const char VERTEX_SHADER_SOURCE[] = "./source/shader/vertex.glsl";
const char PROGRAM_NAME[] = "Particle Sim"; 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_WIDTH = 1920;
const unsigned int SCR_HEIGHT = 1080; const unsigned int SCR_HEIGHT = 1080;
const char *glsl_version; const char *glsl_version;
const unsigned int PARTICLE_COUNT = 100000; const unsigned int PARTICLE_COUNT = 2000;
GLFWwindow *window; GLFWwindow *window;
unsigned int VBO, VAO; unsigned int VBO, VAO;
@ -100,6 +100,7 @@ __attribute__((constructor)) static void init_glfw(void) {
glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO);
glEnable(GL_PROGRAM_POINT_SIZE); glEnable(GL_PROGRAM_POINT_SIZE);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenVertexArrays(1, &VAO); glGenVertexArrays(1, &VAO);
@ -220,16 +221,11 @@ int main() {
snprintf(errLog, 128, "There was a issue allocating memory for the particle list\n"); snprintf(errLog, 128, "There was a issue allocating memory for the particle list\n");
} else { } else {
for (unsigned long long i = 0; i < PARTICLE_COUNT; i++) { 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; particles[i] = particle_init({x, 2, z}, {1.0f, 0.5f, 0.2f, 1.0f});
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;
} }
} }
@ -249,10 +245,13 @@ int main() {
thread_params[i].time = 0; thread_params[i].time = 0;
thread_params[i].exit = 0; thread_params[i].exit = 0;
thread_params[i].run = 0;
thread_params[i].alive_count = 0; thread_params[i].alive_count = 0;
thread_params[i].thread_id = i; 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]); 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 projection = camera_projection(camera, aspect);
glm::mat4 mvp = projection * view; // model is identity glm::mat4 mvp = projection * view; // model is identity
alive_count = 0; pthread_mutex_lock(&mutex);
for (int i = 0; i < THREAD_COUNT; i++) { for (int i = 0; i < THREAD_COUNT; i++) {
thread_params->time = delta_time; thread_params[i].time = delta_time;
thread_params->run = 1; 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 // Render
glClearColor(0.03f, 0.03f, 0.03f, 1.0f); 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); grid_draw(g_grid, mvp);
axis_draw(g_axis, mvp); axis_draw(g_axis, mvp);
@ -318,7 +327,7 @@ int main() {
ImGui::Text("Alive particles: %d", alive_count); ImGui::Text("Alive particles: %d", alive_count);
if (particles) 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, 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::Separator();
ImGui::Text("Left-click to capture mouse"); ImGui::Text("Left-click to capture mouse");
ImGui::Text("ESC = release mouse / quit"); ImGui::Text("ESC = release mouse / quit");

View File

@ -21,6 +21,6 @@ void main() {
vec4 clip_pos = uMVP * vec4(aPos, 1.0); vec4 clip_pos = uMVP * vec4(aPos, 1.0);
gl_Position = clip_pos; 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); gl_PointSize = max(1.0, base_size / clip_pos.w);
} }