/// <summary> /// LateUpdate will prepare and call for calculations on each particle system. /// All threaded calculation is done after Update to ensure stable movement of particles. /// </summary> void LateUpdate() { activeThreads = 0; if (activeSystems.Count>0) activeSystems.Clear(); frameCount++; isFirstUnsafeAutomaticFrames = frameCount<unsafeAutomaticThreadFrames||threadAggregatorRuns<unsafeAutomaticThreadFrames; if (reference!=this) { InitializePlayground(); return; } // Update time SetTime(); // Check the global event delegates for availability CheckEvents(); // Prepare all global manipulators for (int m = 0; m<manipulators.Count; m++) manipulators[m].Update(); // Return if no particle systems are available if (particleSystems.Count==0) return; hasActiveParticleSystems = false; hasLocalNoThreads = false; hasLocalOnePerSystem = false; hasLocalOneForAll = false; hasActiveSkinnedMeshes = false; hasActiveTurbulence = false; if (previousThreadMethod!=threadMethod) { isDoneThread = true; previousThreadMethod = threadMethod; } if (threadMethod!=ThreadMethod.OneForAll) isDoneThread = true; if (previousSkinnedMeshThreadMethod!=skinnedMeshThreadMethod) { isDoneThreadSkinned = true; previousSkinnedMeshThreadMethod = skinnedMeshThreadMethod; } if (previousTurbulenceThreadMethod!=turbulenceThreadMethod) { isDoneThreadTurbulence = true; previousTurbulenceThreadMethod = turbulenceThreadMethod; } // Prepare all particle systems Camera mainCamera = Camera.main; bool frustumPlanesSet = false; bool hasSourceUpdateNow = false; int currentParticleSystemCount = particleSystems.Count; for (int i = 0; i<particleSystems.Count; i++) { if (particleSystems[i]!=null && !particleSystems[i].isSnapshot && particleSystems[i].shurikenParticleSystem!=null && particleSystems[i].particleSystemGameObject.activeInHierarchy && particleSystems[i].Initialized() && !particleSystems[i].IsSettingParticleCount() && !particleSystems[i].IsSettingLifetime() && !particleSystems[i].IsYieldRefreshing() && !particleSystems[i].InTransition() && !particleSystems[i].IsLoading() && !particleSystems[i].IsPrewarming() && !particleSystems[i].IsSettingParticleTime()) { // Catch up Shuriken particle lifetime with the update rate if (Time.frameCount%particleSystems[i].updateRate!=0) { for (int p = 0; p<particleSystems[i].particleCount; p++) particleSystems[i].particleCache[p].lifetime = (particleSystems[i].playgroundCache.death[p]-particleSystems[i].playgroundCache.birth[p])-particleSystems[i].playgroundCache.lifetimeSubtraction[p]; particleSystems[i].isReadyForThreadedCalculations = false; continue; } // Handle any system additions or removals if (currentParticleSystemCount > particleSystems.Count) { if (i>0) { i--; currentParticleSystemCount = particleSystems.Count; } else {hasActiveParticleSystems=false; return;} } else if (currentParticleSystemCount < particleSystems.Count) { currentParticleSystemCount = particleSystems.Count; } if (particleSystems.Count==0 || i>=particleSystems.Count) {hasActiveParticleSystems=false; return;} // Update the main camera frustum planes (this is used for culling particle systems) if (!frustumPlanesSet && particleSystems[i].pauseCalculationWhenInvisible && mainCamera!=null && mainCamera.enabled) { frustumPlanes = GeometryUtility.CalculateFrustumPlanes(mainCamera); frustumPlanesSet = true; } // Update any particle system using onlySourcePositioning or onlyLifetimePositioning if (particleSystems[i].onlySourcePositioning||particleSystems[i].onlyLifetimePositioning) if (!particleSystems[i].UpdateSystem()) continue; // Update any changes. Particle system may also be removed here. if (particleSystems.Count>0 && i<particleSystems.Count) { // Prepare for threaded calculations particleSystems[i].isReadyForThreadedCalculations = particleSystems[i].PrepareThreadedCalculations(); if (particleSystems[i].IsAlive()) { hasActiveParticleSystems = true; if (particleSystems[i].onlySourcePositioning||particleSystems[i].onlyLifetimePositioning) hasSourceUpdateNow = true; if (threadMethod==ThreadMethod.Automatic) activeSystems.Add (i); if (!particleSystems[i].forceSkinnedMeshUpdateOnMainThread && particleSystems[i].IsSkinnedWorldObjectReady() && particleSystems[i].calculate) hasActiveSkinnedMeshes = true; if (particleSystems[i].HasTurbulence() && particleSystems[i].calculate) hasActiveTurbulence = true; switch (particleSystems[i].threadMethod) { case ThreadMethodLocal.NoThreads:hasLocalNoThreads=true;break; case ThreadMethodLocal.OnePerSystem:hasLocalOnePerSystem=true;break; case ThreadMethodLocal.OneForAll:hasLocalOneForAll=true;break; } } else particleSystems[i].isReadyForThreadedCalculations = false; } else if (particleSystems.Count>0 && i<particleSystems.Count && particleSystems[i]!=null) { particleSystems[i].isReadyForThreadedCalculations = false; } } else if (particleSystems[i]!=null) { particleSystems[i].isReadyForThreadedCalculations = false; if (particleSystems[i].IsPrewarming()) { if (particleSystems[i].HasTurbulence()) { hasActiveTurbulence = true; hasActiveParticleSystems = true; } } } } // Proceed if we have any active particle systems if (hasActiveParticleSystems) { // Call for threaded calculations ThreadAggregator(); // Call for immediate update on particle systems using onlySourcePositioning or onlyLifetimePositioning if (hasSourceUpdateNow) { for (int i = 0; i<particleSystems.Count; i++) { if (particleSystems[i]!=null && (particleSystems[i].onlySourcePositioning || particleSystems[i].onlyLifetimePositioning) && particleSystems[i].isReadyForThreadedCalculations && !particleSystems[i].InTransition() && !particleSystems[i].IsLoading() && particleSystems[i].IsReady()) { particleSystems[i].UpdateShuriken(); } } } } // Reset hierarchy repaint check #if UNITY_EDITOR PlaygroundParticlesC.didHierarchyRepaint = false; #endif }
// Update is called both in Edit- and Play Mode once per frame void Update() { activeThreads = 0; frameCount++; isFirstUnsafeAutomaticFrames = frameCount<unsafeAutomaticThreadFrames||threadAggregatorRuns<unsafeAutomaticThreadFrames; if (reference!=this) { InitializePlayground(); return; } // Update time SetTime(); // Check the global event delegates for availability CheckEvents(); // Prepare all global manipulators for (int m = 0; m<manipulators.Count; m++) manipulators[m].Update(); // Return if no particle systems are available if (particleSystems.Count==0) return; hasActiveParticleSystems = false; hasLocalNoThreads = false; hasLocalOnePerSystem = false; hasLocalOneForAll = false; hasActiveSkinnedMeshes = false; hasActiveTurbulence = false; if (previousThreadMethod!=threadMethod) { isDoneThread = true; previousThreadMethod = threadMethod; } if (threadMethod!=ThreadMethod.OneForAll) isDoneThread = true; if (previousSkinnedMeshThreadMethod!=skinnedMeshThreadMethod) { isDoneThreadSkinned = true; previousSkinnedMeshThreadMethod = skinnedMeshThreadMethod; } if (previousTurbulenceThreadMethod!=turbulenceThreadMethod) { isDoneThreadTurbulence = true; previousTurbulenceThreadMethod = turbulenceThreadMethod; } // Prepare all particle systems int currentParticleSystemCount = particleSystems.Count; for (int i = 0; i<particleSystems.Count; i++) { if (particleSystems[i]!=null && particleSystems[i].calculate && !particleSystems[i].isSnapshot && particleSystems[i].shurikenParticleSystem!=null && particleSystems[i].particleSystemGameObject.activeInHierarchy && particleSystems[i].Initialized() && !particleSystems[i].IsSettingParticleCount() && !particleSystems[i].IsSettingLifetime() && !particleSystems[i].IsYieldRefreshing() && !particleSystems[i].InTransition() && !particleSystems[i].IsLoading() && Time.frameCount%particleSystems[i].updateRate==0) { if (currentParticleSystemCount > particleSystems.Count) { if (i>0) { i--; currentParticleSystemCount = particleSystems.Count; } else return; } else if (currentParticleSystemCount < particleSystems.Count) { currentParticleSystemCount = particleSystems.Count; } if (particleSystems.Count==0 || i>=particleSystems.Count) return; // Update any changes. Particle system may also be removed here. if (particleSystems[i].UpdateSystem() && (particleSystems.Count>0 && i<particleSystems.Count)) { // Prepare for threaded calculations particleSystems[i].isReadyForThreadedCalculations = particleSystems[i].PrepareThreadedCalculations(); if (particleSystems[i].IsAlive()) { hasActiveParticleSystems = true; if (particleSystems[i].IsSkinnedWorldObjectReady()) hasActiveSkinnedMeshes = true; if (particleSystems[i].HasTurbulence()) hasActiveTurbulence = true; switch (particleSystems[i].threadMethod) { case ThreadMethodLocal.NoThreads:hasLocalNoThreads=true;break; case ThreadMethodLocal.OnePerSystem:hasLocalOnePerSystem=true;break; case ThreadMethodLocal.OneForAll:hasLocalOneForAll=true;break; } } else particleSystems[i].isReadyForThreadedCalculations = false; } else if (particleSystems.Count>0 && i<particleSystems.Count && particleSystems[i]!=null) { particleSystems[i].isReadyForThreadedCalculations = false; } } else if (particleSystems[i]!=null) particleSystems[i].isReadyForThreadedCalculations = false; } // Call for threaded calculations if (hasActiveParticleSystems) ThreadAggregator(); }