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(); }