📄 particlesystem.cs
字号:
using System;
using System.Collections;
using Microsoft.DirectX;
namespace ParticleSystems
{
namespace Verlet
{
/// <summary>
/// An effect is applied once each timestep. An example of an effect
/// is a wind effect that applies a random force to a collection of
/// particles
/// </summary>
public interface IEffect
{
/// <summary>
/// Applies the effect
/// </summary>
/// <param name="timeDelta">The timedelta used by the particle system this iteration</param>
void Apply(float timeDelta);
}
/// <summary>
/// A global constraint is a constraint that should be applied to all
/// particles once each relax iteration. An example of a global
/// constraint is an axis aligned box which ensures that all particles
/// are inside an axis aligned box
/// </summary>
public interface IGlobalConstraint
{
/// <summary>
/// Applies the global constraint to all particles in the list
/// </summary>
/// <param name="particles">An array of particles</param>
void Apply(Particle[] particles);
}
/// <summary>
/// A constraint maintains a relationship between two or more particles
/// and is applied once relax iteration. An example of a constraint is
/// the stick constraint which ensures that the distance between two
/// particles stays constant
/// </summary>
public interface IConstraint
{
/// <summary>
/// Applies the constraint
/// </summary>
void Apply();
}
/// <summary>
/// ParticleSystem is a set of operations where the most important are
/// ability to add particles, constraints and global constraints and
/// move all particles forward in time (timestep)
/// </summary>
public class ParticleSystem
{
/// <summary>
/// Transaction are used to for instance add particles to the
/// particle system.
/// There are a numerous reasons I created Transaction. A minor
/// reason is that I like the commit/rollback pattern. But the major
/// reason is that when I started using fixed-size arrays in the
/// particle system I needed another way to append changes
/// effeciently. Transaction solves this.
/// </summary>
public class Transaction
{
internal Transaction(ParticleSystem ps)
{
mParticleSystem = ps;
}
/// <summary>
/// Adds an effect to the transaction
/// </summary>
/// <param name="e">An effect</param>
public void AddEffect(IEffect e)
{
mNewEffects.Add(e);
}
/// <summary>
/// Adds a global constraint the transaction
/// </summary>
/// <param name="gc">A global constraint</param>
public void AddGlobalConstraint(IGlobalConstraint gc)
{
mNewGlobalConstraints.Add(gc);
}
/// <summary>
/// Adds a constraint to the transaction
/// </summary>
/// <param name="c">A constraint</param>
public void AddConstraint(IConstraint c)
{
mNewConstraints.Add(c);
}
/// <summary>
/// Adds a particle to the transaction
/// </summary>
/// <param name="p">A particle</param>
public void AddParticle(Particle p)
{
mNewParticles.Add(p);
}
private Array CreateArray(
Array originalElements,
ArrayList newElements,
Type typeOfElement)
{
Array lNewArray = Array.CreateInstance(
typeOfElement,
originalElements.Length + newElements.Count);
originalElements.CopyTo(lNewArray, 0);
newElements.CopyTo(lNewArray, originalElements.Length);
return lNewArray;
}
/// <summary>
/// Commits all the changes into the particle system
/// </summary>
public void Commit()
{
Particle[] lParticles = null;
IConstraint[] lConstraints = null;
IGlobalConstraint[] lGlobalConstraints = null;
IEffect[] lEffects = null;
if( mNewParticles.Count > 0 )
{
lParticles = (Particle[])CreateArray(
mParticleSystem.mParticles,
mNewParticles,
typeof(Particle));
}
if( mNewConstraints.Count > 0 )
{
lConstraints = (IConstraint[])CreateArray(
mParticleSystem.mConstraints,
mNewConstraints,
typeof(IConstraint));
}
if( mNewGlobalConstraints.Count > 0 )
{
lGlobalConstraints = (IGlobalConstraint[])CreateArray(
mParticleSystem.mGlobalConstraints,
mNewGlobalConstraints,
typeof(IGlobalConstraint));
}
if( mNewEffects.Count > 0 )
{
lEffects = (IEffect[])CreateArray(
mParticleSystem.mEffects,
mNewEffects,
typeof(IEffect));
}
if( lParticles != null )
{
mParticleSystem.mParticles = lParticles;
}
if( lConstraints != null )
{
mParticleSystem.mConstraints = lConstraints;
}
if( lGlobalConstraints != null )
{
mParticleSystem.mGlobalConstraints = lGlobalConstraints;
}
if( lEffects != null )
{
mParticleSystem.mEffects = lEffects;
}
mParticleSystem = null;
mNewParticles = null;
mNewConstraints = null;
mNewGlobalConstraints = null;
mNewEffects = null;
}
/// <summary>
/// Rollbacks changes
/// </summary>
public void Rollback()
{
mParticleSystem = null;
mNewParticles = null;
mNewConstraints = null;
mNewGlobalConstraints = null;
mNewEffects = null;
}
ParticleSystem mParticleSystem;
ArrayList mNewParticles = new ArrayList();
ArrayList mNewConstraints = new ArrayList();
ArrayList mNewGlobalConstraints = new ArrayList();
ArrayList mNewEffects = new ArrayList();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="timeDelta">The timeDelta the particle system
/// should initialized with</param>
public ParticleSystem(float timeDelta)
{
// SquareRoot Epsilon since we will square timeDelta later
if( !(timeDelta > (float)Math.Sqrt(float.Epsilon)) )
{
throw new Exception("timeDelta parameter must be larger than 0.0");
}
mTimeDelta = timeDelta;
mEffects = new IEffect[0];
mGlobalConstraints = new IGlobalConstraint[0];
mConstraints = new IConstraint[0];
mParticles = new Particle[0];
mGravity = new Vector3();
}
/// <summary>
/// Retrieves a transaction
/// </summary>
/// <returns>An transaction</returns>
public Transaction GetTransaction()
{
return new Transaction(this);
}
/// <summary>
/// Applies the effects, moves all particles forward in time and
/// relaxes the constraints
/// </summary>
/// <param name="relaxIterations"></param>
public void TimeStep(long relaxIterations)
{
ApplyEffects(mTimeDelta);
VerletIntergration(mTimeDelta);
RelaxConstraints(relaxIterations);
}
/// <summary>
/// All the effects in the particle system
/// </summary>
public IEffect[] Effects
{
get
{
return (IEffect[])mEffects.Clone();
}
}
/// <summary>
/// All the global constraints in the particle system
/// </summary>
public IGlobalConstraint[] GlobalConstraints
{
get
{
return (IGlobalConstraint[])mGlobalConstraints.Clone();
}
}
/// <summary>
/// All the constraints in the particle system
/// </summary>
public IConstraint[] Constraints
{
get
{
return (IConstraint[])mConstraints.Clone();
}
}
/// <summary>
/// All the particles in the particle system
/// </summary>
public Particle[] Particles
{
get
{
return (Particle[])mParticles.Clone();
}
}
/// <summary>
/// Gravity vector used by the particle system
/// </summary>
public Vector3 Gravity
{
get
{
return mGravity;
}
set
{
mGravity = value;
}
}
/// <summary>
/// Time delta used by the particle system
/// </summary>
public float TimeDelta
{
// The Set part is not trivial since the set should
// update the previous position of all particles to preserve
// the speed
get
{
return mTimeDelta;
}
}
private void ApplyEffects(float timeDelta)
{
int lIter = 0;
int lLength = mEffects.Length;
for(; lIter < lLength; ++lIter)
{
mEffects[lIter].Apply(timeDelta);
}
}
private void VerletIntegration(
Particle particle,
Vector3 timeDeltaSquaredMultipledWithGravity)
{
if( !particle.mImmoveable )
{
/*
lNewPosition = 2 * particle.mCurrentPosition - particle.mPreviousPosition +
timeDeltaSquaredMultipledWithGravity;
*/
Vector3 lTmpVector = timeDeltaSquaredMultipledWithGravity;
lTmpVector.Add(particle.mCurrentPosition);
lTmpVector.Add(particle.mCurrentPosition);
lTmpVector.Subtract(particle.mPreviousPosition);
particle.mPreviousPosition = particle.mCurrentPosition;
particle.mCurrentPosition = lTmpVector;
}
else
{
particle.mPreviousPosition = particle.mCurrentPosition;
}
}
private void VerletIntergration(float timeDelta)
{
float lTimeDeltaSquared = timeDelta * timeDelta;
Vector3 lTimeDeltaSquaredMultipledWithGravity =
lTimeDeltaSquared * mGravity;
int lIter = 0;
int lLength = mParticles.Length;
for(; lIter < lLength; ++lIter)
{
VerletIntegration(
mParticles[lIter],
lTimeDeltaSquaredMultipledWithGravity);
}
}
private void RelaxConstraints(long relaxIterations)
{
for(long lIterations = 0; lIterations < relaxIterations; ++lIterations)
{
{
int lIter = 0;
int lLength = mGlobalConstraints.Length;
for(; lIter < lLength; ++lIter)
{
mGlobalConstraints[lIter].Apply(mParticles);
}
}
{
int lIter = 0;
int lLength = mConstraints.Length;
for(; lIter < lLength; ++lIter)
{
mConstraints[lIter].Apply();
}
}
}
}
private float mTimeDelta;
private IEffect[] mEffects;
private IGlobalConstraint[] mGlobalConstraints;
private IConstraint[] mConstraints;
private Particle[] mParticles;
private Vector3 mGravity;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -