📄 tool.cs
字号:
using System;
using System.Collections;
using Microsoft.DirectX;
namespace ParticleSystems
{
namespace Verlet
{
namespace Tools
{
/// <summary>
/// Tools contains a lot of help functions intended to make it
/// easier for the experimenting developer.
/// </summary>
public class Tools
{
static private Random mRandom = new Random();
private Tools()
{
}
/// <summary>
/// Generates a random number that lies within a limit
/// </summary>
/// <param name="min">The lower limit</param>
/// <param name="max">The upper limit</param>
/// <returns>A random number</returns>
public static float GetRandomNumber(float min, float max)
{
return (max - min) * (float)mRandom.NextDouble() + min;
}
/// <summary>
/// Generates a random number between -1 and 1
/// </summary>
/// <returns>A random number</returns>
public static float GetNormalizedRandomNumber()
{
return GetRandomNumber(-1.0f, 1.0f);
}
/// <summary>
/// Generates a normalized random vector;
/// </summary>
/// <returns>A normalized random vector</returns>
public static Vector3 GetNormalizedRandomVector()
{
Vector3 lVector = new Vector3(
GetNormalizedRandomNumber(),
GetNormalizedRandomNumber(),
GetNormalizedRandomNumber());
lVector.Normalize();
return lVector;
}
/// <summary>
/// Generates a random vector of a specified length
/// </summary>
/// <param name="length">Length of random vector</param>
/// <returns>A random vector of specified length</returns>
public static Vector3 RandomVector(float length)
{
Vector3 lVector = GetNormalizedRandomVector();
lVector.Multiply(length);
return lVector;
}
/// <summary>
/// Gives each particle in a particle system a random increase
/// of velocity in a random direction
/// </summary>
/// <param name="maxVelocity">Maximum speed increase</param>
/// <param name="ps">A particle system</param>
public static void Shake(
float maxVelocity,
ParticleSystem ps)
{
float lTimeDelta = ps.TimeDelta;
Particle[] lParticles = ps.Particles;
foreach(Particle lParticle in lParticles)
{
lParticle.IncreaseVelocity(
lTimeDelta,
RandomVector(
maxVelocity * GetNormalizedRandomNumber()));
}
}
/// <summary>
/// ITwoParticleConstraintFactory is used by some of the
/// algorithms in Tools to give a developer the possibilty
/// of controlling what constraints should be created by the
/// algorithm
/// </summary>
public interface ITwoParticleConstraintFactory
{
/// <summary>
/// Creates a constraint between two particles and append
/// it too the particle system using the transaction
/// </summary>
/// <param name="transaction">A transaction</param>
/// <param name="particle1">A particle</param>
/// <param name="particle2">A particle</param>
void CreateConstraint(
ParticleSystem.Transaction transaction,
Particle particle1,
Particle particle2);
}
/// <summary>
/// StickConstraintFactory is an implementation of
/// ITwoParticleConstraintFactory that creates stick constraints
/// </summary>
public class StickConstraintFactory : ITwoParticleConstraintFactory
{
/// <summary>
/// Constructor
/// </summary>
public StickConstraintFactory()
{
}
/// <summary>
/// Creates a constraint between two particles and append
/// it too the particle system using the transaction
/// </summary>
/// <param name="transaction">A transaction</param>
/// <param name="particle1">A particle</param>
/// <param name="particle2">A particle</param>
public void CreateConstraint(
ParticleSystem.Transaction transaction,
Particle particle1,
Particle particle2)
{
transaction.AddConstraint(
new Constraints.Stick(particle1, particle2));
}
}
/// <summary>
/// RopeConstraintFactory is an implementation of
/// ITwoParticleConstraintFactory that creates rope constraints.
/// </summary>
public class RopeConstraintFactory : ITwoParticleConstraintFactory
{
/// <summary>
/// Constructor
/// </summary>
public RopeConstraintFactory()
{
mScale = 1.0f;
}
/// <summary>
/// Constructor for a RopeConstraintFactory that create
/// Rope constraints that are enlonged by scale parameter
/// </summary>
/// <param name="scale">scale must be larger or equal to 1.0f</param>
public RopeConstraintFactory(float scale)
{
mScale = scale;
}
/// <summary>
/// Creates a constraint between two particles and append
/// it too the particle system using the transaction
/// </summary>
/// <param name="transaction">A transaction</param>
/// <param name="particle1">A particle</param>
/// <param name="particle2">A particle</param>
public void CreateConstraint(
ParticleSystem.Transaction transaction,
Particle particle1,
Particle particle2)
{
transaction.AddConstraint(
new Constraints.Rope(mScale, particle1, particle2));
}
private float mScale;
}
/// <summary>
/// SoftStickConstraintFactory is an implementation of
/// ITwoParticleConstraintFactory that creates soft stick
/// constraints.
/// </summary>
public class SoftStickConstraintFactory : ITwoParticleConstraintFactory
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="stiffness">Must be be between 0.0f and 1.0f</param>
public SoftStickConstraintFactory(float stiffness)
{
mStiffness = stiffness;
}
/// <summary>
/// Creates a constraint between two particles and append
/// it too the particle system using the transaction
/// </summary>
/// <param name="transaction">A transaction</param>
/// <param name="particle1">A particle</param>
/// <param name="particle2">A particle</param>
public void CreateConstraint(
ParticleSystem.Transaction transaction,
Particle particle1,
Particle particle2)
{
Constraints.SoftStick lSoftStick =
new Constraints.SoftStick(mStiffness, particle1, particle2);
transaction.AddConstraint(lSoftStick);
transaction.AddEffect(lSoftStick);
}
private float mStiffness;
}
private static void AddParticlesToTransaction(
ArrayList particles,
ParticleSystem.Transaction transaction)
{
foreach(Particle lParticle in particles)
{
transaction.AddParticle(lParticle);
}
}
private static Particle[] ConvertArrayListToParticleList(
ArrayList particles)
{
Particle[] lParticles = new Particle[particles.Count];
particles.CopyTo(lParticles);
return lParticles;
}
/// <summary>
/// Creates a chain of particles and constraints between two
/// particles
/// </summary>
/// <param name="particle1">A particle</param>
/// <param name="particle2">A particle</param>
/// <param name="mass">The mass of the chain</param>
/// <param name="links">How many links in chain</param>
/// <param name="constraintFactory">A constraint factory</param>
/// <param name="transaction">A transaction</param>
/// <returns></returns>
public static Particle[] CreateChain(
Particle particle1,
Particle particle2,
float mass,
int links,
ITwoParticleConstraintFactory constraintFactory,
ParticleSystem.Transaction transaction)
{
if( !(mass > float.Epsilon) )
{
throw new Exception("mass parameter must be greater than 0");
}
if( links < 1 )
{
throw new Exception("links parameter must be greater than 0");
}
ArrayList lCreatedParticles = new ArrayList();
float lMass = mass / links;
Particle lPreviousParticle = particle1;
Vector3 lStep = (particle2.Position - particle1.Position);
lStep.Scale(1.0f / (float)links);
for( int lIter = 0; lIter < links - 1; ++lIter )
{
Vector3 lNext = lPreviousParticle.Position + lStep;
Particle lNextParticle = new Particle(
lMass,
lNext);
lCreatedParticles.Add(lNextParticle);
constraintFactory.CreateConstraint(
transaction,
lPreviousParticle,
lNextParticle);
lPreviousParticle = lNextParticle;
}
constraintFactory.CreateConstraint(
transaction,
lPreviousParticle,
particle2);
AddParticlesToTransaction(lCreatedParticles, transaction);
return ConvertArrayListToParticleList(lCreatedParticles);
}
/// <summary>
/// Enables a developer to modify particles created by some
/// algorithms in Tools before constraints are created.
/// Originally I thought a transform matrix would be enough
/// but I later realized I wanted to do non-linear transforms
/// </summary>
public interface IParticlePreProcessor
{
/// <summary>
/// Applies the preproccessor on a set of particles
/// </summary>
/// <param name="particles">A set of particles</param>
void Apply(ArrayList particles);
}
/// <summary>
/// Base class for particle pre processors that shall be
/// chainable
/// </summary>
public abstract class ChainableParticlePreProcessor : IParticlePreProcessor
{
/// <summary>
/// Constructor
/// </summary>
public ChainableParticlePreProcessor()
{
mNextPreProcessor = null;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="nextPreProcessor">next preprocessor in the chain</param>
public ChainableParticlePreProcessor(IParticlePreProcessor nextPreProcessor)
{
mNextPreProcessor = nextPreProcessor;
}
/// <summary>
/// Applies the preproccessor on a set of particles
/// </summary>
/// <param name="particles">A set of particles</param>
public void Apply(ArrayList particles)
{
ApplyThisPreProcessor(particles);
if( mNextPreProcessor != null )
{
mNextPreProcessor.Apply(particles);
}
}
/// <summary>
/// Abstract method. Inheritors should implement this to
/// apply their preprocessing step
/// </summary>
/// <param name="particles"></param>
protected abstract void ApplyThisPreProcessor(ArrayList particles);
private IParticlePreProcessor mNextPreProcessor;
}
/// <summary>
/// Does a null transform
/// </summary>
public class NullParticlePreProcessor : ChainableParticlePreProcessor
{
/// <summary>
/// Constructor
/// </summary>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -