Пример #1
0
        /// <summary>
        /// Orientates the Particle to face the camera, but constrains the particle to always be perpendicular to the
        /// X-Y plane.
        /// </summary>
        /// <param name="cParticle">The Particle to update.</param>
        /// <param name="fElapsedTimeInSeconds">How long it has been since the last update.</param>
        protected void UpdateParticleToBeConstrainedAroundZAxis(DefaultQuadParticle cParticle, float fElapsedTimeInSeconds)
        {
            Vector3 newNormal = CameraPosition - cParticle.Position;

            newNormal.Z      = 0;
            cParticle.Normal = newNormal;
        }
Пример #2
0
        //===========================================================
        // Vertex Update and Overridden Particle System Functions
        //===========================================================

        /// <summary>
        /// Function to update the Vertex properties according to the Particle properties
        /// </summary>
        /// <param name="sVertexBuffer">The array containing the Vertices to be drawn</param>
        /// <param name="iIndex">The Index in the array where the Particle's Vertex info should be placed</param>
        /// <param name="Particle">The Particle to copy the information from</param>
        protected virtual void UpdateVertexProperties(ref DefaultQuadParticleVertex[] sVertexBuffer, int iIndex, DPSFParticle Particle)
        {
            // Cast the Particle to the type it really is
            DefaultQuadParticle cParticle = (DefaultQuadParticle)Particle;

            // Calculate what half of the Quads Width and Height are
            float fHalfWidth  = cParticle.Width / 2.0f;
            float fHalfHeight = cParticle.Height / 2.0f;

            // Calculate the Positions of the Quads corners around the origin
            Vector3 sTopLeft     = new Vector3(-fHalfWidth, -fHalfHeight, 0);
            Vector3 sTopRight    = new Vector3(fHalfWidth, -fHalfHeight, 0);
            Vector3 sBottomLeft  = new Vector3(-fHalfWidth, fHalfHeight, 0);
            Vector3 sBottomRight = new Vector3(fHalfWidth, fHalfHeight, 0);

            // Rotate the Quad corners around the origin according to its Orientation,
            // then calculate their final Positions
            sTopLeft     = Vector3.Transform(sTopLeft, cParticle.Orientation) + cParticle.Position;
            sTopRight    = Vector3.Transform(sTopRight, cParticle.Orientation) + cParticle.Position;
            sBottomLeft  = Vector3.Transform(sBottomLeft, cParticle.Orientation) + cParticle.Position;
            sBottomRight = Vector3.Transform(sBottomRight, cParticle.Orientation) + cParticle.Position;

            // Copy this Particle's renderable Properties to the Vertex Buffer
            // This is a Quad so we must copy all 4 Vertices over
            sVertexBuffer[iIndex].Position = sBottomLeft;
            sVertexBuffer[iIndex].Color    = cParticle.Color;

            sVertexBuffer[iIndex + 1].Position = sTopLeft;
            sVertexBuffer[iIndex + 1].Color    = cParticle.Color;

            sVertexBuffer[iIndex + 2].Position = sBottomRight;
            sVertexBuffer[iIndex + 2].Color    = cParticle.Color;

            sVertexBuffer[iIndex + 3].Position = sTopRight;
            sVertexBuffer[iIndex + 3].Color    = cParticle.Color;

            // Fill in the Index Buffer for the newly added Vertices.
            // Specify the Vertices in Clockwise order.
            // It takes 6 Indices to represent a quad (2 triangles = 6 corners).
            // If we're using the HiDef profile, fill in the regular Index Buffer.
            if (this.GraphicsDevice.GraphicsProfile == GraphicsProfile.HiDef)
            {
                IndexBuffer[IndexBufferIndex++] = iIndex + 1;
                IndexBuffer[IndexBufferIndex++] = iIndex + 2;
                IndexBuffer[IndexBufferIndex++] = iIndex;
                IndexBuffer[IndexBufferIndex++] = iIndex + 1;
                IndexBuffer[IndexBufferIndex++] = iIndex + 3;
                IndexBuffer[IndexBufferIndex++] = iIndex + 2;
            }
            // Else we're using the Reach profile, so fill the Reach Index Buffer instead.
            else
            {
                IndexBufferReach[IndexBufferIndex++] = (short)(iIndex + 1);
                IndexBufferReach[IndexBufferIndex++] = (short)(iIndex + 2);
                IndexBufferReach[IndexBufferIndex++] = (short)(iIndex);
                IndexBufferReach[IndexBufferIndex++] = (short)(iIndex + 1);
                IndexBufferReach[IndexBufferIndex++] = (short)(iIndex + 3);
                IndexBufferReach[IndexBufferIndex++] = (short)(iIndex + 2);
            }
        }
