示例#1
0
        public static ParticleSystem CreateWaterFall(ContentManager contentManager)
        {
            var ps = new ParticleSystem
            {
                Name = "WaterFall",

                // Preload 2 seconds of the effect using a larger time step.
                PreloadDuration  = TimeSpan.FromSeconds(2),
                PreloadDeltaTime = TimeSpan.FromSeconds(0.1),

                Children = new ParticleSystemCollection
                {
                    CreateSpray(contentManager),
                    CreateWater(contentManager),
                }
            };

            // This parent particle system defines the uniform Gravity parameter for the child
            // particle systems. Uniform particle parameters can be "inherited" - if a child
            // does not have a required uniform parameter, it uses the parameter of the parent.
            ps.Parameters.AddUniform <Vector3>("Gravity").DefaultValue = new Vector3(0, -1f, 0);

            ParticleSystemValidator.Validate(ps);
            ParticleSystemValidator.Validate(ps.Children[0]);
            ParticleSystemValidator.Validate(ps.Children[1]);

            return(ps);
        }
示例#2
0
        public static ParticleSystem Create(ContentManager contentManager)
        {
            var ps = new ParticleSystem
            {
                Name = "Decals",
                MaxNumberOfParticles = 50,
            };

            ps.Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = 5;
            ps.Parameters.AddUniform <float>(ParticleParameterNames.Size).DefaultValue     = 0.3f;

            // Following particle parameters are initialized externally:
            ps.Parameters.AddVarying <Vector3F>(ParticleParameterNames.Position);
            ps.Parameters.AddVarying <Vector3F>("Normal");
            ps.Parameters.AddVarying <Vector3F>("Axis");

            ps.Parameters.AddUniform <Vector3F>(ParticleParameterNames.Color).DefaultValue = new Vector3F(0.667f, 0.667f, 0.667f);

            ps.Parameters.AddVarying <float>(ParticleParameterNames.Alpha);
            ps.Effectors.Add(new SingleLinearSegment3Effector
            {
                OutputParameter = ParticleParameterNames.Alpha,
                Time0           = 0,
                Value0          = 1,
                Time1           = 0.9f,
                Value1          = 1,
                Time2           = 1,
                Value2          = 0,
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.Angle);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Angle,
                Distribution = new UniformDistributionF(-0.5f, 0.5f),
            });

            ps.Parameters.AddUniform <Texture2D>(ParticleParameterNames.Texture).DefaultValue =
                contentManager.Load <Texture2D>("Particles/BulletHole");

            // Particle billboards use a custom billboard orientation:
            ps.Parameters.AddUniform <BillboardOrientation>(ParticleParameterNames.BillboardOrientation).DefaultValue =
                BillboardOrientation.WorldOriented;

            ps.Parameters.AddUniform <BlendState>(ParticleParameterNames.BlendState).DefaultValue = BlendState.AlphaBlend;

            // If the user places too many decals, then we run out of particles. If the
            // MaxNumberOfParticles limit is reached, no more decals can be placed. To
            // avoid this we add the ReserveParticleEffector, which kills old particles
            // if the MaxNumberOfParticles limit is reached.
            ps.Effectors.Add(new ReserveParticleEffector());

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#3
0
        public void Initialize(ContentManager contentManager)
        {
            if (ParticleSystemNode == null)
            {
                // This is the first time this instance is used.

                var ps = new ParticleSystem
                {
                    Name           = "Teleport" + _count,
                    ReferenceFrame = ParticleReferenceFrame.Local,
                    Children       = new ParticleSystemCollection
                    {
                        CreateSparkles(contentManager),
                        CreateFastBeams(contentManager),
                        CreateSlowBeams(contentManager),
                    }
                };

                // Add a uniform float particle parameter that contains the particle system time.
                ps.Parameters.AddUniform <float>("Time");
                ps.Effectors.Add(new TimeToSingleEffector {
                    Parameter = "Time"
                });

                // Add a uniform GlobalAlpha parameter. This parameter controls the alpha of all
                // child particle systems.
                ps.Parameters.AddUniform <float>("GlobalAlpha");
                ps.Effectors.Add(new SingleFadeEffector
                {
                    ValueParameter = "GlobalAlpha",
                    TimeParameter  = "Time",
                    FadeInStart    = 0,
                    FadeInEnd      = 2,
                    FadeOutStart   = 2,
                    FadeOutEnd     = 3,
                });

                ParticleSystemValidator.Validate(ps);
                ParticleSystemValidator.Validate(ps.Children[0]);
                ParticleSystemValidator.Validate(ps.Children[1]);
                ParticleSystemValidator.Validate(ps.Children[2]);

                ParticleSystemNode = new ParticleSystemNode(ps)
                {
                    Name = "TeleportNode" + _count
                };
                _count++;
            }
            else
            {
                ParticleSystem.Reset();
                ParticleSystemNode.PoseWorld = Pose.Identity;
            }
        }
