protected override void Initialise() { Camera2D camera = new Camera2D(); //create the draw target. drawToScreen = new DrawTargetScreen(camera); drawToScreen.ClearBuffer.ClearColour = Color.Black; // uncomment this to force theparticle system to run on the CPU // Note: This property is not available on the xbox. //ParticleSystem.ForceUseCpuParticleSystem = true; // Use ParticleSystem.SystemSupportsGpuParticles to determine if the particle // system will be run on the GPU // // NOTE: When running on the GPU, the particle system will be processed in 16bit floating point // The CPU particle system is not supported on the Xbox. //NEW CODE //create the particle system this.particles = new ParticleSystem(this.UpdateManager); //Like ModelInstance, the ParticleSystem content must be assigned before it can be drawn //create the particle drawer, //In this case, use a VelocityBillboardParticles2DElement. //This is a special particle drawer that will 'stretch' particles in the direction they are //travelling - giving them a streaky look. // particleDrawer = new Xen.Ex.Graphics.Display.VelocityBillboardParticles2DElement(this.particles, true); //align the drawer to the bottom centre of the screen particleDrawer.VerticalAlignment = VerticalAlignment.Bottom; particleDrawer.HorizontalAlignment = HorizontalAlignment.Centre; //add it to ths screen drawToScreen.Add(particleDrawer); }
public HandController(Camera camera, Scene scene, ContentState state) { this.camera = camera; hand = ObjectComposer.Compose(scene, state) .AppendName("hand") .AppendMesh("hand") .AppendMaterialTextures("hand_map", "hand_map") .AppendWorld(Vector3.Zero,Vector3.Zero, Vector3.One * 0.02f) .AppendDummyCollider() .FinishAndAddToScene(); int animationIndex = hand.Model.GetAnimationController().AnimationIndex("Take 001"); hand.Model.GetAnimationController().PlayLoopingAnimation(animationIndex); bonesController = new HandAnimator(hand.Model.ModelData); hand.BoneModifier = bonesController; curseParticles = new ParticleSystem(state.Application.UpdateManager); TestScene._instance.AddDrawable(new BillboardParticles3D(curseParticles)); curseParticles.ParticleSystemData = TestScene._instance.state.Load<ParticleSystemData>("Particles/Spark"); curseParticlesTriger = curseParticles.GetTriggerByName("burst"); }
//the logic to emit a single particle public void Emit(ParticleSystem system, ParticleSystemEmitData emit, int sourceIndex, float sourceIndexF, int step) { //need more capacity? if (particleCapacity == particles.Length) Array.Resize(ref this.particles, this.particles.Length * 2); uint index = particleCapacity++; //for profiling maxParticleCapacity = Math.Max(maxParticleCapacity, index); //find the step the particle will be removed on int stepIndex = emit.baseLifeTimeStep; if (emit.varianceTimeStep != 0) stepIndex += system.systemRandom.Next(emit.varianceTimeStep); stepIndex = Math.Max(1, stepIndex); //lifespan in steps int life = stepIndex; //remove step stepIndex = (stepIndex + step) & timeStepMask; //create the particle Particle particle = new Particle(); particle.index = particleCapacityF++; particle.previousParticleIndexForTimeStep = uint.MaxValue; particle.nextParticleIndexForTimeStep = uint.MaxValue; particle.addActionIndex = addActionCount; if (timeSteps[stepIndex].count++ != 0) { //step isn't empty? uint previousFirst = timeSteps[stepIndex].firstParticleIndex; particle.nextParticleIndexForTimeStep = previousFirst; particles[previousFirst].previousParticleIndexForTimeStep = index; } //start of the linked list timeSteps[stepIndex].firstParticleIndex = index; particle.timeStepIndex = (ushort)stepIndex; //store this.particles[index] = particle; //create the addAction AddAction action = new AddAction(); action.index = index; action.lifeSteps = (uint)life; action.indexF = particle.index; action.cloneFromIndex = sourceIndex; action.cloneFromIndexF = sourceIndexF; action.cloneTypeIndex = emit.emitFromTypeIndex; //if sourceIndex is -1, then this is a root level particle, //so it's positin is set by the application. if (sourceIndex == -1) { system.GetSpawnDetails(out action.spawnDetails); } typeEmitDependancy[emit.emitFromTypeIndex + 1] = true; //cannot spawn more than 32k particles in a single frame if (addActionCount != (ushort)short.MaxValue) { addActions[addActionCount] = action; if (++addActionCount == addActions.Length) Array.Resize(ref addActions, addActions.Length * 2); } }
//void ValidateSteps() //{ // for (int i = 0; i < this.timeSteps.Length; i++) // { // uint prev = uint.MaxValue; // uint index = this.timeSteps[i].firstParticleIndex; // // for (int p = 0; p < this.timeSteps[i].count; p++) // { // if (this.particles[index].previousParticleIndexForTimeStep != prev) // throw new ArgumentException(); // prev = index; // index = this.particles[index].nextParticleIndexForTimeStep; // } // // if (this.timeSteps[i].count > 0 && index != uint.MaxValue) // throw new ArgumentException(); // } //} //the meat of the system public void Update(ParticleSystem system, int step) { int stepIndex = step & timeStepMask; SystemTimeStep timestep = timeSteps[stepIndex]; timeSteps[stepIndex] = new SystemTimeStep(); uint particleIndex = timestep.firstParticleIndex; //run per frame logic for the type if (frameEmitter != null) frameEmitter.RunParticleType(system, this, step); //iterate twice. //first pass, generate the operations to remove the particles //in the second pass, run the remove emitter, if there is one. //this way, a particle created in the removed emitter will not be rearranged //by another removed particle later //this is mostly for the benfit of the GPU system // uint copyCount = copyActionCount; if (timestep.count > 0) { Particle particle, replace; //first, collect the indices for removal, if they exist if (removeEmitter != null) { uint removeIndex = particleIndex; int count = 2; while (timestep.count > count) count *= 2; if (removeIndices == null || count > removeIndices.Length) Array.Resize(ref removeIndices, count); RemoveIndex indexEntry; for (int i = 0; i < timestep.count; i++) { particle = this.particles[removeIndex]; indexEntry.index = removeIndex; indexEntry.indexF = particle.index; removeIndices[i] = indexEntry; removeIndex = particle.nextParticleIndexForTimeStep; } } //now remove them for (int i = 0; i < timestep.count; i++) { particle = this.particles[particleIndex]; --particleCapacityF; uint last = --particleCapacity; //move last particle into this one's position replace = this.particles[last]; //unless it's being removed anyway if (particleIndex != last) { //update the linked list indexing of the particles... if (replace.previousParticleIndexForTimeStep != uint.MaxValue) this.particles[replace.previousParticleIndexForTimeStep].nextParticleIndexForTimeStep = particleIndex; else { if (replace.timeStepIndex != stepIndex) this.timeSteps[replace.timeStepIndex].firstParticleIndex = particleIndex; } //particle has been moved once already in this update? (rare) if (replace.nextParticleIndexForTimeStep != uint.MaxValue) this.particles[replace.nextParticleIndexForTimeStep].previousParticleIndexForTimeStep = particleIndex; //may be moving the next particle in the list... if (particle.nextParticleIndexForTimeStep == last) particle.nextParticleIndexForTimeStep = particleIndex; //store the copy action... //but first... if (replace.addActionIndex < addActionCount && this.addActions[replace.addActionIndex].index == last) { //this particle was just added in this frame, now it's being moved //so modify the add action instead to directly write to the position this.addActions[replace.addActionIndex].index = particleIndex; this.addActions[replace.addActionIndex].indexF = particle.index; } else { if (replace.addActionIndex >= short.MaxValue) // add action indices above 32k are for copy indices { //the particle is already being copied... //so modify the existing copy op copyActions[replace.addActionIndex - short.MaxValue].indexTo = particleIndex; copyActions[replace.addActionIndex - short.MaxValue].indexToF = particle.index; } else { //otherwise do a copy CopyAction copy = new CopyAction(); copy.indexTo = particleIndex; copy.indexToF = particle.index; copy.indexFrom = last; copy.indexFromF = replace.index; replace.addActionIndex = (ushort)(short.MaxValue + copyActionCount); copyActions[copyActionCount] = copy; if (++copyActionCount == copyActions.Length) Array.Resize(ref copyActions, copyActions.Length * 2); } } replace.index = particle.index; this.particles[particleIndex] = replace; } particleIndex = particle.nextParticleIndexForTimeStep; } //now finally run the remove emitters. if (removeEmitter != null) { RemoveIndex index; for (int i = 0; i < timestep.count; i++) { index = removeIndices[i]; if (removeEmitter != null) removeEmitter.RunParticle(system, this, index.index, index.indexF, step); } } } for (uint i = copyCount; i < copyActionCount; i++) { this.particles[copyActions[i].indexTo].addActionIndex = 0; } }
//run particle logic every so 'value' steps internal void RunParticleTypeEvery(ParticleSystem system, int step, int value, ref ParticleSystemActionData child) { //int stepBase = step + timeStepCount; if (value > 3) { //step is getting pretty big... //so... //don't loop all the particles, loop the timesteps that match //then loop all their particles. //this accesses less data but jumps around a lot. SystemTimeStep timestep; for (int t = 0; t < this.timeStepCount; t += value) { //this step is affected, so iterate all it's children. timestep = this.timeSteps[(step + t) & timeStepMask]; uint index = timestep.firstParticleIndex; for (int i = 0; i < timestep.count; i++) { child.RunParticleChildren(system, this, index, this.particles[index].index, step); index = particles[index].nextParticleIndexForTimeStep; } } } else { uint cap =particleCapacity; float f = 0; for (uint i = 0; i < cap; i++) { if (((step + particles[i].timeStepIndex) % value) == 0) child.RunParticleChildren(system, this, i, f, step); f++; } } }
//run particle logic one particle at a time internal void RunParticleTypeOneByOne(ParticleSystem system, int step, ref ParticleSystemActionData child) { uint cap = particleCapacity; float f = 0; for (uint i = 0; i < cap; i++) child.RunParticle(system, this, i,f++, step); }
//emit a particle from every particle public void EmitEach(ParticleSystem system, ParticleSystemEmitData emit, int step) { //emits one particle from every particle. //don't want to emit from a particle being emitted... (recursive emit) int cap = (int)particleCapacity; float f = 0; for (int i = 0; i < cap; i++) system.Emit(emit,i,f++); }
protected override void Initialise() { var tutorials = new Dictionary<string, Type>(); Program.FindTutorials(tutorials); Camera3D camera = new Camera3D(); drawToScreen = new DrawTargetScreen(camera); backgroundParticles = new ParticleSystem(this.UpdateManager); backgroundParticles.GlobalValues[0] = ArrowXOffset; backgroundParticles.GlobalValues[2] = (float)this.WindowWidth; backgroundParticles.GlobalValues[3] = (float)this.WindowHeight; particlesTarget = new DrawTargetTexture2D(camera, this.WindowWidth, this.WindowHeight, SurfaceFormat.Color, DepthFormat.None); particlesBlurred = new DrawTargetTexture2D(camera, this.WindowWidth / 2, this.WindowHeight / 2, SurfaceFormat.Color, DepthFormat.None); DrawTargetTexture2D inter0 = null, inter1 = null; quaterDownsample = new TextureDownsample(particlesTarget, particlesBlurred, ref inter0, ref inter1, particlesBlurred.Width, particlesBlurred.Height); inter0 = new DrawTargetTexture2D(camera, particlesBlurred.Width, particlesBlurred.Height, SurfaceFormat.Color, DepthFormat.None); blurFilter = new BlurFilter(BlurFilterFormat.SevenSampleBlur, 1, particlesBlurred, inter0); backroundDrawer = new VelocityBillboardParticles2DElement(backgroundParticles, false); particlesTarget.Add(backroundDrawer); //draw the resolved particles to the screen drawToScreen.Add(new TexturedElement(particlesTarget, new Vector2(1, 1), true)); //background block other elements are inserted into. invisible var selectionBlock = new Xen.Ex.Graphics2D.SolidColourElement(new Color(0, 0, 0, 0), new Vector2(ElementWidth, tutorials.Count * ElementSeparation)); selectionBlock.AlphaBlendState = AlphaBlendState.Alpha; selectionBlock.VerticalAlignment = VerticalAlignment.Top; this.menuBlock = selectionBlock; int y_pos = 0; foreach (var tutorial in tutorials) { var tut_item = new TutorialSelection(tutorial.Key, y_pos, this.Content, selectionBlock, this.UpdateManager, tutorial.Value); y_pos -= ElementSeparation; buttons.Add(tut_item); } drawToScreen.Add(selectionBlock); var bloom = new TexturedElement(particlesBlurred, new Vector2(1, 1), true); bloom.AlphaBlendState = AlphaBlendState.AdditiveSaturate; drawToScreen.Add(bloom); this.logo = new TexturedElement(new Vector2(282,100)); this.logo.VerticalAlignment = VerticalAlignment.Top; this.logo.HorizontalAlignment = HorizontalAlignment.Centre; this.logo.Position = new Vector2(0, -50); this.helperText = new TextElementRect(new Vector2(800,100),"Use the DPAD to select an item, press 'A' to run the example\nWhen running an example, press 'back' to return to this menu"); this.helperText.VerticalAlignment = VerticalAlignment.Bottom; this.helperText.HorizontalAlignment = HorizontalAlignment.Centre; this.helperText.TextHorizontalAlignment = TextHorizontalAlignment.Centre; this.helperText.TextVerticalAlignment = VerticalAlignment.Centre; this.helperText.Colour = Color.Gray; drawToScreen.Add(logo); drawToScreen.Add(helperText); }
private void SetParticles(ContentState state) { if (_level == 2) { ParticleSystem particles = new ParticleSystem(state.Application.UpdateManager); followingParticles.Add(particles); drawToScreen.Add(new BillboardParticles3D(particles)); particles.ParticleSystemData = state.Load<ParticleSystemData>("Particles/Mist"); } if (_level == 3) { ParticleSystem particles = new ParticleSystem(state.Application.UpdateManager); followingParticles.Add(particles); ParticleDrawer3D fogDrawer = new BillboardParticles3D(particles); ParticleDrawer3D snowDrawer = new VelocityBillboardParticles3D(particles, false, 0.1f); drawToScreen.Add(fogDrawer); drawToScreen.Add(snowDrawer); particles.ParticleSystemData = state.Load<ParticleSystemData>("Particles/Snow"); fogDrawer.SetParticleTypeDrawMask("fog", true); fogDrawer.SetParticleTypeDrawMask("snow", false); snowDrawer.SetParticleTypeDrawMask("fog", false); snowDrawer.SetParticleTypeDrawMask("snow", true); } else if (_level == 2) { } }
protected override void Initialise() { //draw targets usually need a camera. var camera = new Xen.Camera.FirstPersonControlledCamera3D(this.UpdateManager, Vector3.Zero, false); //don't allow the camera to move too fast camera.MovementSensitivity *= 0.1f; camera.LookAt(new Vector3(0,3,0), new Vector3(1, 5, 10), new Vector3(0, 1, 0)); //create the draw target. drawToScreen = new DrawTargetScreen(camera); drawToScreen.ClearBuffer.ClearColour = new Color(45,50,60); //create the fire and smoke particle system this.fireParticleSystem = new ParticleSystem(this.UpdateManager); this.smokeParticleSystem = new ParticleSystem(this.UpdateManager); //IMPORTANT //The following flags are FALSE by default. //For looping effects, such as the fire and smoke, it's highly //recommended to enable this flag. Otherwise, while the effect //is offscreen, the particle system will continue to process. this.fireParticleSystem.PauseUpdatingWhileCulled = true; this.smokeParticleSystem.PauseUpdatingWhileCulled = true; this.drawSorted = new Xen.Ex.Scene.DepthDrawSorter(Xen.Ex.Scene.DepthSortMode.BackToFront); this.drawUnsorted = new DrawList(); var fireDrawer = new Xen.Ex.Graphics.Display.VelocityBillboardParticles3D(this.fireParticleSystem, true); var smokeDrawer = new Xen.Ex.Graphics.Display.BillboardParticles3D(this.smokeParticleSystem); for (int i = 0; i < 10; i++) { Vector3 position = new Vector3((float)Math.Cos(i * Math.PI / 5.0) * 6.0f, 0, (float)Math.Sin(i * Math.PI / 5.0) * 6.0f); CullableParticleWrapper fireEffect, smokeEffect; fireEffect = new CullableParticleWrapper(fireDrawer, position, new Vector3(0, 2, 0), 4); smokeEffect = new CullableParticleWrapper(smokeDrawer, position, new Vector3(0, 6, 0), 5); this.drawSorted.Add(fireEffect); this.drawSorted.Add(smokeEffect); this.drawUnsorted.Add(fireEffect); this.drawUnsorted.Add(smokeEffect); var light = new GroundLightDisk(position); this.drawSorted.Add(light); this.drawUnsorted.Add(light); } //setup the burst effect this.burstParticleSystem = new ParticleSystem(this.UpdateManager); //for this case, PauseUpdatingWhileCulled is not set to true. //The particle emitting is culled when offscreen. If set to true, //Any particles left offscreen could 'pause', when they naturally //wouldn't be emitted anyway. //(The particle system will use very few resources when it has no //active particles) this.burstSources = new BurstSource[20]; Random rand = new Random(); for (int i = 0; i < this.burstSources.Length; i++) { //create the bursts out in the distance Vector3 position = new Vector3((float)i * 5.0f - this.burstSources.Length * 2.5f, 0, -20); float radius = 10; // with a decent radius //give them a random starting time this.burstSources[i] = new BurstSource(position, radius, (float)rand.NextDouble() * 2); this.drawSorted.Add(this.burstSources[i]); this.drawUnsorted.Add(this.burstSources[i]); } //the bursts need to be drawn as a group.. var burstDrawer = new Xen.Ex.Graphics.Display.VelocityBillboardParticles3D(this.burstParticleSystem,false,0.5f); this.drawSorted.Add(burstDrawer); this.drawUnsorted.Add(burstDrawer); //Use all the burst sources to cull the drawer (may not be ideal if there were many sources...) //Use the particle drawer CullProxy to do it burstDrawer.CullProxy = new BurstCullProxy(this.burstSources); //add a ground plane to show the horizon drawToScreen.Add(new Tutorial_22.DarkGroundPlane(new Vector4(0.125f,0.15f,0.135f,1))); //add the sorted and unsorted lists drawToScreen.Add(drawSorted); drawToScreen.Add(drawUnsorted); //finally, create a CullTestVisualizer, which will visually show the cull tests performed cullTestVisualizer = new Xen.Ex.Scene.CullTestVisualizer(); //the visualizer is added as a draw modifier this.drawToScreen.AddModifier(cullTestVisualizer); //add help text this.text = new TextElement(); this.text.VerticalAlignment = VerticalAlignment.Bottom; this.text.Position = new Vector2(50, 100); drawToScreen.Add(this.text); //add draw stats stats = new Xen.Ex.Graphics2D.Statistics.DrawStatisticsDisplay(this.UpdateManager); drawToScreen.Add(stats); }
/// <summary> /// Construct the particle drawer /// </summary> /// <param name="system"></param> /// <param name="useRotationValueToScaleVelocityEffect"><para>When true, the per particle rotation value will be used to scale the velocity stretching effect</para><para>Allowing per-particle scaling based on velocity</para></param> public VelocityBillboardParticles2DElement(ParticleSystem system, bool useRotationValueToScaleVelocityEffect) : base(system) { this.useRotationToScaleVelocityEffect = useRotationValueToScaleVelocityEffect; }
/// <summary> /// Construct the Velocity Billboard particles /// </summary> /// <param name="system"></param> /// <param name="useRotationValueToScaleVelocityEffect"><para>When true, the per particle rotation value will be used to scale the velocity stretching effect</para><para>Allowing per-particle scaling based on velocity</para></param> /// <param name="velocityExtentionScale">Scale factor to extend the particles</param> public VelocityBillboardParticles2DElement(ParticleSystem system, bool useRotationValueToScaleVelocityEffect, float velocityExtentionScale) : base(system) { this.UseRotationValueToScaleVelocityEffect = useRotationValueToScaleVelocityEffect; this.VelocityExtentionScale = velocityExtentionScale; }