Пример #3
0
 /// <summary>
 /// Update a Particle's Rotational Velocity according to its Rotational Acceleration
 /// </summary>
 /// <param name="cParticle">The Particle to update</param>
 /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param>
 protected void UpdateParticleRotationalVelocityUsingRotationalAcceleration(DefaultQuadParticle cParticle, float fElapsedTimeInSeconds)
 {
     // If Rotational Acceleration is being used
     if (cParticle.RotationalAcceleration != Vector3.Zero)
     {
         // Update the Particle's Rotational Velocity according to its Rotational Acceleration
         cParticle.RotationalVelocity += cParticle.RotationalAcceleration * fElapsedTimeInSeconds;
     }
 }
Пример #4
0
        //===========================================================
        // Initialization Function
        //===========================================================

        /// <summary>
        /// Function to Initialize a Default Particle with default settings
        /// </summary>
        /// <param name="Particle">The Particle to be Initialized</param>
        public override void InitializeParticleUsingInitialProperties(DPSFParticle Particle)
        {
            // Cast the Particle to the type it really is
            DefaultQuadParticle cParticle = (DefaultQuadParticle)Particle;

            // Initialize the Particle according to the values specified in the Initial Settings
            base.InitializeParticleUsingInitialProperties(cParticle, mcInitialProperties);

            // If the Rotation should be interpolated between the Min and Max Rotation
            if (mcInitialProperties.InterpolateBetweenMinAndMaxRotation)
            {
                // Calculate the Particle's initial Rotational values
                Vector3 sRotation = Vector3.Lerp(mcInitialProperties.RotationMin, mcInitialProperties.RotationMax, RandomNumber.NextFloat());
                cParticle.Orientation = Quaternion.CreateFromYawPitchRoll(sRotation.Y, sRotation.X, sRotation.Z);
            }
            // Else the Rotation XYZ values should each be calculated individually
            else
            {
                // Calculate the Particle's initial Rotational values
                Vector3 sRotation = DPSFHelper.RandomVectorBetweenTwoVectors(mcInitialProperties.RotationMin, mcInitialProperties.RotationMax);
                cParticle.Orientation = Quaternion.CreateFromYawPitchRoll(sRotation.Y, sRotation.X, sRotation.Z);
            }

            // If the Rotational Velocity should be interpolated between the Min and Max Rotational Velocities
            if (mcInitialProperties.InterpolateBetweenMinAndMaxRotationalVelocity)
            {
                cParticle.RotationalVelocity = Vector3.Lerp(mcInitialProperties.RotationalVelocityMin, mcInitialProperties.RotationalVelocityMax, RandomNumber.NextFloat());
            }
            // Else the Rotational Velocity XYZ values should each be calculated individually
            else
            {
                cParticle.RotationalVelocity = DPSFHelper.RandomVectorBetweenTwoVectors(mcInitialProperties.RotationalVelocityMin, mcInitialProperties.RotationalVelocityMax);
            }

            // If the Rotational Acceleration should be interpolated between the Min and Max Rotational Acceleration
            if (mcInitialProperties.InterpolateBetweenMinAndMaxRotationalAcceleration)
            {
                cParticle.RotationalAcceleration = Vector3.Lerp(mcInitialProperties.RotationalAccelerationMin, mcInitialProperties.RotationalAccelerationMax, RandomNumber.NextFloat());
            }
            // Else the Rotational Acceleration XYZ values should each be calculated individually
            else
            {
                cParticle.RotationalAcceleration = DPSFHelper.RandomVectorBetweenTwoVectors(mcInitialProperties.RotationalAccelerationMin, mcInitialProperties.RotationalAccelerationMax);
            }

            // Calculate the Particle's Width and Height values
            cParticle.StartWidth  = DPSFHelper.RandomNumberBetween(mcInitialProperties.StartSizeMin > 0 ? mcInitialProperties.StartSizeMin : mcInitialProperties.StartWidthMin, mcInitialProperties.StartSizeMax > 0 ? mcInitialProperties.StartSizeMax : mcInitialProperties.StartWidthMax);
            cParticle.EndWidth    = DPSFHelper.RandomNumberBetween(mcInitialProperties.EndSizeMin > 0 ? mcInitialProperties.EndSizeMin : mcInitialProperties.EndWidthMin, mcInitialProperties.EndSizeMax > 0 ? mcInitialProperties.EndSizeMax : mcInitialProperties.EndWidthMax);
            cParticle.StartHeight = DPSFHelper.RandomNumberBetween(mcInitialProperties.StartSizeMin > 0 ? mcInitialProperties.StartSizeMin : mcInitialProperties.StartHeightMin, mcInitialProperties.StartSizeMax > 0 ? mcInitialProperties.StartSizeMax : mcInitialProperties.StartHeightMax);
            cParticle.EndHeight   = DPSFHelper.RandomNumberBetween(mcInitialProperties.EndSizeMin > 0 ? mcInitialProperties.EndSizeMin : mcInitialProperties.EndHeightMin, mcInitialProperties.EndSizeMax > 0 ? mcInitialProperties.EndSizeMax : mcInitialProperties.EndHeightMax);
            cParticle.Width       = cParticle.StartWidth;
            cParticle.Height      = cParticle.StartHeight;
        }