示例#4
0
        public Rockets()
        {
            Name = "Rockets";
            MaxNumberOfParticles = 10;

            // The RocketEffector will add child particle systems.
            Children = new ParticleSystemCollection();

            Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = 2;

            Effectors.Add(new StreamEmitter
            {
                DefaultEmissionRate = 2,
            });

            Parameters.AddVarying <Vector3>(ParticleParameterNames.Position);
            Effectors.Add(new StartPositionEffector
            {
                Parameter    = ParticleParameterNames.Position,
                Distribution = new BoxDistribution {
                    MinValue = new Vector3(-5, 0, -5), MaxValue = new Vector3(5, 0, 0)
                },
            });

            Parameters.AddVarying <Vector3>(ParticleParameterNames.Direction);
            Effectors.Add(new StartDirectionEffector
            {
                Parameter    = ParticleParameterNames.Direction,
                Distribution = new DirectionDistribution {
                    Deviation = 0.5f, Direction = Vector3.UnitY
                },
            });

            Parameters.AddVarying <float>(ParticleParameterNames.LinearSpeed);
            Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.LinearSpeed,
                Distribution = new UniformDistributionF(2, 6),
            });

            Effectors.Add(new LinearVelocityEffector());

            Parameters.AddUniform <Vector3>(ParticleParameterNames.LinearAcceleration).DefaultValue = new Vector3(0, -2f, 0);
            Effectors.Add(new LinearAccelerationEffector());

            Parameters.AddUniform <float>(ParticleParameterNames.Alpha).DefaultValue = 0;

            // The RocketEffector creates and controls nested particle systems for the rocket trails
            // and explosions.
            Effectors.Add(new RocketEffector());

            ParticleSystemValidator.Validate(this);
        }
示例#5
0
        public Explosion(ContentManager contentManager)
        {
            // The explosion particle systems owns 3 child particle systems.
            // (The parent particle system does not have any particles.)
            Children = new ParticleSystemCollection
            {
                CreateFlash(contentManager),
                CreateHotCore(contentManager),
                CreateSmoke(contentManager),
            };

            ParticleSystemValidator.Validate(Children[0]);
            ParticleSystemValidator.Validate(Children[1]);
            ParticleSystemValidator.Validate(Children[2]);
        }
示例#6
0
        private RocketExplosion(ContentManager contentManager)
        {
            Children = new ParticleSystemCollection
            {
                new RocketExplosionSmoke(contentManager),
                new RocketExplosionCore(contentManager),
            };

            // This EmitterVelocity parameter can be used by all child particle systems.
            Parameters.AddUniform <Vector3F>(ParticleParameterNames.EmitterVelocity);

            // The ParticleSystemRecycler recycles this instance into the resource pool when all
            // particles are dead.
            Effectors.Add(new ParticleSystemRecycler
            {
                ResourcePool = Pool,
            });

            ParticleSystemValidator.Validate(this);
            ParticleSystemValidator.Validate(Children[0]);
            ParticleSystemValidator.Validate(Children[1]);
        }
