rebuild the repulsion force grid every n frames
This commit is contained in:
@ -1 +1 @@
|
|||||||
./cmake-build-release/compile_commands.json
|
./cmake-build-debug/compile_commands.json
|
||||||
@ -27,12 +27,13 @@ constexpr float ROT_SPEED = 1.0;
|
|||||||
|
|
||||||
// Physics Engine
|
// Physics Engine
|
||||||
constexpr float MASS = 1.0;
|
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 DAMPENING_CONSTANT = 0.8;
|
||||||
constexpr float REST_LENGTH = 1.0;
|
constexpr float REST_LENGTH = 1.0;
|
||||||
constexpr float REPULSION_FORCE = 0.1;
|
constexpr float REPULSION_FORCE = 0.1;
|
||||||
constexpr float REPULSION_RANGE = 3.0 * REST_LENGTH;
|
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
|
// Graph Drawing
|
||||||
constexpr float VERTEX_SIZE = 0.1;
|
constexpr float VERTEX_SIZE = 0.1;
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <raymath.h>
|
#include <raymath.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class Mass {
|
class Mass {
|
||||||
public:
|
public:
|
||||||
@ -83,12 +84,20 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class MassSpringSystem {
|
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:
|
public:
|
||||||
std::unordered_map<std::string, Mass> masses;
|
std::unordered_map<std::string, Mass> masses;
|
||||||
std::unordered_map<std::string, Spring> springs;
|
std::unordered_map<std::string, Spring> springs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MassSpringSystem() {};
|
MassSpringSystem() : last_build(1000) {};
|
||||||
|
|
||||||
MassSpringSystem(const MassSpringSystem ©) = delete;
|
MassSpringSystem(const MassSpringSystem ©) = delete;
|
||||||
MassSpringSystem &operator=(const MassSpringSystem ©) = delete;
|
MassSpringSystem &operator=(const MassSpringSystem ©) = delete;
|
||||||
@ -97,6 +106,9 @@ public:
|
|||||||
|
|
||||||
~MassSpringSystem() {};
|
~MassSpringSystem() {};
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto BuildGrid() -> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto AddMass(float mass, Vector3 position, bool fixed,
|
auto AddMass(float mass, Vector3 position, bool fixed,
|
||||||
const std::string &state) -> void;
|
const std::string &state) -> void;
|
||||||
|
|||||||
@ -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 float INV_CELL = 1.0f / REPULSION_RANGE;
|
||||||
const int n = masses.size();
|
const int n = masses.size();
|
||||||
|
|
||||||
// Collect pointers
|
// Collect pointers
|
||||||
std::vector<Mass *> massVec;
|
mass_vec.clear();
|
||||||
massVec.reserve(n);
|
mass_vec.reserve(n);
|
||||||
for (auto &[state, mass] : masses) {
|
for (auto &[state, mass] : masses) {
|
||||||
massVec.push_back(&mass);
|
mass_vec.push_back(&mass);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign each particle a cell index
|
// Assign each particle a cell index
|
||||||
@ -145,21 +145,38 @@ auto MassSpringSystem::CalculateRepulsionForces() -> void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Sort particles by cell
|
// Sort particles by cell
|
||||||
std::vector<int> indices(n);
|
indices.clear();
|
||||||
|
indices.resize(n);
|
||||||
std::iota(indices.begin(), indices.end(), 0);
|
std::iota(indices.begin(), indices.end(), 0);
|
||||||
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
|
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
|
// 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) {
|
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
|
#pragma omp parallel for
|
||||||
for (int i = 0; i < n; ++i) {
|
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 cx = (int)std::floor(mass->position.x * INV_CELL);
|
||||||
int cy = (int)std::floor(mass->position.y * INV_CELL);
|
int cy = (int)std::floor(mass->position.y * INV_CELL);
|
||||||
int cz = (int)std::floor(mass->position.z * 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);
|
(int64_t)((cz + dz) & 0xFFFFF);
|
||||||
|
|
||||||
// Binary search for this neighbor cell in sorted array
|
// Binary search for this neighbor cell in sorted array
|
||||||
auto lo = std::lower_bound(cellIDs.begin(), cellIDs.end(), nid);
|
auto lo = std::lower_bound(cell_ids.begin(), cell_ids.end(), nid);
|
||||||
auto hi = std::upper_bound(cellIDs.begin(), cellIDs.end(), nid);
|
auto hi = std::upper_bound(cell_ids.begin(), cell_ids.end(), nid);
|
||||||
|
|
||||||
for (auto it = lo; it != hi; ++it) {
|
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) {
|
if (m == mass) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user