rebuild the repulsion force grid every n frames

This commit is contained in:
2026-02-18 23:12:02 +01:00
parent 1dad350f7d
commit 55ff0f3490
5 changed files with 47 additions and 17 deletions

View File

@ -1 +1 @@
./cmake-build-release/.clangd
./cmake-build-debug/.clangd

View File

@ -1 +1 @@
./cmake-build-release/compile_commands.json
./cmake-build-debug/compile_commands.json

View File

@ -27,12 +27,13 @@ constexpr float ROT_SPEED = 1.0;
// Physics Engine
constexpr float MASS = 1.0;
constexpr float SPRING_CONSTANT = 1.0;
constexpr float SPRING_CONSTANT = 1.5;
constexpr float DAMPENING_CONSTANT = 0.8;
constexpr float REST_LENGTH = 1.0;
constexpr float REPULSION_FORCE = 0.1;
constexpr float REPULSION_RANGE = 3.0 * REST_LENGTH;
constexpr float VERLET_DAMPENING = 0.02; // [0, 1]
constexpr int REPULSION_GRID_REFRESH = 5; // Frames between grid rebuilds
constexpr float VERLET_DAMPENING = 0.01; // [0, 1]
// Graph Drawing
constexpr float VERTEX_SIZE = 0.1;

View File

@ -5,6 +5,7 @@
#include <raymath.h>
#include <string>
#include <unordered_map>
#include <vector>
class Mass {
public:
@ -83,12 +84,20 @@ public:
};
class MassSpringSystem {
private:
std::vector<Mass *> mass_vec;
std::vector<int> indices;
std::vector<int64_t> cell_ids;
int last_build;
int last_masses_count;
int last_springs_count;
public:
std::unordered_map<std::string, Mass> masses;
std::unordered_map<std::string, Spring> springs;
public:
MassSpringSystem() {};
MassSpringSystem() : last_build(1000) {};
MassSpringSystem(const MassSpringSystem &copy) = delete;
MassSpringSystem &operator=(const MassSpringSystem &copy) = delete;
@ -97,6 +106,9 @@ public:
~MassSpringSystem() {};
private:
auto BuildGrid() -> void;
public:
auto AddMass(float mass, Vector3 position, bool fixed,
const std::string &state) -> void;

View File

@ -123,15 +123,15 @@ auto MassSpringSystem::CalculateSpringForces() -> void {
}
}
auto MassSpringSystem::CalculateRepulsionForces() -> void {
auto MassSpringSystem::BuildGrid() -> void {
const float INV_CELL = 1.0f / REPULSION_RANGE;
const int n = masses.size();
// Collect pointers
std::vector<Mass *> massVec;
massVec.reserve(n);
mass_vec.clear();
mass_vec.reserve(n);
for (auto &[state, mass] : masses) {
massVec.push_back(&mass);
mass_vec.push_back(&mass);
}
// Assign each particle a cell index
@ -145,21 +145,38 @@ auto MassSpringSystem::CalculateRepulsionForces() -> void {
};
// Sort particles by cell
std::vector<int> indices(n);
indices.clear();
indices.resize(n);
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
return cellID(massVec[a]->position) < cellID(massVec[b]->position);
return cellID(mass_vec[a]->position) < cellID(mass_vec[b]->position);
});
// Build cell start/end table
std::vector<int64_t> cellIDs(n);
cell_ids.clear();
cell_ids.resize(n);
for (int i = 0; i < n; ++i) {
cellIDs[i] = cellID(massVec[indices[i]]->position);
cell_ids[i] = cellID(mass_vec[indices[i]]->position);
}
}
auto MassSpringSystem::CalculateRepulsionForces() -> void {
const float INV_CELL = 1.0f / REPULSION_RANGE;
const int n = masses.size();
if (last_build >= REPULSION_GRID_REFRESH ||
masses.size() != last_masses_count ||
springs.size() != last_springs_count) {
BuildGrid();
last_build = 0;
last_masses_count = masses.size();
last_springs_count = springs.size();
}
last_build++;
#pragma omp parallel for
for (int i = 0; i < n; ++i) {
Mass *mass = massVec[indices[i]];
Mass *mass = mass_vec[indices[i]];
int cx = (int)std::floor(mass->position.x * INV_CELL);
int cy = (int)std::floor(mass->position.y * INV_CELL);
int cz = (int)std::floor(mass->position.z * INV_CELL);
@ -174,11 +191,11 @@ auto MassSpringSystem::CalculateRepulsionForces() -> void {
(int64_t)((cz + dz) & 0xFFFFF);
// Binary search for this neighbor cell in sorted array
auto lo = std::lower_bound(cellIDs.begin(), cellIDs.end(), nid);
auto hi = std::upper_bound(cellIDs.begin(), cellIDs.end(), nid);
auto lo = std::lower_bound(cell_ids.begin(), cell_ids.end(), nid);
auto hi = std::upper_bound(cell_ids.begin(), cell_ids.end(), nid);
for (auto it = lo; it != hi; ++it) {
Mass *m = massVec[indices[it - cellIDs.begin()]];
Mass *m = mass_vec[indices[it - cell_ids.begin()]];
if (m == mass) {
continue;
}