示例#7
0
        public static ParticleSystem Create(ContentManager contentManager)
        {
            var ps = new ParticleSystem
            {
                Name = "Ribbon",
                MaxNumberOfParticles = 50,
            };

            // Ribbons are enabled by setting the "Type" to ParticleType.Ribbon. Consecutive
            // living particles are connected and rendered as ribbons (quad strips). At least
            // two living particles are required to create a ribbon. Dead particles
            // ("NormalizedAge" ≥ 1) can be used as delimiters to terminate one ribbon and
            // start the next ribbon.
            ps.Parameters.AddUniform <ParticleType>(ParticleParameterNames.Type).DefaultValue =
                ParticleType.Ribbon;

            ps.Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = 1;

            ps.Parameters.AddVarying <Vector3F>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartPositionEffector());

            // The parameter "Axis" determines the orientation of the ribbon.
            // We could use a fixed orientation. It is also possible to "twist" the ribbon
            // by using a varying parameter.
            //ps.Parameters.AddUniform<Vector3F>(ParticleParameterNames.Axis).DefaultValue =
            //  Vector3F.Up;

            ps.Effectors.Add(new RibbonEffector());
            ps.Effectors.Add(new ReserveParticleEffector {
                Reserve = 1
            });

            ps.Parameters.AddUniform <float>(ParticleParameterNames.Size).DefaultValue = 1;

            ps.Parameters.AddVarying <Vector3F>(ParticleParameterNames.Color);
            ps.Effectors.Add(new StartValueEffector <Vector3F>
            {
                Parameter    = ParticleParameterNames.Color,
                Distribution = new BoxDistribution {
                    MinValue = new Vector3F(0.5f, 0.5f, 0.5f), MaxValue = new Vector3F(1, 1, 1)
                }
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.Alpha);
            ps.Effectors.Add(new FuncEffector <float, float>
            {
                InputParameter  = ParticleParameterNames.NormalizedAge,
                OutputParameter = ParticleParameterNames.Alpha,
                Func            = age => 6.7f * age * (1 - age) * (1 - age),
            });

            ps.Parameters.AddUniform <Texture2D>(ParticleParameterNames.Texture).DefaultValue =
                contentManager.Load <Texture2D>("Particles/Ribbon");

            // The parameter "TextureTiling" defines how the texture spreads across the ribbon.
            // 0 ... no tiling,
            // 1 ... repeat every particle,
            // n ... repeat every n-th particle
            ps.Parameters.AddUniform <int>(ParticleParameterNames.TextureTiling).DefaultValue =
                1;

            ps.Parameters.AddUniform <float>(ParticleParameterNames.BlendMode).DefaultValue = 0;

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#8
0
        public static ParticleSystem Create(ContentManager contentManager)
        {
            var ps = new ParticleSystem
            {
                Name = "Rain",
                MaxNumberOfParticles = 2000,
            };

            ps.Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = 0.8f;

            ps.Effectors.Add(new StreamEmitter
            {
                DefaultEmissionRate = 1200,
            });

            ps.Parameters.AddVarying <Vector3F>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartPositionEffector
            {
                Parameter    = ParticleParameterNames.Position,
                Distribution = new BoxDistribution {
                    MinValue = new Vector3F(-20, 15, -20), MaxValue = new Vector3F(20, 15, 20)
                }
            });

            ps.Parameters.AddVarying <Vector3F>(ParticleParameterNames.Direction);
            ps.Effectors.Add(new StartDirectionEffector
            {
                Parameter    = ParticleParameterNames.Direction,
                Distribution = new DirectionDistribution {
                    Deviation = 0f, Direction = -Vector3F.UnitY
                },
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.LinearSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.LinearSpeed,
                Distribution = new UniformDistributionF(20, 30),
            });

            ps.Effectors.Add(new LinearVelocityEffector());

            ps.Parameters.AddUniform <float>(ParticleParameterNames.SizeX).DefaultValue = 0.03f;
            ps.Parameters.AddVarying <float>(ParticleParameterNames.SizeY);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.SizeY,
                Distribution = new UniformDistributionF(0.5f, 1.5f),
            });

            ps.Parameters.AddUniform <Vector3F>(ParticleParameterNames.Color).DefaultValue = new Vector3F(0.5f, 0.7f, 0.9f);

            ps.Parameters.AddUniform <float>(ParticleParameterNames.Alpha).DefaultValue = 0.5f;

            ps.Parameters.AddUniform <Texture2D>(ParticleParameterNames.Texture).DefaultValue =
                contentManager.Load <Texture2D>("Particles/RainDrop");

            // DigitalRune Graphics can render particles with different billboard orientations.
            // The rain drops should use axial billboards in the up direction (a.k.a. cylindrical
            // billboards).
            ps.Parameters.AddUniform <BillboardOrientation>(ParticleParameterNames.BillboardOrientation).DefaultValue = BillboardOrientation.AxialViewPlaneAligned;

            ps.Parameters.AddUniform <float>(ParticleParameterNames.BlendMode).DefaultValue = 0;

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#9
0
        public static ParticleSystem Create(ContentManager contentManager)
        {
            var ps = new ParticleSystem
            {
                Name = "Grass",
                MaxNumberOfParticles = 400,
            };

            // The grass particles do not die.
            ps.Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = float.PositiveInfinity;

            // We create all particles instantly. Up to 400 particles. Then the emission stops.
            ps.Effectors.Add(new StreamEmitter
            {
                DefaultEmissionRate = 400 * 60,
                EmissionLimit       = 400,
            });

            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartPositionEffector
            {
                Parameter    = ParticleParameterNames.Position,
                Distribution = new BoxDistribution {
                    MinValue = new Vector3(-10, 0.4f, -10), MaxValue = new Vector3(10, 0.4f, 10)
                }
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.SizeX);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.SizeX,
                Distribution = new UniformDistributionF(0.6f, 1),
            });
            ps.Parameters.AddVarying <float>(ParticleParameterNames.SizeY);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.SizeY,
                Distribution = new UniformDistributionF(0.6f, 1),
            });

            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Color);
            ps.Effectors.Add(new StartValueEffector <Vector3>
            {
                Parameter    = ParticleParameterNames.Color,
                Distribution = new LineSegmentDistribution {
                    Start = new Vector3(0.82f, 0.92f, 1) * 0.9f, End = new Vector3(1, 1, 1)
                }
            });

            ps.Parameters.AddUniform <Texture2D>(ParticleParameterNames.Texture).DefaultValue =
                contentManager.Load <Texture2D>("Particles/Grass");

            ps.Parameters.AddUniform <BillboardOrientation>(ParticleParameterNames.BillboardOrientation).DefaultValue =
                BillboardOrientation.AxialViewPlaneAligned;

            ps.Parameters.AddUniform <bool>(ParticleParameterNames.IsDepthSorted).DefaultValue = true;

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#10
0
        public static ParticleSystem CreateCampfireSmoke(ContentManager contentManager)
        {
            ParticleSystem ps = new ParticleSystem
            {
                Name = "CampfireSmoke",
                MaxNumberOfParticles = 50,
            };

            // Each particle lives for a random time span.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Lifetime);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Lifetime,
                Distribution = new UniformDistributionF(2.0f, 2.4f),
            });

            // Add an effector that emits particles at a constant rate.
            ps.Effectors.Add(new StreamEmitter
            {
                DefaultEmissionRate = 15,
            });

            // Particle positions start on a circular area (in the xy-plane).
            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartPositionEffector
            {
                Parameter    = ParticleParameterNames.Position,
                Distribution = new CircleDistribution {
                    OuterRadius = 0.4f, InnerRadius = 0
                }
            });

            // Particles move in forward direction with a slight random deviation with a random speed.
            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Direction);
            ps.Effectors.Add(new StartDirectionEffector
            {
                Parameter    = ParticleParameterNames.Direction,
                Distribution = new DirectionDistribution {
                    Deviation = 0.15f, Direction = Vector3.Forward
                },
            });
            ps.Parameters.AddVarying <float>(ParticleParameterNames.LinearSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.LinearSpeed,
                Distribution = new UniformDistributionF(0, 1),
            });

            // The LinearVelocityEffector uses the Direction and LinearSpeed to update the Position
            // of particles.
            ps.Effectors.Add(new LinearVelocityEffector());

            // Lets apply a damping (= exponential decay) to the LinearSpeed using the SingleDampingEffector.
            ps.Parameters.AddUniform <float>(ParticleParameterNames.Damping).DefaultValue = 1.0f;
            ps.Effectors.Add(new SingleDampingEffector
            {
                // Following parameters are equal to the default values. No need to set them.
                //ValueParameter = ParticleParameterNames.LinearSpeed,
                //DampingParameter = ParticleParameterNames.Damping,
            });

            // To create a wind effect, we apply an acceleration to all particles.
            ps.Parameters.AddUniform <Vector3>("Wind").DefaultValue = new Vector3(-1, 3, -0.5f);
            ps.Effectors.Add(new LinearAccelerationEffector {
                AccelerationParameter = "Wind"
            });

            // Each particle starts with a random rotation angle and a random angular speed.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Angle);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Angle,
                Distribution = new UniformDistributionF(-ConstantsF.PiOver2, ConstantsF.PiOver2),
            });
            ps.Parameters.AddVarying <float>(ParticleParameterNames.AngularSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.AngularSpeed,
                Distribution = new UniformDistributionF(-2f, 2f),
            });

            // The AngularVelocityEffector uses the AngularSpeed to update the particle Angle.
            ps.Effectors.Add(new AngularVelocityEffector
            {
                AngleParameter = ParticleParameterNames.Angle,
                SpeedParameter = ParticleParameterNames.AngularSpeed,
            });

            // Each particle gets a random start and end size.
            ps.Parameters.AddVarying <float>("StartSize");
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = "StartSize",
                Distribution = new UniformDistributionF(0.5f, 0.7f),
            });
            ps.Parameters.AddVarying <float>("EndSize");
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = "EndSize",
                Distribution = new UniformDistributionF(1.0f, 1.4f),
            });

            // The Size is computed from linear interpolation between the StartSize and the EndSize.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Size);
            ps.Effectors.Add(new SingleLerpEffector
            {
                ValueParameter  = ParticleParameterNames.Size,
                FactorParameter = ParticleParameterNames.NormalizedAge,
                StartParameter  = "StartSize",
                EndParameter    = "EndSize",
            });

            // The Color slowly changes linearly from light gray to a darker gray.
            ps.Parameters.AddUniform <Vector3>("StartColor").DefaultValue = new Vector3(0.8f, 0.8f, 0.8f);
            ps.Parameters.AddUniform <Vector3>("EndColor").DefaultValue   = new Vector3(0.3f, 0.3f, 0.3f);
            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Color);
            ps.Effectors.Add(new Vector3LerpEffector
            {
                ValueParameter = ParticleParameterNames.Color,
                StartParameter = "StartColor",
                EndParameter   = "EndColor",
            });

            // The Alpha value is 0 for a short time, then it fades in to the TargetAlpha and finally
            // it fades out again.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Alpha);
            ps.Parameters.AddUniform <float>("TargetAlpha").DefaultValue = 0.33f;
            ps.Effectors.Add(new SingleFadeEffector
            {
                ValueParameter       = ParticleParameterNames.Alpha,
                TargetValueParameter = "TargetAlpha",
                TimeParameter        = ParticleParameterNames.NormalizedAge,
                FadeInStart          = 0.36f,
                FadeInEnd            = 0.6f,
                FadeOutStart         = 0.6f,
                FadeOutEnd           = 1.0f,
            });

            // DigitalRune Graphics supports "texture atlases": The class PackedTexture
            // describes a single texture or tile set packed into a texture atlas. The
            // smoke texture in this example consists of 2 tiles.
            ps.Parameters.AddUniform <PackedTexture>(ParticleParameterNames.Texture).DefaultValue =
                new PackedTexture(
                    "Smoke2",
                    contentManager.Load <Texture2D>("Campfire/Smoke2"),
                    Vector2F.Zero, Vector2F.One,
                    2, 1);

            // The particle parameter "AnimationTime" determines which tile is used,
            // where 0 = first tile, 1 = last tile.
            // --> Chooses a random tile for each particle when it is created.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.AnimationTime);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.AnimationTime,
                Distribution = new UniformDistributionF(0, 1),
            });

            // Smoke needs alpha blending.
            ps.Parameters.AddUniform <float>(ParticleParameterNames.BlendMode).DefaultValue = 1;

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#11
0
        public static ParticleSystem Create(ContentManager contentManager)
        {
            ParticleSystem ps = new ParticleSystem
            {
                Name = "Smoke",
                MaxNumberOfParticles = 200,
            };

            // All particles should live for 5 seconds.
            ps.Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = 5;

            // Add an effector that emits particles at a constant rate.
            ps.Effectors.Add(new StreamEmitter
            {
                DefaultEmissionRate = 30,
            });

            // The reference frame can be either "Local" or "World" (Default).
            // - "Local" means that the particle positions, directions, velocities, etc.
            //   are relative to the ParticleSystemNode in the scene graph.
            // - "World" means that those values are given in world space. The position
            //   of the ParticleSystemNode in the scene graph does not affect the particles.
            // (For more information check out sample "11-ReferenceFrame".)
            ps.ReferenceFrame = ParticleReferenceFrame.Local;

            // Particle positions start in the center of the particle system.
            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartPositionEffector
            {
                Parameter    = ParticleParameterNames.Position,
                DefaultValue = Vector3.Zero,
            });

            // Particles move in the up direction with a random deviation of 0.5 radians and a
            // random speed.
            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Direction);
            ps.Effectors.Add(new StartDirectionEffector
            {
                Parameter    = ParticleParameterNames.Direction,
                Distribution = new DirectionDistribution {
                    Deviation = 0.5f, Direction = Vector3.Up
                },
            });
            ps.Parameters.AddVarying <float>(ParticleParameterNames.LinearSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.LinearSpeed,
                Distribution = new UniformDistributionF(0.5f, 1),
            });

            // The LinearVelocityEffector uses the Direction and LinearSpeed to update the Position
            // of particles.
            ps.Effectors.Add(new LinearVelocityEffector
            {
                // Following parameters are equal to the default values. No need to set them.
                //PositionParameter = ParticleParameterNames.Position,
                //DirectionParameter = ParticleParameterNames.Direction,
                //SpeedParameter = ParticleParameterNames.LinearSpeed,
            });

            // To create a wind effect, we apply an acceleration to all particles.
            ps.Parameters.AddUniform <Vector3>(ParticleParameterNames.LinearAcceleration).DefaultValue =
                new Vector3(0.2f, -0.1f, 0);

            ps.Effectors.Add(new LinearAccelerationEffector
            {
                // Following parameters are equal to the default values. No need to set them.
                //AccelerationParameter = ParticleParameterNames.LinearAcceleration,
                //DirectionParameter = ParticleParameterNames.Direction,
                //SpeedParameter = ParticleParameterNames.LinearSpeed,
            });

            // Each particle starts with a random rotation angle and a random angular speed.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Angle);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Angle,
                Distribution = new UniformDistributionF(-ConstantsF.Pi, ConstantsF.Pi),
            });
            ps.Parameters.AddVarying <float>(ParticleParameterNames.AngularSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.AngularSpeed,
                Distribution = new UniformDistributionF(-2, 2),
            });
            // The AngularVelocityEffector uses the AngularSpeed to update the particle Angle.
            ps.Effectors.Add(new AngularVelocityEffector
            {
                // Following parameters are equal to the default values. No need to set them.
                //AngleParameter = ParticleParameterNames.Angle,
                //SpeedParameter = ParticleParameterNames.AngularSpeed,
            });

            ps.Parameters.AddVarying <float>("StartSize");
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = "StartSize",
                Distribution = new UniformDistributionF(0.1f, 0.5f),
            });

            ps.Parameters.AddVarying <float>("EndSize");
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = "EndSize",
                Distribution = new UniformDistributionF(2, 4),
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.Size);
            ps.Effectors.Add(new SingleLerpEffector
            {
                ValueParameter = ParticleParameterNames.Size,
                StartParameter = "StartSize",
                EndParameter   = "EndSize",
            });

            // Particle alpha fades in to a target value of 1 and then back out to 0.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Alpha);
            ps.Parameters.AddUniform <float>("TargetAlpha").DefaultValue = 1f;
            ps.Effectors.Add(new SingleFadeEffector
            {
                ValueParameter       = ParticleParameterNames.Alpha,
                TargetValueParameter = "TargetAlpha",
                FadeInStart          = 0f,
                FadeInEnd            = 0.2f,
                FadeOutStart         = 0.7f,
                FadeOutEnd           = 1f,
            });

            ps.Parameters.AddUniform <Texture2D>(ParticleParameterNames.Texture).DefaultValue =
                contentManager.Load <Texture2D>("Particles/Smoke");

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#12
0
        public BasicParticlesSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            // Create a new "empty" particle system.
            _particleSystem = new ParticleSystem();

            // Names are optional, but very useful for debugging.
            _particleSystem.Name = "MyFirstParticleSystem";

            // The particle system uses pre-allocated arrays. We should define an upper limit for
            // the number of particles that can be alive at the same moment.
            _particleSystem.MaxNumberOfParticles = 200;

            // The particle system's Pose defines the position and orientation of the particle system
            // in the world.
            _particleSystem.Pose = new Pose(new Vector3(0, 2, 0));

            // The properties of the particles in the particle system are defined using
            // "particle parameters" (in the collection _particleSystem.Parameters).
            // Per default, there is only one parameter: "NormalizedAge" - which is managed
            // by the particle system itself and is the age of a particle in the range 0 - 1.

            // All our particles should live for 1 second after they have been created. Therefore,
            // we add a "uniform" parameter called "Lifetime" and set it to 1.
            var lifetimeParameter = _particleSystem.Parameters.AddUniform <float>("Lifetime");

            lifetimeParameter.DefaultValue = 1f;

            // Each particle should have a position value. Therefore, we add a "varying" parameter
            // called "Position". "Varying" means that each particle has its own position value.
            // The particle system will internally allocate a Vector3 array to store all particle
            // positions.
            _particleSystem.Parameters.AddVarying <Vector3>("Position");

            // When particles are created, we want them to appear at random position in a spherical
            // volume. We add an effector which initializes the particle "Positions" of newly created
            // particles.
            _particleSystem.Effectors.Add(new StartPositionEffector
            {
                // This effector should initialize the "Position" parameter.
                // Parameter = "Position",     // "Position" is the default value anyway.

                // The start values should be chosen from this random value distribution:
                Distribution = new SphereDistribution {
                    OuterRadius = 2
                }
            });

            // The particles should slowly fade in and out to avoid sudden appearance and disappearance.
            // We add a varying particle parameter called "Alpha" to store the alpha value per particle.
            _particleSystem.Parameters.AddVarying <float>("Alpha");

            // The SingleFadeEffector animates a float parameter from 0 to a target value and
            // back to 0.
            _particleSystem.Effectors.Add(new SingleFadeEffector
            {
                // If TargetValueParameter is not set, then the target value is 1.
                //TargetValueParameter = 1,

                // The fade-in/out times are relative to a time parameter.
                // By default the "NormalizedAge" of the particles is used.
                //TimeParameter = "NormalizedAge",

                // The Alpha value should be animated.
                ValueParameter = "Alpha",

                // The fade-in/out times relative to the normalized age.
                FadeInStart  = 0.0f,
                FadeInEnd    = 0.3f,
                FadeOutStart = 0.5f,
                FadeOutEnd   = 1.0f,
            });

            // Next, we choose a texture for the particles. All particles use the same texture
            // parameter, which means the parameter is "uniform".
            var textureParameter = _particleSystem.Parameters.AddUniform <Texture2D>("Texture");

            textureParameter.DefaultValue = ContentManager.Load <Texture2D>("Particles/LensFlare");

            // The blend mode is a value between 0 and 1, where 0 means additive blending
            // 1 means alpha blending. Values between 0 and 1 are allowed. The particles in
            // this example should be drawn using additive alpha blending.
            var blendModeParameter = _particleSystem.Parameters.AddUniform <float>("BlendMode");

            blendModeParameter.DefaultValue = 0.0f;

            // There is a lot to configure. Did we forget anything? - We can use an optional helper method
            // to validate our particle system. Uninitialized or missing parameters are printed to the
            // Console. Check the Visual Studio Output window for any messages.
            ParticleSystemValidator.Validate(_particleSystem);

            // Adding the particle system to a ParticleSystemService is optional but very useful
            // because the service will update the particle system for us in each frame.
            ParticleSystemService.ParticleSystems.Add(_particleSystem);

            // To render the particle effect, we need to create a scene node and add it to the
            // scene graph.
            _particleSystemNode = new ParticleSystemNode(_particleSystem);
            GraphicsScreen.Scene.Children.Add(_particleSystemNode);

            // A tip for the future:
            // The class ParticleParameterNames is a collection of strings that can be used for
            // common particle parameters. It is recommended to use the particle parameter names in
            // this class to avoid problems because of typing errors in the source code.
        }