Пример #5
0
        //===========================================================
        // Particle Update Functions
        //===========================================================

        /// <summary>
        /// Update a Particle's Rotation according to its Rotational Velocity
        /// </summary>
        /// <param name="cParticle">The Particle to update</param>
        /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param>
        protected void UpdateParticleRotationUsingRotationalVelocity(DefaultQuadParticle cParticle, float fElapsedTimeInSeconds)
        {
            // Update the Particle's Rotation according to its Rotational Velocity
            // If Rotational Velocity is being used
            if (cParticle.RotationalVelocity != Vector3.Zero)
            {
                // Quaternion Rotation Formula: NewOrientation = OldNormalizedOrientation * Rotation(v*t) * 0.5,
                // where v is the angular(rotational) velocity vector, and t is the amount of time elapsed.
                // The 0.5 is used to scale the rotation so that Pi = 180 degree rotation
                cParticle.Orientation.Normalize();
                Quaternion sRotation = new Quaternion(cParticle.RotationalVelocity * (fElapsedTimeInSeconds * 0.5f), 0);
                cParticle.Orientation += cParticle.Orientation * sRotation;
            }
        }
Пример #6
0
        //===========================================================
        // Particle System Update Functions
        //===========================================================

        /// <summary>
        /// Sorts the particles to draw particles furthest from the camera first, in order to achieve proper depth perspective.
        ///
        /// <para>NOTE: This operation is very expensive and should only be used when you are
        /// drawing particles with both opaque and semi-transparent portions, and not using additive blending.</para>
        /// <para>Merge Sort is the sorting algorithm used, as it tends to be best for linked lists.
        /// TODO - WHILE MERGE SORT SHOULD BE USED, DUE TO TIME CONSTRAINTS A (PROBABLY) SLOWER METHOD (QUICK-SORT)
        /// IS BEING USED INSTEAD. THIS FUNCTION NEEDS TO BE UPDATED TO USE MERGE SORT STILL.
        /// THE LINKED LIST MERGE SORT ALGORITHM CAN BE FOUND AT http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html</para>
        /// </summary>
        /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param>
        protected void UpdateParticleSystemToSortParticlesByDistanceFromCamera(float fElapsedTimeInSeconds)
        {
            // Store the Number of Active Particles to sort
            int iNumberOfActiveParticles = ActiveParticles.Count;

            // If there is nothing to sort
            if (iNumberOfActiveParticles <= 1)
            {
                // Exit without sorting
                return;
            }

            // Create a List to put the Active Particles in to be sorted
            List <Particle> cActiveParticleList = new List <Particle>(iNumberOfActiveParticles);

            // Add all of the Particles to the List
            LinkedListNode <Particle> cNode = ActiveParticles.First;

            while (cNode != null)
            {
                // Copy this Particle into the Array
                cActiveParticleList.Add(cNode.Value);

                // Move to the next Active Particle
                cNode = cNode.Next;
            }

            // Now that the List is full, sort it
            cActiveParticleList.Sort(delegate(Particle Particle1, Particle Particle2)
            {
                DefaultQuadParticle cParticle1 = (DefaultQuadParticle)(DPSFParticle)Particle1;
                DefaultQuadParticle cParticle2 = (DefaultQuadParticle)(DPSFParticle)Particle2;
                return(cParticle1.DistanceFromCameraSquared.CompareTo(cParticle2.DistanceFromCameraSquared));
            });

            // Now that the List is sorted, add the Particles into the Active Particles Linked List in sorted order
            ActiveParticles.Clear();
            for (int iIndex = 0; iIndex < iNumberOfActiveParticles; iIndex++)
            {
                // Add this Particle to the Active Particles Linked List.
                // List is sorted from smallest to largest, but we want
                // our Linked List sorted from largest to smallest, since
                // the Particles at the end of the Linked List are drawn last.
                ActiveParticles.AddFirst(cActiveParticleList[iIndex]);
            }
        }
