public static void ThreadedCalculations (PlaygroundParticlesC playgroundParticles) {

			// Component disabled?
			if (!playgroundParticles.enabled || !playgroundParticles.isDoneThread) return;

			// Has the calculation been paused previously?
			if (playgroundParticles.cameFromNonCalculatedFrame) {
				playgroundParticles.Start();
				playgroundParticles.cameFromNonCalculatedFrame = false;
				return;
			}
		
			// Apply locked position
			if (playgroundParticles.applyLockPosition) {
				if (playgroundParticles.lockPositionIsLocal)
					playgroundParticles.particleSystemTransform.localPosition = playgroundParticles.lockPosition;
				else
					playgroundParticles.particleSystemTransform.position = playgroundParticles.lockPosition;
			}

			// Apply locked rotation
			if (playgroundParticles.applyLockRotation) {
				if (playgroundParticles.lockRotationIsLocal)
					playgroundParticles.particleSystemTransform.localRotation = Quaternion.Euler(playgroundParticles.lockRotation);
				else
					playgroundParticles.particleSystemTransform.rotation = Quaternion.Euler(playgroundParticles.lockRotation);
			}

			// Apply locked scale
			if (playgroundParticles.applyLockScale)
				playgroundParticles.particleSystemTransform.localScale = playgroundParticles.lockScale;
				

			// Set delta time
			playgroundParticles.localDeltaTime = PlaygroundC.globalTime-playgroundParticles.lastTimeUpdated;
			playgroundParticles.lastTimeUpdated = PlaygroundC.globalTime;
			float t = (playgroundParticles.localDeltaTime*playgroundParticles.particleTimescale);

			// Prepare Source positions
			Vector3 	stPos = Vector3.zero;
			Quaternion 	stRot = Quaternion.identity;
			Vector3 	stSca = new Vector3(1f, 1f, 1f);
			Vector3		stDir = new Vector3();
			bool 		localSpace = (playgroundParticles.shurikenParticleSystem.simulationSpace == ParticleSystemSimulationSpace.Local);
			bool 		overflow = (playgroundParticles.overflowOffset!=Vector3.zero);
			bool 		skinnedWorldObjectReady = false;
			playgroundParticles.renderModeStretch = playgroundParticles.particleSystemRenderer2.renderMode==ParticleSystemRenderMode.Stretch;
			
			if (playgroundParticles.emit) {
				switch (playgroundParticles.source) {
				case SOURCEC.Script:

				break;
				case SOURCEC.State:
					if (playgroundParticles.states.Count>0) {
						if (playgroundParticles.states[playgroundParticles.activeState].stateTransform!=null) {

							if (!playgroundParticles.states[playgroundParticles.activeState].initialized)
								playgroundParticles.states[playgroundParticles.activeState].Initialize ();

							stPos = playgroundParticles.states[playgroundParticles.activeState].stateTransform.position;
							stRot = playgroundParticles.states[playgroundParticles.activeState].stateTransform.rotation;
							stSca = playgroundParticles.states[playgroundParticles.activeState].stateTransform.localScale;
							if (localSpace && (playgroundParticles.states[playgroundParticles.activeState].stateTransform.parent==playgroundParticles.particleSystemTransform || playgroundParticles.states[playgroundParticles.activeState].stateTransform==playgroundParticles.particleSystemTransform)) {
								stPos = Vector3.zero;
								stRot = Quaternion.Euler (Vector3.zero);
							}
						}
					} else return;
					break;
				case SOURCEC.Transform:
					stPos = playgroundParticles.sourceTransform.position;
					stRot = playgroundParticles.sourceTransform.rotation;
					stSca = playgroundParticles.sourceTransform.localScale;
					if (localSpace && playgroundParticles.sourceTransform==playgroundParticles.particleSystemTransform) {
						stPos = Vector3.zero;
						stRot = Quaternion.Euler (Vector3.zero);
					}
					break;
				case SOURCEC.WorldObject:
					
					// Handle vertex data in active World Object
					if (playgroundParticles.worldObject.gameObject!=null) {
						if (playgroundParticles.worldObject.gameObject.GetInstanceID()!=playgroundParticles.worldObject.cachedId) 
							playgroundParticles.worldObject = NewWorldObject(playgroundParticles.worldObject.gameObject.transform);
						if (playgroundParticles.worldObject.mesh!=null) {
							stPos = playgroundParticles.worldObject.transform.position;
							stRot = playgroundParticles.worldObject.transform.rotation;
							stSca = playgroundParticles.worldObject.transform.localScale;
							if (localSpace) {
								stPos = Vector3.zero;
								stRot = Quaternion.Euler (Vector3.zero);
							}
							
							playgroundParticles.worldObject.updateNormals = playgroundParticles.worldObjectUpdateNormals;
							if (playgroundParticles.worldObjectUpdateVertices)
								playgroundParticles.worldObject.Update ();
						} else return;
					} else return;
					break;
				case SOURCEC.SkinnedWorldObject:

					// Handle vertex data in active Skinned World Object
					if (playgroundParticles.skinnedWorldObject.gameObject!=null) {
						if (playgroundParticles.skinnedWorldObject.gameObject.GetInstanceID()!=playgroundParticles.skinnedWorldObject.cachedId)
							playgroundParticles.skinnedWorldObject = NewSkinnedWorldObject(playgroundParticles.skinnedWorldObject.gameObject.transform, playgroundParticles.skinnedWorldObject.downResolution);
					}
					skinnedWorldObjectReady = playgroundParticles.skinnedWorldObject.gameObject!=null && playgroundParticles.skinnedWorldObject.mesh!=null;
					if (skinnedWorldObjectReady) {
						
						stPos = playgroundParticles.skinnedWorldObject.transform.position;
						stRot = playgroundParticles.skinnedWorldObject.transform.rotation;
						stSca = playgroundParticles.skinnedWorldObject.transform.localScale;
						stDir = playgroundParticles.skinnedWorldObject.transform.TransformDirection (playgroundParticles.overflowOffset);
						
						playgroundParticles.skinnedWorldObject.updateNormals = playgroundParticles.worldObjectUpdateNormals;

						if (Time.frameCount%PlaygroundC.skinnedUpdateRate==0) {
							if (playgroundParticles.worldObjectUpdateVertices)
								playgroundParticles.skinnedWorldObject.MeshUpdate();
							playgroundParticles.skinnedWorldObject.BoneUpdate();
						}
					} else return;
				break;
				case SOURCEC.Paint:
					if (playgroundParticles.paint.initialized) {
						stPos = playgroundParticles.particleSystemTransform.position;
						stRot = playgroundParticles.particleSystemTransform.rotation;
						stSca = playgroundParticles.particleSystemTransform.localScale;

						if (playgroundParticles.paint.positionLength>0) {
							for (int p = 0; p<playgroundParticles.particleCache.Length; p++) {
								playgroundParticles.paint.Update(p);
							}
						} else return;
					} else {
						playgroundParticles.paint.Initialize ();
						return;
					}
				break;
				case SOURCEC.Projection:
					if (playgroundParticles.projection.projectionTexture!=null && playgroundParticles.projection.projectionTransform!=null) {
						if (!playgroundParticles.projection.initialized)
							playgroundParticles.projection.Initialize();

						stPos = playgroundParticles.projection.projectionTransform.position;
						stRot = playgroundParticles.projection.projectionTransform.rotation;
						stSca = playgroundParticles.projection.projectionTransform.localScale;
						
						if (localSpace)
							playgroundParticles.shurikenParticleSystem.simulationSpace = ParticleSystemSimulationSpace.World;
						
						if (playgroundParticles.projection.liveUpdate || !playgroundParticles.projection.hasRefreshed) {
							playgroundParticles.projection.UpdateSource();
							playgroundParticles.projection.Update();
							stDir = playgroundParticles.projection.projectionTransform.TransformDirection (playgroundParticles.overflowOffset);

							playgroundParticles.projection.hasRefreshed = true;
						}
						
					} else return;
				break;
				}
			}

			// Collision detection (runs on main-thread)
			if (playgroundParticles.collision)
				Collisions(playgroundParticles);

			// Sync positions to main-thread
			if (playgroundParticles.syncPositionsOnMainThread) {
				for (int p = 0; p<playgroundParticles.particleCount; p++) {
					playgroundParticles.particleCache[p].position = playgroundParticles.playgroundCache.position[p];
				}
			}

			// Main-thread preparations
			// Prepare Particle colors
			bool stateReadyForTextureColor = (playgroundParticles.source==SOURCEC.State && playgroundParticles.states[playgroundParticles.activeState].stateTexture!=null);

			// Prepare local manipulators
			for (int m = 0; m<playgroundParticles.manipulators.Count; m++) {
				playgroundParticles.manipulators[m].Update();
				playgroundParticles.manipulators[m].transform.SetLocalPosition(playgroundParticles.particleSystemTransform);
				playgroundParticles.manipulators[m].SetLocalTargetsPosition(playgroundParticles.particleSystemTransform);
				playgroundParticles.manipulators[m].willAffect = true;
			}
			// Prepare global manipulators from this local space
			for (int m = 0; m<PlaygroundC.reference.manipulators.Count; m++) {
				PlaygroundC.reference.manipulators[m].willAffect = ((PlaygroundC.reference.manipulators[m].affects.value & 1<<playgroundParticles.particleSystemGameObject.layer)!=0);
				PlaygroundC.reference.manipulators[m].transform.SetLocalPosition(playgroundParticles.particleSystemTransform);
			}

			// Prepare events
			bool hasEvent = playgroundParticles.events.Count>0;
			bool hasTimerEvent = false;
			if (hasEvent) {
				for (int i = 0; i<playgroundParticles.events.Count; i++) {
					playgroundParticles.events[i].Initialize();
					if (playgroundParticles.events[i].initializedTarget && playgroundParticles.events[i].broadcastType!=EVENTBROADCASTC.EventListeners)
						if (!playgroundParticles.events[i].target.eventControlledBy.Contains (playgroundParticles))
							playgroundParticles.events[i].target.eventControlledBy.Add (playgroundParticles);
					
					if (playgroundParticles.events[i].eventType==EVENTTYPEC.Time) {
						hasTimerEvent = playgroundParticles.events[i].UpdateTime();
					}
				}
			}

			// Calculate all thread-safe data on a new thread
			if (!playgroundParticles.isDoneThread) return;
			playgroundParticles.isDoneThread = false;
			PlaygroundC.RunAsync(()=>{
				if (playgroundParticles.isDoneThread) return;
				lock (playgroundParticles.locker) {

				// Prepare variables for particle source positions
				Matrix4x4 stMx = new Matrix4x4();
				Matrix4x4 fMx = new Matrix4x4();
				stMx.SetTRS(stPos, stRot, stSca);
				fMx.SetTRS(Vector3.zero, stRot, new Vector3(1f,1f,1f));
				int downResolution = playgroundParticles.skinnedWorldObject.downResolution;
				int downResolutionP;

				// Prepare variables for lifetime, velocity & manipulators
				int m = 0;
				float evaluatedLife;
				Vector3 deltaVelocity;
				Vector3 manipulatorPosition;
				float manipulatorDistance;
				Vector3 zero = Vector3.zero;
				Vector3 up = Vector3.up;

				// Prepare variables for colors
				Color lifetimeColor = new Color();
				bool hasLifetimeColors = (playgroundParticles.lifetimeColors.Count>0);

				// Update skinned mesh vertices
				if (skinnedWorldObjectReady)
					playgroundParticles.skinnedWorldObject.Update();
				
				int pCount = playgroundParticles.particleCache.Length;
				bool applyMask = false;

				// Check that cache is correct
				if (playgroundParticles.playgroundCache.maskAlpha.Length!=pCount) {
					playgroundParticles.playgroundCache.maskAlpha = new float[pCount];
					playgroundParticles.playgroundCache.isMasked = new bool[pCount];
				}

				// Calculation loop
				for (int p = 0; p<playgroundParticles.particleCache.Length; p++) {
					
					// Check that particle count is correct
					if (pCount != playgroundParticles.particleCache.Length) {
						playgroundParticles.cameFromNonEmissionFrame = false;
						playgroundParticles.isDoneThread = true;
						return;
					}

					// Apply particle mask
					if (p<playgroundParticles.particleMask) {
						if (playgroundParticles.playgroundCache.maskAlpha[p]<=0 || playgroundParticles.particleMaskTime<=0) {
							playgroundParticles.playgroundCache.isMasked[p] = true;
							playgroundParticles.playgroundCache.maskAlpha[p] = 0;
							playgroundParticles.particleCache[p].size = 0;
							applyMask = true;
						} else {
							applyMask = false;
							playgroundParticles.playgroundCache.maskAlpha[p] -= (1f/playgroundParticles.particleMaskTime)*playgroundParticles.localDeltaTime;
						}
					} else {
						applyMask = false;
						if (playgroundParticles.playgroundCache.maskAlpha[p]<1f && playgroundParticles.particleMaskTime>0) {
							playgroundParticles.playgroundCache.maskAlpha[p] += (1f/playgroundParticles.particleMaskTime)*playgroundParticles.localDeltaTime;
						} else {
							playgroundParticles.playgroundCache.maskAlpha[p] = 1f;
							playgroundParticles.playgroundCache.isMasked[p] = false;
						}
					}

					// Get this particle's color
					if (!playgroundParticles.playgroundCache.changedByPropertyColor[p] && !playgroundParticles.playgroundCache.changedByPropertyColorLerp[p]) {
						switch (playgroundParticles.colorSource) {
						case COLORSOURCEC.Source:
							switch (playgroundParticles.source) {
							case SOURCEC.Script:
								lifetimeColor = playgroundParticles.playgroundCache.scriptedColor[p];
								break;
							case SOURCEC.State:
								if (stateReadyForTextureColor)
									lifetimeColor = playgroundParticles.states[playgroundParticles.activeState].GetColor(p);
								else
									lifetimeColor = playgroundParticles.lifetimeColor.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime));
								break;
							case SOURCEC.Projection:
								lifetimeColor = playgroundParticles.projection.GetColor(p);
								break;
							case SOURCEC.Paint:
								lifetimeColor = playgroundParticles.paint.GetColor(p);
								break;
							default:
								lifetimeColor = playgroundParticles.lifetimeColor.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime));
								break;
							}
							if (playgroundParticles.sourceUsesLifetimeAlpha)
								lifetimeColor.a = Mathf.Clamp(playgroundParticles.lifetimeColor.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime)).a, 0, lifetimeColor.a);
							break;
						case COLORSOURCEC.LifetimeColor:
							lifetimeColor = playgroundParticles.lifetimeColor.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime));
							break;
						case COLORSOURCEC.LifetimeColors:
							if (hasLifetimeColors)
								lifetimeColor = playgroundParticles.lifetimeColors[playgroundParticles.playgroundCache.lifetimeColorId[p]%playgroundParticles.lifetimeColors.Count].gradient.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime));
							else
								lifetimeColor = playgroundParticles.lifetimeColor.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime));
							break;
						}
						
					} else if (playgroundParticles.playgroundCache.changedByPropertyColorKeepAlpha[p]) {
						lifetimeColor = playgroundParticles.particleCache[p].color;
						lifetimeColor.a = Mathf.Clamp(playgroundParticles.lifetimeColor.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime)).a, 0, lifetimeColor.a);
					}

					// Assign color to particle
					lifetimeColor*=playgroundParticles.playgroundCache.maskAlpha[p];
					playgroundParticles.particleCache[p].color = lifetimeColor;
					
					// Give Playground Cache its color value
					playgroundParticles.playgroundCache.color[p] = lifetimeColor;

					// Source positions
					if (playgroundParticles.emit) {
						switch (playgroundParticles.source) {
						case SOURCEC.State:
							if (playgroundParticles.playgroundCache.rebirth[p] || playgroundParticles.onlySourcePositioning) {
								playgroundParticles.playgroundCache.previousTargetPosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
								if (playgroundParticles.applyInitialLocalVelocity)
									playgroundParticles.playgroundCache.targetDirection[p] = fMx.MultiplyPoint3x4(Vector3Scale(playgroundParticles.playgroundCache.initialLocalVelocity[p], playgroundParticles.states[playgroundParticles.activeState].GetNormal(p)));
								if (!overflow) {
									playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(playgroundParticles.states[playgroundParticles.activeState].GetPosition(p))+playgroundParticles.playgroundCache.scatterPosition[p];
								} else {
									switch (playgroundParticles.overflowMode) {
									case OVERFLOWMODEC.SourceTransform:
										playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(playgroundParticles.states[playgroundParticles.activeState].GetPosition(p)+GetOverflow2(playgroundParticles.overflowOffset, p, playgroundParticles.states[playgroundParticles.activeState].positionLength))+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.World:
										playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(playgroundParticles.states[playgroundParticles.activeState].GetPosition(p))+GetOverflow2(playgroundParticles.overflowOffset, p, playgroundParticles.states[playgroundParticles.activeState].positionLength)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.SourcePoint:
										playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(playgroundParticles.states[playgroundParticles.activeState].GetPosition(p)+GetOverflow2(playgroundParticles.overflowOffset, playgroundParticles.states[playgroundParticles.activeState].GetNormal(p), p, playgroundParticles.states[playgroundParticles.activeState].positionLength))+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									}
								}
								
								// Local space compensation calculation
								if (localSpace && playgroundParticles.applyLocalSpaceMovementCompensation)
									playgroundParticles.playgroundCache.localSpaceMovementCompensation[p] = playgroundParticles.playgroundCache.targetPosition[p]-playgroundParticles.playgroundCache.previousTargetPosition[p];
							}
						break;
						case SOURCEC.Transform:
							if (playgroundParticles.playgroundCache.rebirth[p] || playgroundParticles.onlySourcePositioning) {
								playgroundParticles.playgroundCache.previousTargetPosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
								if (playgroundParticles.applyInitialLocalVelocity)
									playgroundParticles.playgroundCache.targetDirection[p] = stRot*playgroundParticles.playgroundCache.initialLocalVelocity[p];
								if (!overflow) {
									playgroundParticles.playgroundCache.targetPosition[p] = stPos+playgroundParticles.playgroundCache.scatterPosition[p];
								} else {
									switch (playgroundParticles.overflowMode) {
									case OVERFLOWMODEC.SourceTransform:
										playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(GetOverflow2(playgroundParticles.overflowOffset, p, 1))+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.World:
										playgroundParticles.playgroundCache.targetPosition[p] = stPos+GetOverflow2(playgroundParticles.overflowOffset, p, 1)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.SourcePoint:
										playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(GetOverflow2(playgroundParticles.overflowOffset, p, 1))+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									}
								}
								
								// Local space compensation calculation
								if (localSpace && playgroundParticles.applyLocalSpaceMovementCompensation)
									playgroundParticles.playgroundCache.localSpaceMovementCompensation[p] = playgroundParticles.playgroundCache.targetPosition[p]-playgroundParticles.playgroundCache.previousTargetPosition[p];
							}
						break;
						case SOURCEC.WorldObject:
							if (playgroundParticles.playgroundCache.rebirth[p] || playgroundParticles.onlySourcePositioning) {
								playgroundParticles.playgroundCache.previousTargetPosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
								if (playgroundParticles.applyInitialLocalVelocity)
									playgroundParticles.playgroundCache.targetDirection[p] = fMx.MultiplyPoint3x4(Vector3Scale(playgroundParticles.playgroundCache.initialLocalVelocity[p], playgroundParticles.worldObject.normals[p%playgroundParticles.worldObject.vertexPositions.Length]));
								if (!overflow) {
									playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(
										playgroundParticles.worldObject.vertexPositions[p%playgroundParticles.worldObject.vertexPositions.Length]
										)+playgroundParticles.playgroundCache.scatterPosition[p];
								} else {
									switch (playgroundParticles.overflowMode) {
									case OVERFLOWMODEC.SourceTransform:
										playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(
											playgroundParticles.worldObject.vertexPositions[p%playgroundParticles.worldObject.vertexPositions.Length]+GetOverflow2(playgroundParticles.overflowOffset, p, playgroundParticles.worldObject.vertexPositions.Length)
											)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.World:
										playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(
											playgroundParticles.worldObject.vertexPositions[p%playgroundParticles.worldObject.vertexPositions.Length]
											)+GetOverflow2(playgroundParticles.overflowOffset, p, playgroundParticles.worldObject.vertexPositions.Length)+
											playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.SourcePoint:
										playgroundParticles.playgroundCache.targetPosition[p] = stMx.MultiplyPoint3x4(
											playgroundParticles.worldObject.vertexPositions[p%playgroundParticles.worldObject.vertexPositions.Length]+GetOverflow2(playgroundParticles.overflowOffset, playgroundParticles.worldObject.normals[p%playgroundParticles.worldObject.normals.Length], p, playgroundParticles.worldObject.vertexPositions.Length)
											)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									}
								}
								
								// Local space compensation calculation
								if (localSpace && playgroundParticles.applyLocalSpaceMovementCompensation)
									playgroundParticles.playgroundCache.localSpaceMovementCompensation[p] = playgroundParticles.playgroundCache.targetPosition[p]-playgroundParticles.playgroundCache.previousTargetPosition[p];
							}
						break;
						case SOURCEC.SkinnedWorldObject:
							if (playgroundParticles.playgroundCache.rebirth[p] || playgroundParticles.onlySourcePositioning) {
								playgroundParticles.playgroundCache.previousTargetPosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
								if (playgroundParticles.applyInitialLocalVelocity)
									playgroundParticles.playgroundCache.targetDirection[p] = fMx.MultiplyPoint3x4(Vector3Scale(playgroundParticles.playgroundCache.initialLocalVelocity[p], playgroundParticles.skinnedWorldObject.normals[p%playgroundParticles.skinnedWorldObject.normals.Length]));
								downResolutionP = Mathf.RoundToInt(p*downResolution)%playgroundParticles.skinnedWorldObject.vertexPositions.Length;
								if (!overflow) {
									playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.skinnedWorldObject.vertexPositions[downResolutionP]+playgroundParticles.playgroundCache.scatterPosition[p];
								} else {
									switch (playgroundParticles.overflowMode) {
									case OVERFLOWMODEC.SourceTransform:
										playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.skinnedWorldObject.vertexPositions[downResolutionP]+
											GetOverflow2(
												stDir,
												p, 
												playgroundParticles.skinnedWorldObject.vertexPositions.Length/downResolution
												)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.World:
										playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.skinnedWorldObject.vertexPositions[downResolutionP]+
											GetOverflow2(
												playgroundParticles.overflowOffset,
												p, 
												playgroundParticles.skinnedWorldObject.vertexPositions.Length/downResolution
												)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.SourcePoint:
										playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.skinnedWorldObject.vertexPositions[downResolutionP]+
											GetOverflow2(
												playgroundParticles.overflowOffset,
												playgroundParticles.skinnedWorldObject.normals[downResolutionP],
												p, 
												playgroundParticles.skinnedWorldObject.vertexPositions.Length/downResolution
												)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									}
								}
								
								// Local space compensation calculation
								if (localSpace && playgroundParticles.applyLocalSpaceMovementCompensation)
									playgroundParticles.playgroundCache.localSpaceMovementCompensation[p] = playgroundParticles.playgroundCache.targetPosition[p]-playgroundParticles.playgroundCache.previousTargetPosition[p];
							}
						
						break;
						case SOURCEC.Projection:
								if (playgroundParticles.playgroundCache.rebirth[p] || playgroundParticles.onlySourcePositioning) {
									playgroundParticles.playgroundCache.previousTargetPosition[p] = playgroundParticles.playgroundCache.targetPosition[p];

									if (playgroundParticles.applyInitialLocalVelocity)
										playgroundParticles.playgroundCache.targetDirection[p] = Vector3Scale(playgroundParticles.projection.GetNormal(p), playgroundParticles.playgroundCache.initialLocalVelocity[p]);
									if (!overflow) {
										playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.projection.GetPosition(p)+playgroundParticles.playgroundCache.scatterPosition[p];
									} else {
										switch (playgroundParticles.overflowMode) {
										case OVERFLOWMODEC.SourceTransform:
											playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.projection.GetPosition(p)+GetOverflow2(stDir, p, playgroundParticles.projection.positionLength)+playgroundParticles.playgroundCache.scatterPosition[p];
											break;
										case OVERFLOWMODEC.World:
											playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.projection.GetPosition(p)+GetOverflow2(playgroundParticles.overflowOffset, p, playgroundParticles.projection.positionLength)+playgroundParticles.playgroundCache.scatterPosition[p];
											break;
										case OVERFLOWMODEC.SourcePoint:
											playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.projection.GetPosition(p)+GetOverflow2(Vector3Scale(stDir, playgroundParticles.projection.GetNormal(p)), p, playgroundParticles.projection.positionLength)+playgroundParticles.playgroundCache.scatterPosition[p];
											break;
										}
									}
								}

						break;
						case SOURCEC.Paint:
							if (playgroundParticles.playgroundCache.rebirth[p] || playgroundParticles.onlySourcePositioning) {
								playgroundParticles.playgroundCache.previousTargetPosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
								if (playgroundParticles.applyInitialLocalVelocity)
									playgroundParticles.playgroundCache.targetDirection[p] = playgroundParticles.paint.GetRotation(p)*Vector3Scale(playgroundParticles.playgroundCache.initialLocalVelocity[p], playgroundParticles.paint.GetNormal(p));
								if (!overflow) {
									playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.paint.GetPosition(p)+playgroundParticles.playgroundCache.scatterPosition[p];
								} else {
									switch (playgroundParticles.overflowMode) {
									case OVERFLOWMODEC.SourceTransform:
										playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.paint.GetPosition(p)+GetOverflow2(playgroundParticles.paint.GetRotation(p)*playgroundParticles.overflowOffset, p, playgroundParticles.paint.positionLength)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.World:
										playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.paint.GetPosition(p)+GetOverflow2(playgroundParticles.overflowOffset, p, playgroundParticles.paint.positionLength)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									case OVERFLOWMODEC.SourcePoint:
										playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.paint.GetPosition(p)+playgroundParticles.paint.GetRotation(p)*GetOverflow2(playgroundParticles.overflowOffset, playgroundParticles.paint.GetNormal(p), p, playgroundParticles.paint.positionLength)+playgroundParticles.playgroundCache.scatterPosition[p];
										break;
									}
								}
								
								// Local space compensation calculation
								if (localSpace && playgroundParticles.applyLocalSpaceMovementCompensation) 
									playgroundParticles.playgroundCache.localSpaceMovementCompensation[p] = playgroundParticles.playgroundCache.targetPosition[p]-playgroundParticles.playgroundCache.previousTargetPosition[p];
							}
						break;
						}
					}

					// Set initial particle values if life is 0
					if (playgroundParticles.playgroundCache.life[p]==0) {
						playgroundParticles.playgroundCache.position[p] = playgroundParticles.playgroundCache.targetPosition[p];
						playgroundParticles.playgroundCache.initialColor[p] = lifetimeColor;
					}

					// Particle lifetime, velocity and manipulators
					if (playgroundParticles.playgroundCache.rebirth[p]) {
						
						// Particle is alive
						if (playgroundParticles.playgroundCache.life[p]<=PlaygroundC.globalTime+playgroundParticles.lifetime) {
							
							// Reset particle velocity
							//playgroundParticles.particleCache[p].velocity = Vector3.zero;
							
							// Lifetime size
							if (!playgroundParticles.playgroundCache.changedByPropertySize[p]) {
								if (playgroundParticles.applyLifetimeSize)
									playgroundParticles.playgroundCache.size[p] = playgroundParticles.playgroundCache.initialSize[p]*playgroundParticles.lifetimeSize.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime))*playgroundParticles.scale;
								else
									playgroundParticles.playgroundCache.size[p] = playgroundParticles.playgroundCache.initialSize[p]*playgroundParticles.scale;
							}
							playgroundParticles.particleCache[p].size = !applyMask?playgroundParticles.playgroundCache.size[p]:0;
							

							
							
							// Local Manipulators
							for (m = 0; m<playgroundParticles.manipulators.Count; m++) {
								if (playgroundParticles.manipulators[m].transform!=null) {
									manipulatorPosition = localSpace?playgroundParticles.manipulators[m].transform.localPosition:playgroundParticles.manipulators[m].transform.position;
									manipulatorDistance = playgroundParticles.manipulators[m].strengthDistanceEffect>0?Vector3.Distance (manipulatorPosition, playgroundParticles.playgroundCache.position[p])/playgroundParticles.manipulators[m].strengthDistanceEffect:10f;
									CalculateManipulator(playgroundParticles, playgroundParticles.manipulators[m], p, t, playgroundParticles.playgroundCache.life[p], playgroundParticles.playgroundCache.position[p], manipulatorPosition, manipulatorDistance, localSpace);
								}
							}
							
							// Global Manipulators
							for (m = 0; m<PlaygroundC.reference.manipulators.Count; m++) {
								if (PlaygroundC.reference.manipulators[m].transform!=null) {
									manipulatorPosition = localSpace?PlaygroundC.reference.manipulators[m].transform.localPosition:PlaygroundC.reference.manipulators[m].transform.position;
									manipulatorDistance = PlaygroundC.reference.manipulators[m].strengthDistanceEffect>0?Vector3.Distance (manipulatorPosition, playgroundParticles.playgroundCache.position[p])/PlaygroundC.reference.manipulators[m].strengthDistanceEffect:10f;
									CalculateManipulator(playgroundParticles, PlaygroundC.reference.manipulators[m], p, t, playgroundParticles.playgroundCache.life[p], playgroundParticles.playgroundCache.position[p], manipulatorPosition, manipulatorDistance, localSpace);
								}
							}

							if (!playgroundParticles.onlySourcePositioning) {
								
								// Velocity bending
								if (playgroundParticles.applyVelocityBending) {
									if (playgroundParticles.velocityBendingType==VELOCITYBENDINGTYPEC.SourcePosition) {
										playgroundParticles.playgroundCache.velocity[p] += Vector3.Reflect(
											new Vector3(
											playgroundParticles.playgroundCache.velocity[p].x*playgroundParticles.velocityBending.x,
											playgroundParticles.playgroundCache.velocity[p].y*playgroundParticles.velocityBending.y, 
											playgroundParticles.playgroundCache.velocity[p].z*playgroundParticles.velocityBending.z
											),
											(playgroundParticles.playgroundCache.targetPosition[p]-playgroundParticles.playgroundCache.position[p]).normalized
											)*t;
									} else {
										playgroundParticles.playgroundCache.velocity[p] += Vector3.Reflect(
											new Vector3(
											playgroundParticles.playgroundCache.velocity[p].x*playgroundParticles.velocityBending.x,
											playgroundParticles.playgroundCache.velocity[p].y*playgroundParticles.velocityBending.y, 
											playgroundParticles.playgroundCache.velocity[p].z*playgroundParticles.velocityBending.z
											),
											(playgroundParticles.playgroundCache.previousParticlePosition[p]-playgroundParticles.playgroundCache.position[p]).normalized
											)*t;
									}
								}
								
								// Delta velocity
								if (!playgroundParticles.cameFromNonEmissionFrame && playgroundParticles.calculateDeltaMovement && playgroundParticles.playgroundCache.life[p]==0 && playgroundParticles.source!=SOURCEC.Script) {
									deltaVelocity = playgroundParticles.playgroundCache.targetPosition[p]-(playgroundParticles.playgroundCache.previousTargetPosition[p]);
									playgroundParticles.playgroundCache.velocity[p] += deltaVelocity*playgroundParticles.deltaMovementStrength;
								}

								// Set previous target position (used by delta velocity & local space movement compensation)
								playgroundParticles.playgroundCache.previousTargetPosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
								
								// Gravity
								playgroundParticles.playgroundCache.velocity[p] -= playgroundParticles.gravity*t;
								
								// Lifetime additive velocity
								if (playgroundParticles.applyLifetimeVelocity) 
									playgroundParticles.playgroundCache.velocity[p] += playgroundParticles.lifetimeVelocity.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime))*t;
								
								// Damping, max velocity, constraints and final positioning
								if (playgroundParticles.playgroundCache.velocity[p]!=zero) {

									// Max velocity
									if (playgroundParticles.playgroundCache.velocity[p].sqrMagnitude>playgroundParticles.maxVelocity)
										playgroundParticles.playgroundCache.velocity[p] = Vector3.ClampMagnitude(playgroundParticles.playgroundCache.velocity[p], playgroundParticles.maxVelocity);

									// Damping
									if (playgroundParticles.damping>0)
										playgroundParticles.playgroundCache.velocity[p] = Vector3.Lerp(playgroundParticles.playgroundCache.velocity[p], zero, playgroundParticles.damping*t);
									
									// Axis constraints
									if (playgroundParticles.axisConstraints.x)
										playgroundParticles.playgroundCache.velocity[p].x = 0;
									if (playgroundParticles.axisConstraints.y)
										playgroundParticles.playgroundCache.velocity[p].y = 0;
									if (playgroundParticles.axisConstraints.z)
										playgroundParticles.playgroundCache.velocity[p].z = 0;
									
									
									// Set calculated collision position 
									playgroundParticles.playgroundCache.collisionParticlePosition[p] = playgroundParticles.playgroundCache.previousParticlePosition[p];

									
									// Relocate
									playgroundParticles.playgroundCache.position[p] += playgroundParticles.playgroundCache.velocity[p]*t;
									if (playgroundParticles.applyLocalSpaceMovementCompensation) {
										if (!playgroundParticles.applyMovementCompensationLifetimeStrength)
											playgroundParticles.playgroundCache.position[p] += playgroundParticles.playgroundCache.localSpaceMovementCompensation[p];
										else
											playgroundParticles.playgroundCache.position[p] += playgroundParticles.playgroundCache.localSpaceMovementCompensation[p]*playgroundParticles.movementCompensationLifetimeStrength.Evaluate(Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime));
									}

										// Set particle velocity to be able to stretch towards movement
										if (playgroundParticles.renderModeStretch) {
											if (playgroundParticles.applyLifetimeStretching)
												playgroundParticles.particleCache[p].velocity = Vector3.Slerp (playgroundParticles.particleCache[p].velocity, playgroundParticles.playgroundCache.position[p]-playgroundParticles.playgroundCache.previousParticlePosition[p], t*playgroundParticles.stretchSpeed)*playgroundParticles.stretchLifetime.Evaluate(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime);
											else
												playgroundParticles.particleCache[p].velocity = Vector3.Slerp (playgroundParticles.particleCache[p].velocity, playgroundParticles.playgroundCache.position[p]-playgroundParticles.playgroundCache.previousParticlePosition[p], t*playgroundParticles.stretchSpeed);
										}

								}
								
							} else {
								
								// Only Source Positioning
								// Set particle velocity to be able to stretch towards movement
								if (playgroundParticles.renderModeStretch) {
									if (playgroundParticles.applyLifetimeStretching)
										playgroundParticles.particleCache[p].velocity = Vector3.Slerp (playgroundParticles.particleCache[p].velocity, playgroundParticles.playgroundCache.targetPosition[p]-playgroundParticles.playgroundCache.previousTargetPosition[p], t*playgroundParticles.stretchSpeed)*playgroundParticles.stretchLifetime.Evaluate(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime);
									else
										playgroundParticles.particleCache[p].velocity = Vector3.Slerp (playgroundParticles.particleCache[p].velocity, playgroundParticles.playgroundCache.targetPosition[p]-playgroundParticles.playgroundCache.previousTargetPosition[p], t*playgroundParticles.stretchSpeed);
								}
								playgroundParticles.playgroundCache.previousTargetPosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
								if (playgroundParticles.source!=SOURCEC.Script)
									playgroundParticles.playgroundCache.position[p] = playgroundParticles.playgroundCache.targetPosition[p];
								
							}

							// Rotation
							if (!playgroundParticles.rotateTowardsDirection)
								playgroundParticles.playgroundCache.rotation[p] += playgroundParticles.playgroundCache.rotationSpeed[p]*t;
							else {
								playgroundParticles.playgroundCache.rotation[p] = playgroundParticles.playgroundCache.initialRotation[p]+SignedAngle(
									up, 
									playgroundParticles.playgroundCache.position[p]-playgroundParticles.playgroundCache.previousParticlePosition[p],
									playgroundParticles.rotationNormal
								);
							}
								
							playgroundParticles.particleCache[p].rotation = playgroundParticles.playgroundCache.rotation[p];

								// Set previous particle position
								playgroundParticles.playgroundCache.previousParticlePosition[p] = playgroundParticles.playgroundCache.position[p];

							// Send timed event
							if (hasTimerEvent)
								playgroundParticles.SendEvent(EVENTTYPEC.Time, p);
						}


						// Calculate lifetime
						evaluatedLife = (PlaygroundC.globalTime-playgroundParticles.playgroundCache.birth[p])/playgroundParticles.lifetime;
						
						// Lifetime
						if (playgroundParticles.playgroundCache.life[p]<playgroundParticles.lifetime) {
							playgroundParticles.playgroundCache.life[p] = playgroundParticles.lifetime*evaluatedLife;
							playgroundParticles.particleCache[p].lifetime = Mathf.Clamp(playgroundParticles.lifetime - playgroundParticles.playgroundCache.life[p], .1f, playgroundParticles.lifetime);
						} else {
							
							// Loop exceeded
							if (!playgroundParticles.loop && PlaygroundC.globalTime>playgroundParticles.simulationStarted+playgroundParticles.lifetime-.01f) {
								playgroundParticles.loopExceeded = true;
								
								if (playgroundParticles.disableOnDone && playgroundParticles.loopExceededOnParticle==p && evaluatedLife>2)
									playgroundParticles.queueEmissionHalt = true;
								if (playgroundParticles.loopExceededOnParticle==-1)
									playgroundParticles.loopExceededOnParticle = p;
							}
							
							// Send death event
							if (hasEvent) {
								playgroundParticles.SendEvent(EVENTTYPEC.Death, p);
							}
							
							// New cycle begins
							if (PlaygroundC.globalTime>=playgroundParticles.playgroundCache.birth[p]+playgroundParticles.playgroundCache.birthDelay[p] && !playgroundParticles.loopExceeded && playgroundParticles.source!=SOURCEC.Script) {
								if (!playgroundParticles.playgroundCache.changedByPropertyDeath[p] || playgroundParticles.playgroundCache.changedByPropertyDeath[p] && PlaygroundC.globalTime>playgroundParticles.playgroundCache.death[p])
									Rebirth(playgroundParticles, p, playgroundParticles.internalRandom02);
								else {
									playgroundParticles.playgroundCache.position[p] = PlaygroundC.initialTargetPosition;
								}
							} else {
								playgroundParticles.playgroundCache.position[p] = PlaygroundC.initialTargetPosition;
							}
							
						}

					} else {
						
						// Particle is set to not rebirth
						playgroundParticles.playgroundCache.targetPosition[p] = PlaygroundC.initialTargetPosition;
						playgroundParticles.playgroundCache.position[p] = PlaygroundC.initialTargetPosition;
					}

					// Set particle position if no sync
					if (!playgroundParticles.syncPositionsOnMainThread)
						playgroundParticles.particleCache[p].position = playgroundParticles.playgroundCache.position[p];
				}

				}
				playgroundParticles.cameFromNonEmissionFrame = false;
				playgroundParticles.isDoneThread = true;
			});

			// Turbulence
			if (!playgroundParticles.onlySourcePositioning && playgroundParticles.turbulenceStrength>0 && playgroundParticles.turbulenceType!=TURBULENCETYPE.None) {

				float strengthMultiplier = 1f;
				float zeroFixX = 1f;
				float zeroFixY = 2f; 
				float zeroFixZ = 3f; 

				// Simplex
				if (playgroundParticles.turbulenceType==TURBULENCETYPE.Simplex) {
					if (playgroundParticles.turbulenceSimplex==null)
						playgroundParticles.turbulenceSimplex = new SimplexNoise();
					PlaygroundC.RunAsync(()=>{

						for (int p = 0; p<playgroundParticles.particleCount; p++) {
							if (playgroundParticles.playgroundCache.rebirth[p]) {
								if (playgroundParticles.turbulenceTimeScale>0) {
									if (playgroundParticles.turbulenceApplyLifetimeStrength)
										strengthMultiplier = playgroundParticles.turbulenceLifetimeStrength.Evaluate (Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime));
									if (strengthMultiplier>0) {
									if (!playgroundParticles.axisConstraints.x)
										playgroundParticles.playgroundCache.velocity[p].x += (float)playgroundParticles.turbulenceSimplex.noise(
										(playgroundParticles.playgroundCache.position[p].x+zeroFixX)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].y+zeroFixY)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].z+zeroFixZ)*playgroundParticles.turbulenceScale,
										PlaygroundC.globalTime*playgroundParticles.turbulenceTimeScale
										)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									if (!playgroundParticles.axisConstraints.y)
										playgroundParticles.playgroundCache.velocity[p].y += (float)playgroundParticles.turbulenceSimplex.noise(
										(playgroundParticles.playgroundCache.position[p].y+zeroFixY)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].x+zeroFixX)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].z+zeroFixZ)*playgroundParticles.turbulenceScale,
										PlaygroundC.globalTime*playgroundParticles.turbulenceTimeScale
										)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									if (!playgroundParticles.axisConstraints.z)
										playgroundParticles.playgroundCache.velocity[p].z += (float)playgroundParticles.turbulenceSimplex.noise(
										(playgroundParticles.playgroundCache.position[p].z+zeroFixZ)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].x+zeroFixX)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].y+zeroFixY)*playgroundParticles.turbulenceScale,
										PlaygroundC.globalTime*playgroundParticles.turbulenceTimeScale
										)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									}
								} else {
									if (strengthMultiplier>0) {
									if (!playgroundParticles.axisConstraints.x)
										playgroundParticles.playgroundCache.velocity[p].x += (float)playgroundParticles.turbulenceSimplex.noise(
										(playgroundParticles.playgroundCache.position[p].x+zeroFixX)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].y+zeroFixY)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].z+zeroFixZ)*playgroundParticles.turbulenceScale
										)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									if (!playgroundParticles.axisConstraints.y)
										playgroundParticles.playgroundCache.velocity[p].y += (float)playgroundParticles.turbulenceSimplex.noise(
										(playgroundParticles.playgroundCache.position[p].y+zeroFixY)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].x+zeroFixX)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].z+zeroFixZ)*playgroundParticles.turbulenceScale
										)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									if (!playgroundParticles.axisConstraints.z)
										playgroundParticles.playgroundCache.velocity[p].z += (float)playgroundParticles.turbulenceSimplex.noise(
										(playgroundParticles.playgroundCache.position[p].z+zeroFixZ)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].x+zeroFixX)*playgroundParticles.turbulenceScale,
										(playgroundParticles.playgroundCache.position[p].y+zeroFixY)*playgroundParticles.turbulenceScale
										)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									}
								}
							}
						}
					});
				}

				// Perlin
				if (playgroundParticles.turbulenceType==TURBULENCETYPE.Perlin) {
					PlaygroundC.RunAsync(()=>{
						for (int p = 0; p<playgroundParticles.particleCount; p++) {
							if (playgroundParticles.playgroundCache.rebirth[p]) {
								if (playgroundParticles.turbulenceStrength>0) {
									if (playgroundParticles.turbulenceApplyLifetimeStrength)
										strengthMultiplier = playgroundParticles.turbulenceLifetimeStrength.Evaluate (Mathf.Clamp01(playgroundParticles.playgroundCache.life[p]/playgroundParticles.lifetime));
									if (strengthMultiplier>0) {
									if (!playgroundParticles.axisConstraints.x)
										playgroundParticles.playgroundCache.velocity[p].x += (Mathf.PerlinNoise (
											PlaygroundC.globalTime*playgroundParticles.turbulenceTimeScale,
											playgroundParticles.playgroundCache.position[p].z*playgroundParticles.turbulenceScale
										)-.5f)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									if (!playgroundParticles.axisConstraints.y)
										playgroundParticles.playgroundCache.velocity[p].y += (Mathf.PerlinNoise (
											PlaygroundC.globalTime*playgroundParticles.turbulenceTimeScale,
											playgroundParticles.playgroundCache.position[p].x*playgroundParticles.turbulenceScale

										)-.5f)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									if (!playgroundParticles.axisConstraints.z)
										playgroundParticles.playgroundCache.velocity[p].z += (Mathf.PerlinNoise (
											PlaygroundC.globalTime*playgroundParticles.turbulenceTimeScale,
											playgroundParticles.playgroundCache.position[p].y*playgroundParticles.turbulenceScale

										)-.5f)*playgroundParticles.turbulenceStrength*t*strengthMultiplier;
									}
								}
							}
						}
					});
				}
			}

		}
		// Updates a PlaygroundParticlesC object (called from Playground)
		public static void Update (PlaygroundParticlesC playgroundParticles) {
			if (playgroundParticles.isYieldRefreshing || playgroundParticles.isLoading || playgroundParticles.playgroundCache==null) return;

			// Emission halt for disabling called from calculation thread
			if (playgroundParticles.queueEmissionHalt)
				playgroundParticles.particleSystemGameObject.SetActive(false);

			// Particle count
			if (playgroundParticles.particleCount!=playgroundParticles.previousParticleCount) {
				SetParticleCount(playgroundParticles, playgroundParticles.particleCount);
				playgroundParticles.Start();
				return;
			}

			// Particle emission
			if (playgroundParticles.emit!=playgroundParticles.previousEmission) {
				playgroundParticles.Emit (playgroundParticles.emit);
			}
			
			// Particle size
			if (playgroundParticles.sizeMin!=playgroundParticles.previousSizeMin || playgroundParticles.sizeMax!=playgroundParticles.previousSizeMax)
				SetSizeRandom(playgroundParticles, playgroundParticles.sizeMin, playgroundParticles.sizeMax);
			
			// Particle rotation
			if (playgroundParticles.initialRotationMin!=playgroundParticles.previousInitialRotationMin || playgroundParticles.initialRotationMax!=playgroundParticles.previousInitialRotationMax)
				SetInitialRotationRandom(playgroundParticles, playgroundParticles.initialRotationMin, playgroundParticles.initialRotationMax);
			if (playgroundParticles.rotationSpeedMin!=playgroundParticles.previousRotationSpeedMin || playgroundParticles.rotationSpeedMax!=playgroundParticles.previousRotationSpeedMax)
				SetRotationRandom(playgroundParticles, playgroundParticles.rotationSpeedMin, playgroundParticles.rotationSpeedMax);
			
			// Particle velocity
			if (playgroundParticles.applyInitialVelocity)
				if (playgroundParticles.initialVelocityMin!=playgroundParticles.previousVelocityMin || playgroundParticles.initialVelocityMax!=playgroundParticles.previousVelocityMax || playgroundParticles.playgroundCache.initialVelocity==null || playgroundParticles.playgroundCache.initialVelocity.Length!=playgroundParticles.particleCount)
					SetVelocityRandom(playgroundParticles, playgroundParticles.initialVelocityMin, playgroundParticles.initialVelocityMax);
			
			// Particle local velocity
			if (playgroundParticles.applyInitialLocalVelocity)
				if (playgroundParticles.initialLocalVelocityMin!=playgroundParticles.previousLocalVelocityMin || playgroundParticles.initialLocalVelocityMax!=playgroundParticles.previousLocalVelocityMax || playgroundParticles.playgroundCache.initialLocalVelocity==null || playgroundParticles.playgroundCache.initialLocalVelocity.Length!=playgroundParticles.particleCount)
					SetLocalVelocityRandom(playgroundParticles, playgroundParticles.initialLocalVelocityMin, playgroundParticles.initialLocalVelocityMax);
			
			// Particle life
			if (playgroundParticles.previousLifetime!=playgroundParticles.lifetime) {
				SetLifetime(playgroundParticles, playgroundParticles.sorting, playgroundParticles.lifetime);
				return;
			}

			// Particle emission rate
			if (playgroundParticles.previousEmissionRate!=playgroundParticles.emissionRate)
				SetEmissionRate(playgroundParticles);
			
			// Particle state change
			if (playgroundParticles.source==SOURCEC.State && playgroundParticles.activeState!=playgroundParticles.previousActiveState) {
				if (playgroundParticles.states[playgroundParticles.activeState].positionLength>playgroundParticles.particleCount)
					SetParticleCount(playgroundParticles, playgroundParticles.states[playgroundParticles.activeState].positionLength);
				playgroundParticles.previousActiveState = playgroundParticles.activeState;
			}
			
			// Particle calculation
			if (PlaygroundC.reference.calculate && playgroundParticles.calculate && !playgroundParticles.inTransition)
				ThreadedCalculations(playgroundParticles);
			else playgroundParticles.cameFromNonCalculatedFrame = true;
			
			// Assign all particles into the particle system
			if (!playgroundParticles.inTransition && playgroundParticles.particleCache.Length>0 && playgroundParticles.calculate)
				playgroundParticles.shurikenParticleSystem.SetParticles(playgroundParticles.particleCache, playgroundParticles.particleCache.Length);

			// Make sure this particle system is playing
			if (playgroundParticles.shurikenParticleSystem.isPaused || playgroundParticles.shurikenParticleSystem.isStopped)
				playgroundParticles.shurikenParticleSystem.Play();
		}