示例#13
0
        public static ParticleSystem Create(ContentManager contentManager)
        {
            ParticleSystem ps = new ParticleSystem
            {
                Name = "Fire",
                MaxNumberOfParticles = 300
            };

            ps.Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = 2;

            ps.Effectors.Add(new StreamEmitter
            {
                DefaultEmissionRate = 120,
            });

            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartPositionEffector
            {
                Parameter    = ParticleParameterNames.Position,
                Distribution = new CircleDistribution {
                    OuterRadius = 2, InnerRadius = 2
                }
            });

            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Direction);
            ps.Effectors.Add(new StartDirectionEffector
            {
                Parameter = ParticleParameterNames.Direction,

                // The start direction can be any direction (direction deviation is 360°).
                Distribution = new DirectionDistribution {
                    Deviation = ConstantsF.TwoPi, Direction = Vector3.UnitY
                },
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.LinearSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.LinearSpeed,
                Distribution = new UniformDistributionF(0, 0.5f),
            });

            ps.Effectors.Add(new LinearVelocityEffector());

            ps.Parameters.AddUniform <Vector3>(ParticleParameterNames.LinearAcceleration).DefaultValue = new Vector3(0, 1, 0);
            ps.Effectors.Add(new LinearAccelerationEffector());

            ps.Parameters.AddVarying <float>(ParticleParameterNames.Angle);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Angle,
                Distribution = new UniformDistributionF(-ConstantsF.Pi, ConstantsF.Pi),
            });

            ps.Parameters.AddUniform <float>("TargetAlpha").DefaultValue = 1f;
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Alpha);
            ps.Effectors.Add(new SingleFadeEffector
            {
                ValueParameter       = ParticleParameterNames.Alpha,
                TargetValueParameter = "TargetAlpha",
                FadeInStart          = 0f,
                FadeInEnd            = 0.1f,
                FadeOutStart         = 0.2f,
                FadeOutEnd           = 1f,
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.Size);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Size,
                Distribution = new UniformDistributionF(0.5f, 1),
            });

            ps.Parameters.AddUniform <Texture2D>(ParticleParameterNames.Texture).DefaultValue =
                contentManager.Load <Texture2D>("Particles/Fire");

            // Fire needs additive blending.
            ps.Parameters.AddUniform <float>(ParticleParameterNames.BlendMode).DefaultValue = 0.0f;

            // Fire should be drawn on top of other effects (like smoke).
            // "DrawOrder" is supported by the ParticleBatch renderer.
            ps.Parameters.AddUniform <int>(ParticleParameterNames.DrawOrder).DefaultValue = 100;

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#14
0
        public static ParticleSystem Create(ITriangleMesh mesh, ContentManager contentManager)
        {
            var ps = new ParticleSystem
            {
                Name = "GlowingMeshEffect",
                MaxNumberOfParticles = 100
            };

            ps.Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = 1.0f;

            ps.Effectors.Add(new StreamEmitter
            {
                DefaultEmissionRate = 100,
            });

            // The particles start on random positions on the surface of the given triangle mesh.
            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartOnMeshEffector
            {
                Parameter = ParticleParameterNames.Position,
                Mesh      = mesh
            });

            // Just to demonstrate a new custom effector:
            // The size follows a user-defined curve using the FuncEffector.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Size);
            ps.Effectors.Add(new FuncEffector <float, float>
            {
                InputParameter  = ParticleParameterNames.NormalizedAge,
                OutputParameter = ParticleParameterNames.Size,
                Func            = age => 6.7f * age * (1 - age) * (1 - age) * 0.4f,
            });

            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Color);
            ps.Effectors.Add(new StartValueEffector <Vector3>
            {
                Parameter    = ParticleParameterNames.Color,
                Distribution = new BoxDistribution
                {
                    MinValue = new Vector3(0.5f, 0.5f, 0.5f),
                    MaxValue = new Vector3(1, 1, 1)
                }
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.Alpha);
            ps.Effectors.Add(new FuncEffector <float, float>
            {
                InputParameter  = ParticleParameterNames.NormalizedAge,
                OutputParameter = ParticleParameterNames.Alpha,
                Func            = age => 6.7f * age * (1 - age) * (1 - age),
            });

            ps.Parameters.AddUniform <Texture2D>(ParticleParameterNames.Texture).DefaultValue =
                contentManager.Load <Texture2D>("Particles/Star");

            ps.Parameters.AddUniform <float>(ParticleParameterNames.BlendMode).DefaultValue = 0;


            ps.Parameters.AddUniform <BillboardOrientation>(ParticleParameterNames.BillboardOrientation).DefaultValue =
                BillboardOrientation.ScreenAligned;

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#15
0
        private RocketTrail(ContentManager contentManager)
        {
            MaxNumberOfParticles = 200;

            Parameters.AddVarying <float>(ParticleParameterNames.Lifetime);
            Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Lifetime,
                Distribution = new UniformDistributionF(1, 2),
            });

            Parameters.AddUniform <float>(ParticleParameterNames.EmissionRate);
            Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.EmissionRate,
                DefaultValue = 60,
            });
            Effectors.Add(new StreamEmitter
            {
                EmissionRateParameter = ParticleParameterNames.EmissionRate,
            });

            Parameters.AddVarying <Vector3F>(ParticleParameterNames.Position);
            Effectors.Add(new StartPositionEffector
            {
                Parameter = ParticleParameterNames.Position,
            });

            Parameters.AddVarying <Vector3F>(ParticleParameterNames.Direction);
            Effectors.Add(new StartDirectionEffector
            {
                Parameter    = ParticleParameterNames.Direction,
                Distribution = new DirectionDistribution {
                    Deviation = ConstantsF.Pi, Direction = Vector3F.UnitY
                },
            });

            Parameters.AddVarying <float>(ParticleParameterNames.LinearSpeed);
            Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.LinearSpeed,
                Distribution = new UniformDistributionF(0.1f, 0.3f),
            });

            // The StartVelocityBiasEffector adds a velocity to new particles. We use this to add
            // the rocket velocity (stored in the parameter "EmitterVelocity") to the start velocities
            // of the particles.
            Parameters.AddUniform <Vector3F>(ParticleParameterNames.EmitterVelocity);
            Effectors.Add(new StartVelocityBiasEffector {
                Strength = 0.1f
            });

            Effectors.Add(new LinearVelocityEffector());

            Parameters.AddVarying <float>(ParticleParameterNames.Angle);
            Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Angle,
                Distribution = new UniformDistributionF(-ConstantsF.Pi, ConstantsF.Pi),
            });

            Parameters.AddVarying <float>(ParticleParameterNames.AngularSpeed);
            Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.AngularSpeed,
                Distribution = new UniformDistributionF(-1, 1),
            });
            Effectors.Add(new AngularVelocityEffector());

            Parameters.AddVarying <float>("StartSize");
            Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = "StartSize",
                Distribution = new UniformDistributionF(0.2f, 0.5f),
            });

            Parameters.AddVarying <float>("EndSize");
            Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = "EndSize",
                Distribution = new UniformDistributionF(0.5f, 1f),
            });

            Parameters.AddVarying <float>(ParticleParameterNames.Size);
            Effectors.Add(new SingleLerpEffector
            {
                ValueParameter = ParticleParameterNames.Size,
                StartParameter = "StartSize",
                EndParameter   = "EndSize",
            });

            Parameters.AddVarying <Vector3F>(ParticleParameterNames.Color);
            Effectors.Add(new StartValueEffector <Vector3F>
            {
                Parameter    = ParticleParameterNames.Color,
                Distribution = new LineSegmentDistribution {
                    Start = new Vector3F(0.5f, 0.4f, 0.25f), End = new Vector3F(0.7f, 0.6f, 0.5f)
                },
            });

            Parameters.AddVarying <float>(ParticleParameterNames.Alpha);
            Effectors.Add(new FuncEffector <float, float>
            {
                InputParameter  = ParticleParameterNames.NormalizedAge,
                OutputParameter = ParticleParameterNames.Alpha,
                Func            = age => 6.7f * age * (1 - age) * (1 - age),
            });


            Parameters.AddUniform <Texture2D>(ParticleParameterNames.Texture).DefaultValue =
                contentManager.Load <Texture2D>("Particles/Smoke");

            // Draw behind explosion.
            Parameters.AddUniform <int>(ParticleParameterNames.DrawOrder).DefaultValue = -100;

            // The ParticleSystemRecycler recycles this instance into the specified resource
            // pool when all particles are dead.
            Effectors.Add(new ParticleSystemRecycler
            {
                ResourcePool = Pool,

                // Set a minimum life-time to avoid that the particle system is recycled too early.
                // (The rocket trail might need a few frames before particles are created.)
                MinRuntime = TimeSpan.FromSeconds(0.05f),
            });

            ParticleSystemValidator.Validate(this);
        }
