The big picture: Obi and Oni

Obi is a collection of particle-based physics plugins for Unity. That means that everything is made out of small spheres called particles. Particles can affect each other, affect and be affected by other objects all trough the the use of constraints.

Obi only takes care of particle allocation and constraint setup. The physical simulation itself is performed by Oni (japanese for "demon") which is a completely engine-agnostic particle physics library written in C++. You can think of Obi as the middle-layer between Unity and Oni. Let's take a look at Obi's component architecture, and why it's made that way:

ObiSolver

ObiSolver is the main component in Obi. It is an interface to Oni's core solver. As such, it should always be at least one ObiSolver present in your scene if you want simulation to take place at all (there can be more than one ObiSolver instance, tough). ObiSolver exposes a few global simulation parameters such as particle interaction radius and gravity, and a few common parameters for all kinds of particle constraints available.

ObiActor

ObiActor is the base class for any entity wishing to use particle physics. ObiActors can be added to and removed from a ObiSolver. ObiCloth,ObiRope and ObiEmitter are examples of ObiActors.

Most actors will need some info provided by the user to generate a physical repesentation of whatever they're meant to represent. For instance, ObiRope needs a few parameters about the rope: thickness, resolution, etc. ObiCloth needs a ObiMeshTopology asset to generate particles and constraints from. Once this particle-based representation has been generated, actors need to be added to an ObiSolver in order for their particles to be simulated.

All actors need to be initialized manually. When you initialize an actor (or re-initialize it), all of its particles and constraints will be (re)created from scratch. This means that if you edited per-particle data using the particle editor (such as masses, radii, etc) or you added per-particle constraints (such as pins, handles or tethers) they will disappear and you will have to set them up again, so be careful with this. The only exception to the rule is ObiEmitter, as it is always initialized automatically when needed.

Reinitializing an actor is generally only needed when you make change substantial changes to it: modify the mesh of a cloth, or alter the initial path of a rope, for instance.

ObiConstraints

ObiConstraints is the base class for any group of particle constraints used by an ObiActor. ObiActors should specify which ObiConstraints they will need (making use of the RequireComponent directive). For instance, ObiRopes need 4 different kinds of constraints: ObiDistanceConstraints, ObiTetherConstrains, ObiBendingConstraints and ObiPinConstraints.

ObiConstraints get added and removed to/from an ObiSolver together with the ObiActor that created them.

Now, the basic steps that take place when an ObiActor gets added to an ObiSolver are:

  • ObiActor borrows a handful of particles from its ObiSolver, and sets their initial properties.
  • ObiActor asks its ObiConstraints components to generate constraints of multiple kinds between these particles.
  • In turn, each ObiConstraints component asks the ObiSolver to put these constraints in place.

Then, ObiSolver forwards all these petitions to Oni and asks it to simulate all active particles and constraints. Oni does not know which particles or constraints belong to each ObiActor, in fact it doesn't even know what an ObiActor is. This allows different ObiActors to physically interact with each other in lots of different ways, with no special case handling. Because at the end of the day, everything's just a bunch of particles.