Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Believable physics in C#

0.00/5 (No votes)
29 Dec 2003 4  
How to create believable physics using C#.

Sample Image - parachute.jpg

Introduction

After reading the great article 'Advanced Character Physics' [1], I realized that, contrary to my earlier belief, creating believable physics on a computer isn't overly complicated. In fact, it's rather simple and isn't especially CPU-hungry neither. As I figured this might be an interesting topic for some developers, I put together these projects and this article for CodeProject.

Setting up

Requirements

To be able to compile and use the projects, you'll need the managed extensions for Directx9 [2]. You might need to perform an extra step after installing the DirectX9 SDK. Please refer to the readme.txt that comes with the DirectX9 SDK. The project ParticleSystem depends upon DirectX9 for some basic operations on vectors and matrices. The test application depends on DirectX9 more heavily as it uses DirectX9 to visualize the particle-constraint system.

Compiling

Once you have the managed extensions for DirectX9, it should be easy to compile the projects.

Running the test application

You should see a parachuting box not unlike the picture above. There are simple commands to move the viewpoint as well as change some parameters of the particle-constraint system.

  • Arrow-keys: Moves the viewpoint.
  • A: Makes gravity vector pointing downward.
  • B: Makes gravity vector pointing upward.
  • S: Shakes the particles.
  • K: Increase the strength of the wind (that affects the parachute).
  • L: Decrease the strength of the wind (that affects the parachute).

The code in the test project is close to awful as I only patched the DirectX9 wizard generated code just enough so I could view the particle-constraint system. The interesting code is in the ParticleSystem project.

How to create a simple particle-constraint system

Let's assume you want to create a very simple system with only one small box in it.

// Begin a transaction

ParticleSystem.Transaction lTransaction = ps.GetTransaction(); 
// Adds a global constraint to the system (to make sure that the box 

// doesn't fall and fall and fall)

lTransaction.AddGlobalConstraint(new AxisAlignedBox( 
    new Vector3(-10, -15, -10), 
    new Vector3(10, 15, 10))); 
// Set the gravity vector of the system

ps.Gravity = new Vector3(0, -1, 0); 
// Creates a stick-constraint factory (since we want our box to be created 

// using stiff stick-constraints)

Tools.ITwoParticleConstraintFactory lStickConstraintFactory = 
    new Tools.StickConstraintFactory(); 
// Create the box at position (0,0,0), with mass 10.0 and side-length 1.0

Tools.CreateBox(
    new Vector3(0.0f, 0.0f, 0.0f), 
    10.0f, 
    1.0f, 
    lStickConstraintFactory, 
    lTransaction); 
// Commit the added particles and constraints to the system

lTransaction.Commit();

If you want to test what the example looks like, just replace the code in the function InitializeParticleSystem with the code above. Also you have to add the row windEffect = null;

Now let's say you wish to attach a chain to the box and the non moving particle. The code would then look as this:

// Begin a transaction

ParticleSystem.Transaction lTransaction = ps.GetTransaction(); 
// Adds a global constraint to the system (to make sure that the box 

// doesn't fall and fall and fall) 

lTransaction.AddGlobalConstraint(new AxisAlignedBox(
    new Vector3(-10, -15, -10), 
    new Vector3(10, 15, 10))); 
// Set the gravity vector of the system 

ps.Gravity = new Vector3(0, -1, 0); 
// Creates a stick-constraint factory (since we want our box to be created 

// using stiff stick-constraints) 

Tools.ITwoParticleConstraintFactory lStickConstraintFactory = 
    new Tools.StickConstraintFactory(); 
// Create the box at position (0,0,0), with mass 10.0 and side-length 1.0 

Particle[] lBoxParticles = Tools.CreateBox(
    new Vector3(0.0f, 0.0f, 0.0f), 
    10.0f, 
    1.0f, 
    lStickConstraintFactory, 
    lTransaction); 
// Create a single particle 

Particle lParticle = new Particle(1.0f, new Vector3(0.0f, 5.0f, 0.0f)); 
// Make the particle non-moving 

lParticle.Immoveable = true; 
// Add the particle the system 

lTransaction.AddParticle(lParticle); 
// Create a chain between the single particle and a box-particle 

Tools.CreateChain(
    lParticle, 
    lBoxParticles[0], 
    1.0f, 
    6, 
    lStickConstraintFactory, 
    lTransaction); 
// Commit the added particles and constraints to the system 

lTransaction.Commit();

For a more complex example, see the parachuting box code in the ParticleSystemTestApplication.

A tiny introduction to the ParticleSystem project

  • The project is named ParticleSystem. A better name would be ParticleConstraintSystem because that's essentially what it is.
  • The design goal of ParticleSystem was primarily to make it easy for a developer to add new constraints, effects and global constraints classes. Also, I wanted to make it reasonably easy to create "experiments". Performance hasn't been a primary concern.
  • You add instances of particles, constraints, effects and global constraints to a ParticleSystem using the Transaction object. You get an instance of a Transaction object by calling GetTransaction() on an instance of a ParticleSystem. Remember to commit.
  • To generate the next frame, you call TimeStep().
  • You can create own constraints, effects and global constraints by implementing the required interface. For instance, to create a constraint, the object has to implement IConstraint which only has one method: Apply().
  • A reasonable question is what should a constraint do when it gets a call to Apply()? It should check if the constraint is invalid. If its invalid, then it should move the particles that's part of the constraint so that the constraint becomes valid again. As an example, take a look at the StickConstraint; if the particles are too far away, it pulls them together until they are at the correct distance. If they are too close, it pushes them away until they are at the correct distance. It also looks at the mass of the particles and moves differently depending on how much they weigh. Please see 'Advanced Character Physics' [1] for a better insight of how to create constraints.
  • The Tool-class contains a lot of static methods intended to make it easier for a developer.

Exercises for the interested reader:

This is of course an ironical nudge towards the impossible 'exercises for the interested reader' that are so often found in student literature.

  • Implement a 'real' parachute. Instead of having a fixed wind blowing upwards, the particles in the parachute could be affected by a wind that's dependent on average velocity of the particles in the parachute. That is, the faster they are going down, the stronger the wind is blowing upwards.
  • Implement a sailboat game.

TODO:

  • Add NUnit tests
  • Improve the documentation and provide a NDoc project
  • Reengineer the gravity to be a IEffect instead of an intrinsic part of the ParticleSystem-class. This to allow systems where you have a centre of gravity or many gravity sources.
  • Implement collision detection between particles and triangles. This would enable some very cool things such as; solid bodies bouncing against each other, trampolines and friction.

Acknowledgments

Thomas Jakobsen - for without his great article [1], I doubt that I ever would have started playing around with imaginary particles and constraints (and thus leading a lesser life). Also, I have shamelessly robbed code from his article when building ParticleSystem.

References

Change History

  • 2003-12-27 - Article posted.
  • 2003-12-27 - 'Change history' section added.
  • 2003-12-27 - 'About the Author' section removed.
  • 2003-12-30 - Source code and binaries updated 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here