Пример #7
0
        /// <summary>
        /// Deep copy all of the Particle properties
        /// </summary>
        /// <param name="ParticleToCopy">The Particle to Copy the properties from</param>
        public override void CopyFrom(DPSFParticle ParticleToCopy)
        {
            // Cast the Particle to the type it really is
            DefaultQuadParticle cParticleToCopy = (DefaultQuadParticle)ParticleToCopy;

            base.CopyFrom(cParticleToCopy);
            this.Orientation            = cParticleToCopy.Orientation;
            this.RotationalVelocity     = cParticleToCopy.RotationalVelocity;
            this.RotationalAcceleration = cParticleToCopy.RotationalAcceleration;
            this.Width       = cParticleToCopy.Width;
            this.Height      = cParticleToCopy.Height;
            this.StartHeight = cParticleToCopy.StartHeight;
            this.StartWidth  = cParticleToCopy.StartWidth;
            this.EndHeight   = cParticleToCopy.EndHeight;
            this.EndWidth    = cParticleToCopy.EndWidth;
            this.DistanceFromCameraSquared = cParticleToCopy.DistanceFromCameraSquared;
        }
Пример #8
0
 /// <summary>
 /// Updates the Particle's DistanceFromCameraSquared property to reflect how far this Particle is from the Camera.
 /// </summary>
 /// <param name="cParticle">The Particle to update.</param>
 /// <param name="fElapsedTimeInSeconds">How long it has been since the last update.</param>
 protected void UpdateParticleDistanceFromCameraSquared(DefaultQuadParticle cParticle, float fElapsedTimeInSeconds)
 {
     cParticle.DistanceFromCameraSquared = Vector3.DistanceSquared(this.CameraPosition, cParticle.Position);
 }
Пример #9
0
 /// <summary>
 /// Turns the Particle into a Billboard Particle (i.e. The Particle always faces the Camera).
 /// <para>NOTE: This Update function should be called after all other Update functions to ensure that
 /// the Particle is orientated correctly.</para>
 /// <para>NOTE: Update the Particle System's Camera Position every frame to ensure that this works correctly.</para>
 /// <para>NOTE: Only Roll Rotations (i.e. around the Z axis) will be visible when this is used.</para>
 /// </summary>
 /// <param name="cParticle">The Particle to update.</param>
 /// <param name="fElapsedTimeInSeconds">How long it has been since the last update.</param>
 protected void UpdateParticleToFaceTheCamera(DefaultQuadParticle cParticle, float fElapsedTimeInSeconds)
 {
     // Make the Particle face the Camera
     cParticle.Normal = CameraPosition - cParticle.Position;
 }
Пример #10
0
 /// <summary>
 /// Linearly interpolate the Particle's Width and Height between the Start and End values according
 /// to the Particle's Normalized Lifetime
 /// </summary>
 /// <param name="cParticle">The Particle to update</param>
 /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param>
 protected void UpdateParticleWidthAndHeightUsingLerp(DefaultQuadParticle cParticle, float fElapsedTimeInSeconds)
 {
     // Calculate the Particle's new Width and Height
     cParticle.Width  = MathHelper.Lerp(cParticle.StartWidth, cParticle.EndWidth, cParticle.NormalizedElapsedTime);
     cParticle.Height = MathHelper.Lerp(cParticle.StartHeight, cParticle.EndHeight, cParticle.NormalizedElapsedTime);
 }
Пример #11
0
 /// <summary>
 /// Update a Particle's Rotation and Rotational Velocity according to its Rotational Acceleration
 /// </summary>
 /// <param name="cParticle">The Particle to update</param>
 /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param>
 protected void UpdateParticleRotationAndRotationalVelocityUsingRotationalAcceleration(DefaultQuadParticle cParticle, float fElapsedTimeInSeconds)
 {
     // Update the Particle's Rotational Velocity and Rotation according to its Rotational Acceleration
     UpdateParticleRotationalVelocityUsingRotationalAcceleration(cParticle, fElapsedTimeInSeconds);
     UpdateParticleRotationUsingRotationalVelocity(cParticle, fElapsedTimeInSeconds);
 }
