protected void UpdateParticleTransparencyWithQuickFadeOut(DPSFDefaultBaseParticle cParticle, float fElapsedTimeInSeconds) { // Calculate how transparent the Particle should be and apply it byte bAlpha = DPSFHelper.FadeOutQuicklyBasedOnLifetime(cParticle.NormalizedElapsedTime); cParticle.Color = new Color(cParticle.Color.R, cParticle.Color.G, cParticle.Color.B, bAlpha); }
/// <summary> /// Resets each of the render properties to their default values. /// </summary> public void ResetToDefaults() { // Clone the states instead of just setting to them directly so that they are not read-only and we can change their properties. this.BlendState = DPSFHelper.CloneBlendState(BlendState.AlphaBlend); this.DepthStencilState = DPSFHelper.CloneDepthStencilState(DepthStencilState.DepthRead); this.RasterizerState = DPSFHelper.CloneRasterizerState(RasterizerState.CullCounterClockwise); this.SamplerState = DPSFHelper.CloneSamplerState(SamplerState.LinearClamp); }
//=========================================================== // 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; }
//=========================================================== // Initialization Function //=========================================================== /// <summary> /// Function to Initialize a Default Particle with default Properties /// </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 DefaultSpriteParticle cParticle = (DefaultSpriteParticle)Particle; // Initialize the Particle according to the values specified in the Initial Settings base.InitializeParticleUsingInitialProperties(cParticle, mcInitialProperties); // Calculate the Particle's Rotation values cParticle.Rotation = DPSFHelper.RandomNumberBetween(mcInitialProperties.RotationMin, mcInitialProperties.RotationMax); cParticle.RotationalVelocity = DPSFHelper.RandomNumberBetween(mcInitialProperties.RotationalVelocityMin, mcInitialProperties.RotationalVelocityMax); cParticle.RotationalAcceleration = DPSFHelper.RandomNumberBetween(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; }
/// <summary> /// Function to setup the Render Properties (i.e. BlendState, DepthStencilState, RasterizerState, and SamplerState) /// which will be applied to the Graphics Device before drawing the Particle System's Particles. /// <para>This function is called when initializing the particle system.</para> /// </summary> protected override void InitializeRenderProperties() { // We use the Alpha Test Effect by default for 3D Sprites this.Effect = new AlphaTestEffect(this.GraphicsDevice); RenderProperties.RasterizerState = DPSFHelper.CloneRasterizerState(RasterizerState.CullNone); }
/// <summary> /// Function to setup the Render Properties (i.e. BlendState, DepthStencilState, RasterizerState, and SamplerState) /// which will be applied to the Graphics Device before drawing the Particle System's Particles. /// <para>This function is called when initializing the particle system.</para> /// </summary> protected override void InitializeRenderProperties() { // Use the NonPremultiplied BlendState by default for Sprite particles so that transparency is drawn. RenderProperties.BlendState = DPSFHelper.CloneBlendState(BlendState.NonPremultiplied); }
/// <summary> /// Returns the vector force that a Magnet should exert on a Particle /// </summary> /// <param name="cMagnet">The Magnet affecting the Particle</param> /// <param name="cParticle">The Particle being affected by the Magnet</param> /// <returns>Returns the vector force that a Magnet should exert on a Particle</returns> protected Vector3 CalculateForceMagnetShouldExertOnParticle(DefaultParticleSystemMagnet cMagnet, DPSFDefaultBaseParticle cParticle) { // Variable to store the Force to Exert on the Particle Vector3 sForceToExertOnParticle = Vector3.Zero; // Calculate which Direction to push the Particle Vector3 sDirectionToPushParticle; // If this is a Point Magnet if (cMagnet.MagnetType == DefaultParticleSystemMagnet.MagnetTypes.PointMagnet) { // Cast the Magnet to the proper type MagnetPoint cPointMagnet = (MagnetPoint)cMagnet; // Calculate the direction to attract the Particle to the point in space where the Magnet is sDirectionToPushParticle = cPointMagnet.PositionData.Position - cParticle.Position; } // Else If this is a Line Magnet else if (cMagnet.MagnetType == DefaultParticleSystemMagnet.MagnetTypes.LineMagnet) { // Cast the Magnet to the proper type MagnetLine cLineMagnet = (MagnetLine)cMagnet; // Calculate the closest point on the Line to the Particle. // Equation taken from http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/pointline/ // Also explained at http://www.allegro.cc/forums/thread/589720 // Calculate 2 points on the Line Vector3 sPosition1 = cLineMagnet.PositionOnLine; Vector3 sPosition2 = cLineMagnet.PositionOnLine + cLineMagnet.Direction; // Put calculations into temp variables for speed and easy readability float fA = cParticle.Position.X - sPosition1.X; float fB = cParticle.Position.Y - sPosition1.Y; float fC = cParticle.Position.Z - sPosition1.Z; float fD = sPosition2.X - sPosition1.X; float fE = sPosition2.Y - sPosition1.Y; float fF = sPosition2.Z - sPosition1.Z; // Next calculate the value of U. // NOTE: The Direction is normalized, so the distance between Position1 and Position2 is one, so we // don't need to bother squaring and dividing by the length here. float fU = (fA * fD) + (fB * fE) + (fC * fF); // Calculate the closest point on the Line to the Particle Vector3 sClosestPointOnLine = new Vector3(); sClosestPointOnLine.X = sPosition1.X + (fU * fD); sClosestPointOnLine.Y = sPosition1.Y + (fU * fE); sClosestPointOnLine.Z = sPosition1.Z + (fU * fF); // Calculate the direction to attract the Particle to the closest point on the Line sDirectionToPushParticle = sClosestPointOnLine - cParticle.Position; } // Else if the is a Line Segment Magnet else if (cMagnet.MagnetType == DefaultParticleSystemMagnet.MagnetTypes.LineSegmentMagnet) { // Cast the Magnet to the proper type MagnetLineSegment cLineSegmentMagnet = (MagnetLineSegment)cMagnet; // Calculate the closest point on the Line to the Particle. // Equation taken from http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/pointline/ // Also explained at http://www.allegro.cc/forums/thread/589720 // Calculate 2 points on the Line Vector3 sPosition1 = cLineSegmentMagnet.EndPoint1; Vector3 sPosition2 = cLineSegmentMagnet.EndPoint2; // Put calculations into temp variables for speed and easy readability float fA = cParticle.Position.X - sPosition1.X; float fB = cParticle.Position.Y - sPosition1.Y; float fC = cParticle.Position.Z - sPosition1.Z; float fD = sPosition2.X - sPosition1.X; float fE = sPosition2.Y - sPosition1.Y; float fF = sPosition2.Z - sPosition1.Z; // Next calculate the value of U float fDot = (fA * fD) + (fB * fE) + (fC * fF); float fLengthSquared = (fD * fD) + (fE * fE) + (fF * fF); float fU = fDot / fLengthSquared; // Calculate the closest point on the Line to the Particle Vector3 sClosestPointOnLine = new Vector3(); // If the Particle is closest to the first End Point if (fU < 0.0f) { sClosestPointOnLine = sPosition1; } // Else If the Particle is closest to the second End Point else if (fU > 1.0f) { sClosestPointOnLine = sPosition2; } // Else the Particle is closest to the Line Segment somewhere between the End Points else { // Calculate where in between the End Points the Particle is closest to sClosestPointOnLine.X = sPosition1.X + (fU * (sPosition2.X - sPosition1.X)); sClosestPointOnLine.Y = sPosition1.Y + (fU * (sPosition2.Y - sPosition1.Y)); sClosestPointOnLine.Z = sPosition1.Z + (fU * (sPosition2.Z - sPosition1.Z)); } // Calculate the direction to attract the Particle to the closest point on the Line sDirectionToPushParticle = sClosestPointOnLine - cParticle.Position; } // Else If this is a Plane Magnet else if (cMagnet.MagnetType == DefaultParticleSystemMagnet.MagnetTypes.PlaneMagnet) { // Cast the Magnet to the proper type MagnetPlane cPlaneMagnet = (MagnetPlane)cMagnet; // Calculate the closest point on the Plane to the Particle. // Equation taken from http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/pointline/ // Calculate how far from the Plane the Particle is float fDistanceFromPlane = Vector3.Dot(cParticle.Position - cPlaneMagnet.PositionOnPlane, cPlaneMagnet.Normal); // Calculate the closest point on the Plane to the Particle Vector3 sClosestPointOnPlane = cParticle.Position + (-cPlaneMagnet.Normal * fDistanceFromPlane); // Calculate the direction to attract the Particle to the closest point on the Plane sDirectionToPushParticle = sClosestPointOnPlane - cParticle.Position; } // Else we don't know what kind of Magnet this is else { // So exit returning no force return(Vector3.Zero); } // If the Particle should be Repelled away from the Magnet (instead of attracted to it) if (cMagnet.Mode == DefaultParticleSystemMagnet.MagnetModes.Repel) { // Reverse the direction we are going to push the Particle sDirectionToPushParticle *= -1; } // If the Direction To Push the Particle is not valid and we should be Repelling the Particle if (sDirectionToPushParticle == Vector3.Zero && cMagnet.Mode == DefaultParticleSystemMagnet.MagnetModes.Repel) { // Pick a random Direction vector with a very short length to repel the Particle with sDirectionToPushParticle = DPSFHelper.RandomNormalizedVector() * 0.00001f; } // Get how far away the Particle is from the Magnet float fDistanceFromMagnet = sDirectionToPushParticle.Length(); // If the Particle is within range to be affected by the Magnet if (fDistanceFromMagnet >= cMagnet.MinDistance && fDistanceFromMagnet <= cMagnet.MaxDistance) { // If the Direction To Push the Particle is valid if (sDirectionToPushParticle != Vector3.Zero) { // Normalize the Direction To Push the Particle sDirectionToPushParticle.Normalize(); } // Calculate the normalized distance from the Magnet that the Particle is float fLerpAmount = 0.0f; if (cMagnet.MaxDistance != cMagnet.MinDistance) { fLerpAmount = (fDistanceFromMagnet - cMagnet.MinDistance) / (cMagnet.MaxDistance - cMagnet.MinDistance); } // Else the Max Distance equals the Min Distance else { // So to avoid a divide by zero we just assume a full Lerp amount fLerpAmount = 1.0f; } // Calculate how much of the Max Force to apply to the Particle float fNormalizedForce = 0.0f; switch (cMagnet.DistanceFunction) { default: case DefaultParticleSystemMagnet.DistanceFunctions.Constant: fNormalizedForce = cMagnet.MaxForce; break; case DefaultParticleSystemMagnet.DistanceFunctions.Linear: fNormalizedForce = MathHelper.Lerp(0, cMagnet.MaxForce, fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.Squared: fNormalizedForce = MathHelper.Lerp(0, cMagnet.MaxForce, fLerpAmount * fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.Cubed: fNormalizedForce = MathHelper.Lerp(0, cMagnet.MaxForce, fLerpAmount * fLerpAmount * fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.LinearInverse: fNormalizedForce = MathHelper.Lerp(cMagnet.MaxForce, 0, fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.SquaredInverse: fNormalizedForce = MathHelper.Lerp(cMagnet.MaxForce, 0, fLerpAmount * fLerpAmount); break; case DefaultParticleSystemMagnet.DistanceFunctions.CubedInverse: fNormalizedForce = MathHelper.Lerp(cMagnet.MaxForce, 0, fLerpAmount * fLerpAmount * fLerpAmount); break; } // Calculate how much Force should be Exerted on the Particle sForceToExertOnParticle = sDirectionToPushParticle * (fNormalizedForce * cMagnet.MaxForce); } // Return how much Force to Exert on the Particle return(sForceToExertOnParticle); }
/// <summary> /// Linearly interpolates the Particle's Color between it's Start Color and End Color based on the Particle's Normalized Elapsed Time. /// </summary> /// <param name="cParticle">The Particle to update</param> /// <param name="fElapsedTimeInSeconds">How long it has been since the last update</param> protected void UpdateParticleColorUsingLerp(DPSFDefaultBaseParticle cParticle, float fElapsedTimeInSeconds) { // Update the Particle's Color cParticle.Color = DPSFHelper.LerpColor(cParticle.StartColor, cParticle.EndColor, cParticle.NormalizedElapsedTime); }
/// <summary> /// Function to Initialize a Default Particle with the Initial Settings /// </summary> /// <param name="Particle">The Particle to be Initialized</param> /// <param name="cInitialProperties">The Initial Settings to use to Initialize the Particle</param> public void InitializeParticleUsingInitialProperties(DPSFParticle Particle, CInitialProperties cInitialProperties) { // Cast the Particle to the type it really is DPSFDefaultBaseParticle cParticle = (DPSFDefaultBaseParticle)Particle; // Initialize the Particle according to the values specified in the Initial Settings cParticle.Lifetime = DPSFHelper.RandomNumberBetween(cInitialProperties.LifetimeMin, cInitialProperties.LifetimeMax); // If the Position should be interpolated between the Min and Max Positions if (cInitialProperties.InterpolateBetweenMinAndMaxPosition) { cParticle.Position = Vector3.Lerp(cInitialProperties.PositionMin, cInitialProperties.PositionMax, RandomNumber.NextFloat()); } // Else the Position XYZ values should each be calculated individually else { cParticle.Position = DPSFHelper.RandomVectorBetweenTwoVectors(cInitialProperties.PositionMin, cInitialProperties.PositionMax); } // If the Particle's Velocity should be affected by the Emitters Orientation if (cInitialProperties.VelocityIsAffectedByEmittersOrientation) { // Rotate the Particle around the Emitter according to the Emitters orientation cParticle.Position = Vector3.Transform(cParticle.Position, Emitter.OrientationData.Orientation); } // If the Particle should be affected by the Emitters Position if (cInitialProperties.PositionIsAffectedByEmittersPosition) { // Add the Emitter's Position to the Particle's Position cParticle.Position += Emitter.PositionData.Position; } // If the Velocity should be interpolated between the Min and Max Velocity if (cInitialProperties.InterpolateBetweenMinAndMaxVelocity) { cParticle.Velocity = Vector3.Lerp(cInitialProperties.VelocityMin, cInitialProperties.VelocityMax, RandomNumber.NextFloat()); } // Else the Velocity XYZ values should each be calculated individually else { cParticle.Velocity = DPSFHelper.RandomVectorBetweenTwoVectors(cInitialProperties.VelocityMin, cInitialProperties.VelocityMax); } // Have the Emitters Rotation affect the Particle's starting Velocity cParticle.Velocity = Vector3.Transform(cParticle.Velocity, Emitter.OrientationData.Orientation); // If the Acceleration should be interpolated between the Min and Max Acceleration if (cInitialProperties.InterpolateBetweenMinAndMaxAcceleration) { cParticle.Acceleration = Vector3.Lerp(cInitialProperties.AccelerationMin, cInitialProperties.AccelerationMax, RandomNumber.NextFloat()); } // Else the Acceleration XYZ values should each be calculated individually else { cParticle.Acceleration = DPSFHelper.RandomVectorBetweenTwoVectors(cInitialProperties.AccelerationMin, cInitialProperties.AccelerationMax); } // If the External Force should be interpolated between the Min and Max External Force if (cInitialProperties.InterpolateBetweenMinAndMaxExternalForce) { cParticle.ExternalForce = Vector3.Lerp(cInitialProperties.ExternalForceMin, cInitialProperties.ExternalForceMax, RandomNumber.NextFloat()); } // Else the External Force XYZ values should each be calculated individually else { cParticle.ExternalForce = DPSFHelper.RandomVectorBetweenTwoVectors(cInitialProperties.ExternalForceMin, cInitialProperties.ExternalForceMax); } // Calculate the amount of Friction to use cParticle.Friction = DPSFHelper.RandomNumberBetween(cInitialProperties.FrictionMin, cInitialProperties.FrictionMax); // If the new Color values should be somewhere between the interpolation of the Min and Max Colors if (cInitialProperties.InterpolateBetweenMinAndMaxColors) { cParticle.StartColor = DPSFHelper.LerpColor(cInitialProperties.StartColorMin, cInitialProperties.StartColorMax, RandomNumber.NextFloat()); cParticle.EndColor = DPSFHelper.LerpColor(cInitialProperties.EndColorMin, cInitialProperties.EndColorMax, RandomNumber.NextFloat()); } // Else the RGBA Color values should each be randomly calculated individually else { cParticle.StartColor = DPSFHelper.LerpColor(cInitialProperties.StartColorMin, cInitialProperties.StartColorMax, RandomNumber.NextFloat(), RandomNumber.NextFloat(), RandomNumber.NextFloat(), RandomNumber.NextFloat()); cParticle.EndColor = DPSFHelper.LerpColor(cInitialProperties.EndColorMin, cInitialProperties.EndColorMax, RandomNumber.NextFloat(), RandomNumber.NextFloat(), RandomNumber.NextFloat(), RandomNumber.NextFloat()); } cParticle.Color = cParticle.StartColor; }