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.
ParticleSystem.Transaction lTransaction = ps.GetTransaction();
lTransaction.AddGlobalConstraint(new AxisAlignedBox(
new Vector3(-10, -15, -10),
new Vector3(10, 15, 10)));
ps.Gravity = new Vector3(0, -1, 0);
Tools.ITwoParticleConstraintFactory lStickConstraintFactory =
new Tools.StickConstraintFactory();
Tools.CreateBox(
new Vector3(0.0f, 0.0f, 0.0f),
10.0f,
1.0f,
lStickConstraintFactory,
lTransaction);
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:
ParticleSystem.Transaction lTransaction = ps.GetTransaction();
lTransaction.AddGlobalConstraint(new AxisAlignedBox(
new Vector3(-10, -15, -10),
new Vector3(10, 15, 10)));
ps.Gravity = new Vector3(0, -1, 0);
Tools.ITwoParticleConstraintFactory lStickConstraintFactory =
new Tools.StickConstraintFactory();
Particle[] lBoxParticles = Tools.CreateBox(
new Vector3(0.0f, 0.0f, 0.0f),
10.0f,
1.0f,
lStickConstraintFactory,
lTransaction);
Particle lParticle = new Particle(1.0f, new Vector3(0.0f, 5.0f, 0.0f));
lParticle.Immoveable = true;
lTransaction.AddParticle(lParticle);
Tools.CreateChain(
lParticle,
lBoxParticles[0],
1.0f,
6,
lStickConstraintFactory,
lTransaction);
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