LEMMA Physics Engine
This section explains how LEMMA
's simple physics engine works. First the meaning of all the necessary properties is explained and the math used to calculate them. After that a sequence diagram shows how this is realized in the program.
The following attributes of Rigid Body are computed in every frame for every particle and (except SUM_FORCES) every compound part:
This vector is set in every loop after the interactables are checked. At the end of the calculations it is deleted again to avoid accumulation. It is set by a vector from an interactable to the actor (hand) and expressed in user coordinates.
The mass of the particles is set by specifiing it as a number in front of the particles name (e.g. 023_leftArm for 23% of the overall weight). If the sum of all the particles weights yield 100 the whole body weights 1 kg. It can be set differently. Then the numbers are used as % further on. The mass of the parts are calculated from the sum of the childrens mass in every frame.
This is the axis or rotation of the particular RigidBody expressed in user coordinates.
This is the vector that points from the origin of the user coordinate system to the nearest point on the axis of rotation, expressed in user coordinates.
This is the vector from the point on the axis that is nearest to the User Coordinate System Origin to the center of the particular RigidBody (Part or Particle), expressed in User Coordinates. The center of mass of the particles is set by their pivot position, that of the parts is calculated from the particles after the formula sum(child(i).center_of_mass*child(i).mass)/my_mass
: This vector points from the origin of the user coordinate system to the center of mass of the particle / part
: This vector points from the axis of rotation to the center of mass, expressed in user coordinates
Vector from the point on the axis that is nearest to the User Coordinate System Origin to the Interactible of the particle. If the particle doesn't have an interactable, it's the same as center of mass.
INERTIA_X, INERTIA_Y, INERTIA_Z:
As the rotational inertia is not a vector but a tensor, which can be representetd as a 3x3 matrix these three vectors will
represent the columns of this matrix. At the moment we use a simplified method for calculating the inertia and for that, what the vectors represent now
is the inertia stored in the vectors length in the directions x, y, z. So eg INERTIA_X is at the moment (Inertia, 0,0).
The rotational inertia is calculated for every particle by the formula I = Icm + mass *radius^2 (parallel axis theorem) where Icm is (mass*particle_radius^2)/2 which is the inertia for a cylinder (hack). After that every part calculates its inerti by summing over its children. I assume here that a particle is a cylinder with the radius 0.025 what has to be taken into account when modeling.
Torque is computed by first calculating all torques of the particles by ISA
(x = crossproduct). Then those torques are summed up in the compound parts. To simulate the effect of force and counterforce, the upmost RigidBody dots this torque on the AXIS (it may be better to come up with a possibility to really generate counterforces in the fellow particles, but I have no idea how that works). After that, if there are any ENVIRONMENTAL_FORCEs like gravity, the torque for that is then calculated by CENTER_OF_MASS x ENVIRONMENTAL_FORCES and then added to the torque (only upmost parent!). Because it is calculated from vectors in terms of the user coordinate system, the torque vector itself is expressed in user coordinates, too.
is computed after the torque, only for the upmost rigid body according to AngularAcceleration = Torque / RotationalInertia
is computed two times. the first time after the event loop has just begun and the interactables have been checked, as this is the moment when objects might have moved. That means that the angular momentum could have changed according to e.g. changed rotational inertia. As no torques were applied so far, the angular momentum has to stay constant. So the angular velocity has to be adapted to yield the same angular momentum again by the formula omega_new = omega_old * rotInertia_old/rot_inertia_new.
The second time is after the angular acceleration has been computet. Then the angularVelocity_new = angularVelocity_old + angularAcceleration * frameDuration.
As we are concentrating only on rotational dynamics the linear velocity computes like linear_velocity = angular_velocity x center_of_mass
The linear momentum computes linear_momentum = linear_velocity * mass
Angular Momentum computes for the particles like angular_momentum = center_of_mass x linear_momentum. The angular momentum of the compound parts is the sumof the children. The upmost part additionally takes the component of the torque that is perpendicular to its axis (tpa) and adds it to the AM like this: angular_momentum = angular_momentum + tpa * delta_t where delta_t is the time of an "instant", namely the length of a frame.
In case gravity is off this vector is (0,0,0) otherwise it's the amount, gravity is set to.
How does it work
The objects in the scene are modeled in a compound pattern. A RigidBody is composed of other RigidBodies where the intermediate RigidBodies are called "Parts". Those RigidBodies that do not have "children" any more, are called "Particles". In fact, a RigidBody is a collection of Particles, glued together by RigidBodyParts.
It is important to notice that it is only necessary to call the topmost RigidBodyPart to trigger the calculations for all its children (parts and particles).
The following process happens during every frame (defined by the OpenSceneGraph Viewer, located in the VisuCanvas):
- All Interactables are checked. This means, if a force has been generated by them, it is now transfered to the target particle. Also external forces like gravity are transfered to the RigidBodies.
- The VisuCanvas asks the VisuController to update the position of every RigidBody in its control. Cut short: after doing this all the RigidBodys (Parts and Particles) in the scene know where they are relative to the User Coordinate System (ofu) and how their particular axis of rotation is oriented (afu). In this task all vectors that concern the location of a body are set anew. Additionally the mass is reconfigured if necessary and the rotational inertia recalculated.
- The VisuCanvas asks the VisuController to update the remaining attributes of all RigidBodys in its control. At this point 1) the user coordinate system can have moved, but the vectors don't know anything about it, and 2) The rigid bodies can have moved. The next three methods are necessary to conserve angular momentum as no external force has been applied so far.
- Now one after another Torque, Angular Acceleration, Angular Velocity, Linear Velocity, Linear Momentum and Angular Momentum are recomputed based on the above given equations and the new positions and forces.
- At the end of this process the VisuCanvas can use those properties to draw all objects accordingly.