⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 particlesystem.cs

📁 Particle System Test Application on C#
💻 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 + -