Difference between revisions of "Team Guardian Physics"
NorthWind87 (talk | contribs) (→Physics System Overview) |
NorthWind87 (talk | contribs) (→Framework Breakdown) |
||
Line 55: | Line 55: | ||
The framework consists of a physics simulator (PhysicsScene) and a collision space (SimpleCollisionSpace). They are designed to work relatively independently using a set a of joint interfaces. | The framework consists of a physics simulator (PhysicsScene) and a collision space (SimpleCollisionSpace). They are designed to work relatively independently using a set a of joint interfaces. | ||
− | === PhysicsScene === | + | Let's first look at the physics-only components: |
+ | |||
+ | === Physics === | ||
+ | |||
+ | ==== PhysicsScene ==== | ||
<pre>#include "iPhysicsScene.h"</pre> | <pre>#include "iPhysicsScene.h"</pre> | ||
Line 124: | Line 128: | ||
This is sufficient to add physics simulation support to Chris' framework. This won't magically cause your objects to suddenly start moving around and reacting to gravity however. To do that, each object that should be simulated by the simulator must be associated with a RigidBody. It is also possible to use a PhysicsFrame in a similar role, more on that later. | This is sufficient to add physics simulation support to Chris' framework. This won't magically cause your objects to suddenly start moving around and reacting to gravity however. To do that, each object that should be simulated by the simulator must be associated with a RigidBody. It is also possible to use a PhysicsFrame in a similar role, more on that later. | ||
− | === RigidBody === | + | ==== RigidBody ==== |
<pre>#include "iRigidBody.h"</pre> | <pre>#include "iRigidBody.h"</pre> | ||
Line 168: | Line 172: | ||
; virtual RBDynamics& getDynamics() : Returns a reference to the RBDynamics struct. The public properties of the struct can be directly edited in this way. The physics simulator will update these properties every frame. | ; virtual RBDynamics& getDynamics() : Returns a reference to the RBDynamics struct. The public properties of the struct can be directly edited in this way. The physics simulator will update these properties every frame. | ||
; virtual void Delete() const : Deletes this RigidBody and its RBDynamics instance. Does not delete the associated object or any associated collision listeners. | ; virtual void Delete() const : Deletes this RigidBody and its RBDynamics instance. Does not delete the associated object or any associated collision listeners. | ||
+ | |||
+ | === Collision === | ||
+ | |||
+ | ==== CollisionSpace ==== | ||
== Listening For Collisions == | == Listening For Collisions == |
Revision as of 02:53, 6 April 2011
Contents
Physics System Overview
By 'northWind'
Major Classes
- Physics
- iPhysicsFrame
- iRigidBody
- RBDynamics
- Physics Coordinator
- iPhysicsScene
- Collision Information
- iCollisionGeometry
- iCSphere
- iCOBB
- Collision Notification
- iCollisionListener
- Collision Space
- iCollisionSpace
- iSimpleCollisionSpace
How to Use
- Sample Code To Be Placed In Design
iPhysicsFrame* f = CreatePhysicsFrame(); // Create base physics frame RBDynamics* d = f->getDynamics(); // Obtain handle to physics frame iObject* o = CreateSphere(…..); o->attachTo(f); // Create graphical object and attach to pframe d.velocity += Vector(0, 0, 500); // Set some of the physics properties // OPTIONAL - Attach collision primitive iCollisionGeometry* c = CreateCSphere(f->getRB(), 50); // At this point the object is simulating in the world and no further action is *necessary* // Other dynamics properties can also be changed for further effects // Although the physics simulator keeps track of collision geometries and rigid bodies and will dispose of // them upon shutdown (it does not track PhysicsFrame objects), it is good practice to clear bodies that // are out of use since physics computations, especially collision, are quite costly. // To release, call delete on the allocated elements. Generally, the elements can be disallocated in any // order. Note here that I did NOT need to delete the Object created but I am deleting it since I attached // it to my PhysicsFrame and I do not want to delete the parent of the object prior to deleting the // object itself. o->Delete(); f->Delete(); c->Delete();
Framework Breakdown
The framework consists of a physics simulator (PhysicsScene) and a collision space (SimpleCollisionSpace). They are designed to work relatively independently using a set a of joint interfaces.
Let's first look at the physics-only components:
Physics
PhysicsScene
#include "iPhysicsScene.h"
PhysicsScene is the coordinator responsible for frame by frame physics simulation. It should be created in Engine
's constructor by calling:
CreatePhysicsScene(iContext* c)
The collision space, if any, should be set in Engine
's setup() function. We will look at this later.
Let's take a look at PhysicsScene's interface:
/* Physics Scene Interface - Scene Component - Model Branch * * iPhysicsScene.h * November 6 2010 */ //--------------------------- iPhysicsScene ----------------------------------- // // iPhysicsScene is the interface to the physics scene coordinator // class iRigidBody; class iContext; class iCollisionSpace; class iPhysicsScene { public: // initialization functions virtual bool add(iRigidBody* o) = 0; virtual void setNewGlobalCollisionSpace(iCollisionSpace* cs) = 0; virtual void restore(int now) = 0; // execution functions virtual void update(int now) = 0; // termination functions virtual void reset(int now) = 0; virtual void suspend() const = 0; virtual void release() const = 0; virtual void remove(const iRigidBody* o) = 0; virtual void Delete() const = 0; }; extern "C" iPhysicsScene* CreatePhysicsScene(iContext* c);
The standard controller functions should be called in the usual places in Engine.cpp (Delete(), release(), suspend(), reset(), restore()), please refer to Engine.cpp in the reference implementation for more details.
In order to advance the simulation forward, update(int now)
should be called every frame. Naturally, PhysicsScene's update()
should be called from within Engine
's run. Physics should be updated before design is updated. Let's look at how this is accomplished in the reference implementation:
now = rightNow; // retrieve user input, if any keyboard->retrieveInput(); mouse->retrieveInput(); joystick->retrieveInput(); // update the model components physicsScene->update(rightNow); design->update(rightNow); scene->updateEmitters(rightNow); viewing->update(rightNow); audio->update(rightNow); lighting->update(); hud->update(rightNow);
This is sufficient to add physics simulation support to Chris' framework. This won't magically cause your objects to suddenly start moving around and reacting to gravity however. To do that, each object that should be simulated by the simulator must be associated with a RigidBody. It is also possible to use a PhysicsFrame in a similar role, more on that later.
RigidBody
#include "iRigidBody.h"
A RigidBody provides access to a physics object's state in the world at any given point in time. Each RigidBody instance holds its physics properties in an RBDynamics struct. In order to access a RigidBody instance's properties, the method getDynamics()
is called on the instance. This method returns a reference to an RBDynamics struct. Let's look at the interface:
class iRigidBody { public: // initialization functions virtual iRigidBody* clone() const = 0; virtual void attach(iFrame* o) = 0; virtual void attachListener(iCollisionListener* l) = 0; virtual void detachListener(const iCollisionListener* l)= 0; virtual void restore(int now) = 0; // execution functions virtual std::vector<iCollisionListener*>& getListeners()= 0; virtual iFrame* getFrame () = 0; virtual RBDynamics& getDynamics() = 0; virtual const RBDynamics& getDynamics() const = 0; virtual void setDynamics(const RBDynamics& d) = 0; // termination functions virtual void reset(int now) = 0; virtual void suspend() const = 0; virtual void release() const = 0; virtual void Delete() const = 0; }; extern "C" iRigidBody* CreateRigidBody(iFrame* o);
Aside from the usual suspects, a few functions are of particular importance:
iRigidBody* CreateRigidBody(iFrame* o); virtual void attach(iFrame* o) = 0; virtual RBDynamics& getDynamics() = 0; virtual void Delete() const = 0;
- iRigidBody* CreateRigidBody(iFrame* o)
- Creates a RigidBody and associates it with the active PhysicsScene coordinator. This function accepts an
iFrame* o
parameter. This parameter can be NULL if desired but should usually be the address of a valid iFrame.
The passed iFrame will be bound to this RigidBody. Every frame, PhysicsScene will update the frame's homogenous transformation matrix (T) to follow the location and rotation of the RigidBody. This is done at the end of the physics update step. - virtual void attach(iFrame* o)
- Associates an iFrame instance with the RigidBody. Can also be used to associate the RigidBody with a new iFrame or to detach it from its currently associated iFrame by passing in NULL.
- virtual RBDynamics& getDynamics()
- Returns a reference to the RBDynamics struct. The public properties of the struct can be directly edited in this way. The physics simulator will update these properties every frame.
- virtual void Delete() const
- Deletes this RigidBody and its RBDynamics instance. Does not delete the associated object or any associated collision listeners.
Collision
CollisionSpace
Listening For Collisions
While RigidBodies are not directly responsible for holding collision information or for keeping track of collisions, a decision was made early on to let RigidBody hold the CollisionListener list. The logic behind this is foul and mysterious; in the future, the CollisionListener list will most likely be held by instances of iCollisionGeometry.
A CollisionListener is an object that performs some action in response to a collision event between two objects. This is done by implementing the iCollisionListener interface in a class and then adding an instance of the listener class to the CollisionListener list of a given RigidBody. From that point on, that RigidBody will forward all collision events that it is involved in to the added CollisionListener as well as any other CollisionListeners that may have been added to the RigidBody previously. CollisionListeners can also be removed from a given RigidBody.
The CollisionListener list of a given RigidBody may be edited by calling the following functions:
virtual void attachListener(iCollisionListener* l) = 0; virtual void detachListener(const iCollisionListener* l)= 0; virtual std::vector<iCollisionListener*>& getListeners()= 0;
I assume that the purpose of these functions is mostly self explanatory :)
CollisionListener
#include "iCollisionListener.h"
Let's look at the CollisionListener interface:
/* Collision Listener Interface - Physics Scene Component - Model Branch * * iCollisionListener.h * December 8 2010 */ //--------------------------- iCollisionListener ------------------------------ // // A listener for collision events. Can be attached to a rigid body. // #include "MathDeclarations.h" class iRigidBody; class iCollisionListener { public: virtual void HitWall( iRigidBody* other, Vector hitNormal, Vector hitLocation) = 0; };
The interface requires a single function to be implemented:
virtual void HitWall(iRigidBody* other, Vector hitNormal, Vector hitLocation)
This function will be called by PhysicsScene every frame that two objects are colliding.
- iRigidBody* other
- The RigidBody that the RigidBody that this CollisionListener is attached to has collided with.
- Vector hitNormal
- A unit vector in world space perpendicular to the surface of collision, points in the direction of
other
. - Vector hitLocation
- The location in world space of the point of collision.
Integrating Framework Into Existing Projects
There are three ways to integrate the framework into your game:
- As a physics simulator and collision detector combination
- As a physics simulator only
- As a collision detector only
Please skip to the section relevant to your interests :)
Combined Physics Simulator/Collision Detector
This is the framework in its default state.
RBDynamics Properties Reference
- Vector position
- Current position of COM
- Vector velocity
- Current velocity of COM
- Vector lastVelocity
- Used to help detect velocity spikes
- Vector acceleration
- Additive acceleration of COM
- Vector force
- Constant force applied to COM
- Vector temporalForce
- Force that will be applied at the nexttick and then reset to 0. Total linear acceleration is equal to: <math>acceleration + ((force + temporalForce)/mass)</math>
- float mass
- Mass, defaults to 1, the more mass present the more force required to move the object. Set this to INFINITE_MASS (#include "ModelSettings.h") to prevent the object from moving.
- float dragCoefficient
- The drag coefficient, 0 implies no drag, 0.25~0.45 is the drag of a car, etc...
- float restitution
- How much energy does the object keep after a collision? 1 - Superball, the object loses none, 0 - Clay, the object loses all
- float friction
- Tangential impulse applied during a collision that hinders movement along the plane of the collision normal. Coefficient of friction of a given collision is calculated by adding together the friction values of the two objects colliding.
- Vector com
- Center of Mass offset.
- PhysicsType physicsType
- Type of physics applied to body, defaults to Falling (BUGGY, use PHYS_Falling and PHYS_Floating for now)
- Matrix orientation
- Matrix representing rotation in XYZ
- Vector angularVelocity
- Angular velocity in radians/sec in XYZ
- Vector angularMomentum
- Angular momentum on the COM
- Vector torque
- Torque force on the COM
- Vector temporalTorque
- Torque force that will be applied at the next tick and then reset to 0; Total angular acceleration is equal to: angularAcceleration + ((torque + temporalTorque)/inertiaMoment)
RBDynamics Functions Reference
- Vector getWorldCOM() const
- Returns the world position of the COM with respect to this body.
- Vector getVelocityAtWorldPoint(const Vector& p) const
- Given a point in worldspace, returns its speed taking into account velocity and angular velocity.
- Void setInverseInertiaTensor(const Matrix& i)
- Sets the inverse inertia tensor of this body. Automatically sets the inertia tensor as well by inversing the incoming matrix. DOES NOT NEED TO BE CALLED AFTER CALLING setInertiaTensor()
- Void setInertiaTensor(const Matrix& i)
- Opposite of setInverseInertiaTensor. DOES NOT NEED TO BE CALLED AFTER CALLING setInverseInertiaTensor()
- Matrix& getInertiaTensor()
- Matrix& getInverseInertiaTensor()
- Returns the inertia tensor or inverse inertia tensor contained by this object.
- Void ApplyImpulse(const Vector& impulse, const Vector& pointOfApplication)
- Applies a given impulse instantaneously onto this object at a given world point of application. Can be used to shoot or prod objects.
Other Topics Reference
Inertia Tensor
The inertia tensor is a Matrix representation of the distribution of mass within an object. This property is important in that it determines how objects rotate in reaction to given impulses. Provided are two methods to create them:
- Use the quick inertia tensor calculators (getBoxInertiaTensor, getSphereInertiaTensor, #include “MathDefinitions.h”)
- Create a sequence of PointMass objects and calculate the inertia tensor on them by using getInertiaTensor (const PointMass* points, size_t n). If possible, please use method 1 as method 2 has been returning somewhat exaggerated results.
Impulse
A force that is applied to an object over a very small time period. Practically, this force is applied instantaneously in the case of this engine.
Collision Geometry
The collision representation of an object. Typically in the form of boxes or spheres but may be other shapes. Currently implemented shapes are spheres and boxes, future additions include planes (possibly although use appears limited since no graphical representation of infinite plane) and compound objects.
Collision Space
A geometric space that contains a set of collision geometries. It is responsible for weeding out impossible collisions and generally controls the number of maximum collision calculations in a frame. Currently, the “simple” collision space is implemented ((N^2)/2 collisions) but the octree collision space is being currently implemented and should alleviate the number of objects bottleneck currently plaguing the system.
Matrix Inverse
Has a similar effect to the traditional division operation when multiplied by a float or vector (ie it acts as the divisor). This explanation is not rigorous in any way shape or form :)