Пример #12
0
        //===========================================================
        // Vertex Update and Overridden Particle System Functions
        //===========================================================

        /// <summary>
        /// Function to update the Vertex properties according to the Particle properties
        /// </summary>
        /// <param name="sVertexBuffer">The array containing the Vertices to be drawn</param>
        /// <param name="iIndex">The Index in the array where the Particle's Vertex info should be placed</param>
        /// <param name="Particle">The Particle to copy the information from</param>
        protected virtual void UpdateVertexProperties(ref DefaultQuadParticleVertex[] sVertexBuffer, int iIndex, DPSFParticle Particle)
        {
            // Cast the Particle to the type it really is
            DefaultQuadParticle cParticle = (DefaultQuadParticle)Particle;

            // Calculate what half of the Quads Width and Height are
            float fHalfWidth  = cParticle.Width / 2.0f;
            float fHalfHeight = cParticle.Height / 2.0f;

            // Calculate the Positions of the Quads corners around the origin
            Vector3 sTopLeft     = new Vector3(-fHalfWidth, -fHalfHeight, 0);
            Vector3 sTopRight    = new Vector3(fHalfWidth, -fHalfHeight, 0);
            Vector3 sBottomLeft  = new Vector3(-fHalfWidth, fHalfHeight, 0);
            Vector3 sBottomRight = new Vector3(fHalfWidth, fHalfHeight, 0);

            // Rotate the Quad corners around the origin according to its Orientation,
            // then calculate their final Positions
            sTopLeft     = Vector3.Transform(sTopLeft, cParticle.Orientation) + cParticle.Position;
            sTopRight    = Vector3.Transform(sTopRight, cParticle.Orientation) + cParticle.Position;
            sBottomLeft  = Vector3.Transform(sBottomLeft, cParticle.Orientation) + cParticle.Position;
            sBottomRight = Vector3.Transform(sBottomRight, cParticle.Orientation) + cParticle.Position;

            // Effect expects a premultiplied color, so get the actual color to use.
            Color premultipliedColor = cParticle.ColorAsPremultiplied;

            // Copy this Particle's renderable Properties to the Vertex Buffer
            // This is a Quad so we must copy all 4 Vertices over
            sVertexBuffer[iIndex].Position = sBottomLeft;
            sVertexBuffer[iIndex].Color    = premultipliedColor;

            sVertexBuffer[iIndex + 1].Position = sTopLeft;
            sVertexBuffer[iIndex + 1].Color    = premultipliedColor;

            sVertexBuffer[iIndex + 2].Position = sBottomRight;
            sVertexBuffer[iIndex + 2].Color    = premultipliedColor;

            sVertexBuffer[iIndex + 3].Position = sTopRight;
            sVertexBuffer[iIndex + 3].Color    = premultipliedColor;

            // Fill in the Index Buffer for the newly added Vertices.
            // Specify the Vertices in Clockwise order.
            // It takes 6 Indices to represent a quad (2 triangles = 6 corners).
            // If we should be using the 32-bit Integer Index Buffer, fill it.
            if (this.IsUsingIntegerIndexBuffer)
            {
                IndexBuffer[IndexBufferIndex++] = iIndex + 1;
                IndexBuffer[IndexBufferIndex++] = iIndex + 2;
                IndexBuffer[IndexBufferIndex++] = iIndex;
                IndexBuffer[IndexBufferIndex++] = iIndex + 1;
                IndexBuffer[IndexBufferIndex++] = iIndex + 3;
                IndexBuffer[IndexBufferIndex++] = iIndex + 2;
            }
            // Else we should be using the 16-bit Short Index Buffer.
            else
            {
                IndexBufferShort[IndexBufferIndex++] = (short)(iIndex + 1);
                IndexBufferShort[IndexBufferIndex++] = (short)(iIndex + 2);
                IndexBufferShort[IndexBufferIndex++] = (short)(iIndex);
                IndexBufferShort[IndexBufferIndex++] = (short)(iIndex + 1);
                IndexBufferShort[IndexBufferIndex++] = (short)(iIndex + 3);
                IndexBufferShort[IndexBufferIndex++] = (short)(iIndex + 2);
            }
        }