示例#16
0
        public static ParticleSystem CreateCampfire(ContentManager contentManager)
        {
            ParticleSystem ps = new ParticleSystem
            {
                Name = "Campfire",
                MaxNumberOfParticles = 50
            };

            // Each particle lives for a random time span.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Lifetime);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Lifetime,
                Distribution = new UniformDistributionF(0.8f, 1.2f),
            });

            // Add an effector that emits particles at a constant rate.
            ps.Effectors.Add(new StreamEmitter
            {
                DefaultEmissionRate = 30,
            });

            // Particle positions start on a circular area (in the xy-plane).
            ps.Parameters.AddVarying <Vector3>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartPositionEffector
            {
                Parameter    = ParticleParameterNames.Position,
                Distribution = new CircleDistribution {
                    OuterRadius = 0.4f, InnerRadius = 0
                }
            });

            // Particles move in forward direction with a random speed.
            ps.Parameters.AddUniform <Vector3>(ParticleParameterNames.Direction).DefaultValue = Vector3.Forward;
            ps.Parameters.AddVarying <float>(ParticleParameterNames.LinearSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.LinearSpeed,
                Distribution = new UniformDistributionF(0, 1),
            });

            // The LinearVelocityEffector uses the Direction and LinearSpeed to update the Position
            // of particles.
            ps.Effectors.Add(new LinearVelocityEffector());

            // Lets apply a damping (= exponential decay) to the LinearSpeed using the SingleDampingEffector.
            ps.Parameters.AddUniform <float>(ParticleParameterNames.Damping).DefaultValue = 1.0f;
            ps.Effectors.Add(new SingleDampingEffector
            {
                // Following parameters are equal to the default values. No need to set them.
                //ValueParameter = ParticleParameterNames.LinearSpeed,
                //DampingParameter = ParticleParameterNames.Damping,
            });

            // To create a wind effect, we apply an acceleration to all particles.
            ps.Parameters.AddUniform <Vector3>("Wind").DefaultValue = new Vector3(-1, 3, -0.5f);
            ps.Effectors.Add(new LinearAccelerationEffector {
                AccelerationParameter = "Wind"
            });

            // Each particle starts with a random rotation angle and a random angular speed.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Angle);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.Angle,
                Distribution = new UniformDistributionF(-ConstantsF.Pi, ConstantsF.Pi),
            });
            ps.Parameters.AddVarying <float>(ParticleParameterNames.AngularSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.AngularSpeed,
                Distribution = new UniformDistributionF(-2f, 2f),
            });

            // The AngularVelocityEffector uses the AngularSpeed to update the particle Angle.
            ps.Effectors.Add(new AngularVelocityEffector());

            // All particle have the same size.
            ps.Parameters.AddUniform <float>(ParticleParameterNames.Size).DefaultValue = 0.8f;

            // Particle alpha fades in to 1 and then back out to 0.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.Alpha);
            ps.Effectors.Add(new SingleFadeEffector
            {
                ValueParameter = ParticleParameterNames.Alpha,
                FadeInStart    = 0.0f,
                FadeInEnd      = 0.2f,
                FadeOutStart   = 0.8f,
                FadeOutEnd     = 1.0f,
            });

            // DigitalRune Graphics supports "texture atlases": The class PackedTexture
            // describes a single texture or tile set packed into a texture atlas. The
            // fire texture in this example consists of 4 tiles.
            ps.Parameters.AddUniform <PackedTexture>(ParticleParameterNames.Texture).DefaultValue =
                new PackedTexture(
                    "FireParticles",
                    contentManager.Load <Texture2D>("Campfire/FireParticles"),
                    Vector2F.Zero, Vector2F.One,
                    4, 1);

            // The particle parameter "AnimationTime" determines which tile is used,
            // where 0 = first tile, 1 = last tile.
            // --> Chooses a random tile for each particle when it is created.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.AnimationTime);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.AnimationTime,
                Distribution = new UniformDistributionF(0, 1),
            });

            // Fire needs additive blending.
            ps.Parameters.AddUniform <float>(ParticleParameterNames.BlendMode).DefaultValue = 0;

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }
示例#17
0
        public static ParticleSystem Create(ContentManager contentManager)
        {
            var ps = new ParticleSystem
            {
                Name = "BeeSwarm",
                MaxNumberOfParticles = 100,
            };

            ps.Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = float.PositiveInfinity;

            ps.Parameters.AddVarying <Vector3F>(ParticleParameterNames.Position);
            ps.Effectors.Add(new StartPositionEffector
            {
                Parameter    = ParticleParameterNames.Position,
                DefaultValue = new Vector3F(0, 0, 0)
            });

            ps.Parameters.AddUniform <float>(ParticleParameterNames.SizeY).DefaultValue = 0.1f;

            // The SizeX is varying because the BeeEffector sets a negative size if the bee should look in the
            // opposite direction.
            ps.Parameters.AddVarying <float>(ParticleParameterNames.SizeX);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.SizeX,
                DefaultValue = 0.1f,
            });

            ps.Parameters.AddVarying <float>(ParticleParameterNames.LinearSpeed);
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = ParticleParameterNames.LinearSpeed,
                Distribution = new UniformDistributionF(1, 2),
            });

            // The BeeEffector creates the random movement of the bees.
            ps.Parameters.AddVarying <Vector3F>("TargetPosition");
            ps.Parameters.AddUniform <Pose>("CameraPose").DefaultValue = Pose.Identity;
            ps.Effectors.Add(new BeeEffector
            {
                PositionParameter       = ParticleParameterNames.Position,
                TargetPositionParameter = "TargetPosition",
                SpeedParameter          = ParticleParameterNames.LinearSpeed,
                SizeXParameter          = ParticleParameterNames.SizeX,
                CameraPoseParameter     = "CameraPose",
                InvertLookDirection     = true,
                MaxRange = 4.0f,
            });

            // The texture is a set of 3 images.
            ps.Parameters.AddUniform <PackedTexture>(ParticleParameterNames.Texture).DefaultValue =
                new PackedTexture(
                    "Bee",
                    contentManager.Load <Texture2D>("Particles/beeWingFlap"),
                    Vector2F.Zero, Vector2F.One,
                    3, 1);

            // The Frame particle parameter stores the index of the animation frame and the
            // AnimationTime particle parameter stores the current progress in seconds.
            ps.Parameters.AddVarying <int>("Frame");
            ps.Parameters.AddVarying <float>("AnimationTime");

            // Initialize the AnimationTime with a random value, otherwise all bees would look
            // the same.
            ps.Effectors.Add(new StartValueEffector <float>
            {
                Parameter    = "AnimationTime",
                Distribution = new UniformDistributionF(0, 0.125f),
            });

            // The AnimationEffector advances the AnimationTime and sets the Frame.
            // It changes frames at 24 fps.
            ps.Effectors.Add(new AnimationEffector
            {
                AnimationTimeParameter = "AnimationTime",
                FramesPerSecond        = 24,
                NumberOfFrames         = 3,
            });

            ParticleSystemValidator.Validate(ps);

            return(ps);
        }