This project is a 2D collision simulation on polygons using PBD. It explores the dynamics of collisions between various shapes in a two-dimensional space.
Forces are colored according to their sign and magnitude. Pulling forces are blue, while pushing forces are red.
Above is a screenshot of a shape falling on another shape. You can see when springs are compressed, they are drawn a brighter red color.
Here is the same screenshot drawn in normal mode, where the springs are not drawn.
I spawned in a polygon that is intersecting with the floor. In the next screenshot, you will see the response.
The intersecting vertex has been moved, and the appropriate forces have been applied.
A pinned shape has been knocked away from it's pin (drawn in magenta) by having a heavy object dropped on it. The force is drawn blue, indicating that the particle will be pulled back to its pin position.
I started this project from my finished Assignment 4 (Inverse Kinematics), because that project already had a set up for a 2D camera, which is what I wanted in my project.
I also copied the code for the springs from Assignment 5 (Cloth Sim) into my project, because my polygons are essentially cloths with very, very rigid springs. I did some refactoring and put the behavior
for the springs into the Spring
class, and made that class inherit from a base class Constraint
. This would make it much easier to add new types of
constraints, such as the Pin
.
The Pin
constraint works similiar to fixing a particle, but it can be overcome with enough force. It can be used to make objects
that rotate around a fixed point, like see-saws and swings.
I will show you some header files to demonstrate the interfaces of the objects, but keep in mind they may be edited for brevity.
For instance, the Polygon
class has some geometric helper methods that I won't show you here.
The Constraint
class, described earlier, provides methods for satisfying the constraint, and drawing it.
class Constraint {
public:
virtual void satisfyConstraint(double h) = 0;
virtual void draw() = 0;
};
The Polygon
class holds Particles
and Constraints
.
It has a constructor that takes in a list of points. It will automatically generate the particles and springs connecting them. There is also a method willIntersect
that will check if a particle will intersect this polygon.
If it will, it returns true and outputs the particles making up the intersected edge to b1 and b2, and the point p where the intersection normal intersects this edge.
class Polygon {
public:
Polygon(const std::vector<Eigen::Vector2d>& vertices);
bool willIntersect(std::shared_ptr<Particle> a, std::shared_ptr<Particle>& b1, std::shared_ptr<Particle>& b2, Eigen::Vector2d& p);
std::vector<std::shared_ptr<Particle>> particles;
std::vector<std::shared_ptr<Constraint>> constraints;
};
PBD works better than rigid body, in my opinion, for the following reasons:
I know this because when I started my project, I implemented rigid body, and encountered these problems. I then switched to PBD.