protected virtual void Awake() { if (!Object.op_Implicit((Object)this.spriteRenderer)) { if (this.verboseDebug) { Debug.LogWarning((object)"Sprite Renderer not defined, trying to find in same GameObject"); } this.spriteRenderer = (SpriteRenderer)((Component)this).GetComponent <SpriteRenderer>(); if (!Object.op_Implicit((Object)this.spriteRenderer) && this.verboseDebug) { Debug.LogWarning((object)"Sprite Renderer not found"); } } if (!Object.op_Implicit((Object)this.particlesSystem)) { this.particlesSystem = (ParticleSystem)((Component)this).GetComponent <ParticleSystem>(); if (!Object.op_Implicit((Object)this.particlesSystem)) { if (!this.verboseDebug) { return; } Debug.LogError((object)"No particle system found. Static Sprite Emission won't work"); return; } } this.mainModule = this.particlesSystem.get_main(); ((ParticleSystem.MainModule) ref this.mainModule).set_loop(false); ((ParticleSystem.MainModule) ref this.mainModule).set_playOnAwake(false); this.particlesSystem.Stop(); this.SimulationSpace = ((ParticleSystem.MainModule) ref this.mainModule).get_simulationSpace(); }
protected override void ReadFromImpl(object obj) { base.ReadFromImpl(obj); ParticleSystem.VelocityOverLifetimeModule uo = (ParticleSystem.VelocityOverLifetimeModule)obj; enabled = uo.enabled; x = uo.x; y = uo.y; z = uo.z; xMultiplier = uo.xMultiplier; yMultiplier = uo.yMultiplier; zMultiplier = uo.zMultiplier; orbitalX = uo.orbitalX; orbitalY = uo.orbitalY; orbitalZ = uo.orbitalZ; orbitalXMultiplier = uo.orbitalXMultiplier; orbitalYMultiplier = uo.orbitalYMultiplier; orbitalZMultiplier = uo.orbitalZMultiplier; orbitalOffsetX = uo.orbitalOffsetX; orbitalOffsetY = uo.orbitalOffsetY; orbitalOffsetZ = uo.orbitalOffsetZ; orbitalOffsetXMultiplier = uo.orbitalOffsetXMultiplier; orbitalOffsetYMultiplier = uo.orbitalOffsetYMultiplier; orbitalOffsetZMultiplier = uo.orbitalOffsetZMultiplier; radial = uo.radial; radialMultiplier = uo.radialMultiplier; speedModifier = uo.speedModifier; speedModifierMultiplier = uo.speedModifierMultiplier; space = uo.space; }
private void SimulationSpaceAdjust(ParticleSystemSimulationSpace simulationSpace) { switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: { targetTransform = transform; break; } case ParticleSystemSimulationSpace.Custom: { targetTransform = particleSystemMainModule.customSimulationSpace; break; } case ParticleSystemSimulationSpace.World: { targetTransform = transform; break; } default: { throw new System.NotSupportedException(string.Format("Unsupported simulation space '{0}'.", System.Enum.GetName(typeof(ParticleSystemSimulationSpace), particleSystemMainModule.simulationSpace))); } } }
/// <summary> /// Starts the playback of this Playground Recorder with specified starting point, playback speed and if looping should occur. /// </summary> /// <param name="fromNormalizedTime">From normalized time in recording.</param> /// <param name="speed">The speed of the playback.</param> /// <param name="repeat">If set to <c>true</c> then enable looping.</param> public void Play(float fromNormalizedTime, float speed, bool repeat) { if (!_hasPlaygroundSystem) { return; } if (!_isReplaying && localSpaceOnPlayback) { _previousSimulationSpace = playgroundSystem.shurikenParticleSystem.simulationSpace; playgroundSystem.shurikenParticleSystem.simulationSpace = ParticleSystemSimulationSpace.Local; } playgroundSystem.inPlayback = true; playbackSpeed = speed; loopPlayback = repeat; playHead = fromNormalizedTime; _isReplaying = true; StopRecording(); StartPlayback(); if (playHead >= 1f) { playHead = 0; } if (Application.isPlaying) { StartCoroutine(PlayRecordedFrames(playHead)); } }
private void OnTriggerStay(Collider collider) { if (!animator) { return; } if (collider.gameObject.CompareTag("Player") && animator.GetFloat(parameterHash) > 0.9f) { if (GameSceneManager.Instance && GameSceneManager.Instance.BloodParticles) { ParticleSystem system = GameSceneManager.Instance.BloodParticles; system.transform.position = transform.position; system.transform.rotation = Camera.main.transform.rotation; ParticleSystemSimulationSpace spaceMode = system.main.simulationSpace; spaceMode = ParticleSystemSimulationSpace.World; system.Emit(bloodParticlesBurstAmount); } if (gameSceneManager != null) { PlayerInfo info = gameSceneManager.GetPlayerInfo(collider.GetInstanceID()); if (info != null && info.characterManager != null) { info.characterManager.TakeDamage(damageAmount, doDamageSound && firstContact, doPainSound); } } firstContact = false; } }
protected virtual void Awake() { this.uiParticleSystem = (UIParticleRenderer)((Component)this).GetComponent <UIParticleRenderer>(); if (!Object.op_Implicit((Object)this.imageRenderer)) { if (this.verboseDebug) { Debug.LogWarning((object)"Image Renderer not defined, must be defined in order for the system to work"); } this.isPlaying = false; } if (!Object.op_Implicit((Object)this.particlesSystem)) { this.particlesSystem = (ParticleSystem)((Component)this).GetComponent <ParticleSystem>(); if (!Object.op_Implicit((Object)this.particlesSystem)) { if (!this.verboseDebug) { return; } Debug.LogError((object)"No particle system found. Static Sprite Emission won't work"); return; } } this.mainModule = this.particlesSystem.get_main(); ((ParticleSystem.MainModule) ref this.mainModule).set_loop(false); ((ParticleSystem.MainModule) ref this.mainModule).set_playOnAwake(false); this.particlesSystem.Stop(); this.SimulationSpace = ((ParticleSystem.MainModule) ref this.mainModule).get_simulationSpace(); }
public static ParticleSystem SetSimulationSpace(this ParticleSystem ps, ParticleSystemSimulationSpace space) { var m = ps.main; m.simulationSpace = space; return(ps); }
public static void ParticleVelocityOverTimeSettings(this ParticleSystem PS, bool enabled = true, ParticleSystemSimulationSpace space = ParticleSystemSimulationSpace.World, float scalar = 0.0f, AnimationCurve X = null, // Set Externally AnimationCurve Y = null, // Set Externally AnimationCurve Z = null // Set Externally ) { // Crashes for some reason //ParticleSystem.VelocityOverLifetimeModule velocityOverLifetimeModule = PS.velocityOverLifetime; //// Velocity Settings //velocityOverLifetimeModule.enabled = enabled; //velocityOverLifetimeModule.space = space; //if (X != null) //{ // ParticleSystem.MinMaxCurve VelocityCurveX = new ParticleSystem.MinMaxCurve(scalar, X); // velocityOverLifetimeModule.x = VelocityCurveX; //} //if (Y != null) //{ // ParticleSystem.MinMaxCurve VelocityCurveY = new ParticleSystem.MinMaxCurve(scalar, Y); // velocityOverLifetimeModule.y = VelocityCurveY; //} //if (Z != null) //{ // ParticleSystem.MinMaxCurve VelocityCurveZ = new ParticleSystem.MinMaxCurve(scalar, Z); // velocityOverLifetimeModule.z = VelocityCurveZ; //} }
static int IntToEnum(IntPtr L) { int arg0 = (int)LuaDLL.lua_tonumber(L, 1); ParticleSystemSimulationSpace o = (ParticleSystemSimulationSpace)arg0; LuaScriptMgr.PushEnum(L, o); return(1); }
public override AIStateType OnUpdate() { timer += Time.deltaTime; if (zombieStateMachine.Satisfaction > 0.9f) { zombieStateMachine.GetWaypointPosition(false); return(AIStateType.Alerted); } if (zombieStateMachine.visualThreat.Type != AITargetType.None && zombieStateMachine.visualThreat.Type != AITargetType.VisualFood) { zombieStateMachine.SetTarget(zombieStateMachine.visualThreat); return(AIStateType.Alerted); } if (zombieStateMachine.audioThreat.Type == AITargetType.Audio) { zombieStateMachine.SetTarget(zombieStateMachine.audioThreat); return(AIStateType.Alerted); } int currentHash = zombieStateMachine.Animator.GetCurrentAnimatorStateInfo(eatingLayerIndex).shortNameHash; if (currentHash == eatingStateHash || currentHash == crawlEatingStateHash) { zombieStateMachine.Satisfaction = Mathf.Min(zombieStateMachine.Satisfaction + (Time.deltaTime * zombieStateMachine.ReplenishRate) / 100.0f, 1.0f); if (GameSceneManager.Instance && GameSceneManager.Instance.BloodParticles && bloodParticlesMount) { if (timer > bloodParticlesBurstTime) { ParticleSystem system = GameSceneManager.Instance.BloodParticles; system.transform.position = bloodParticlesMount.transform.position; system.transform.rotation = bloodParticlesMount.transform.rotation; ParticleSystemSimulationSpace spaceMode = system.main.simulationSpace; spaceMode = ParticleSystemSimulationSpace.World; system.Emit(bloodParticlesBurstAmount); timer = 0.0f; } } } if (!zombieStateMachine.UseRootRotation) { Vector3 targetPos = zombieStateMachine.TargetPosition; targetPos.y = zombieStateMachine.transform.position.y; Quaternion newRot = Quaternion.LookRotation(targetPos - zombieStateMachine.transform.position); zombieStateMachine.transform.rotation = Quaternion.Slerp(zombieStateMachine.transform.rotation, newRot, Time.deltaTime * slerpSpeed); } Vector3 headToTarget = zombieStateMachine.TargetPosition - zombieStateMachine.Animator.GetBoneTransform(HumanBodyBones.Head).position; zombieStateMachine.transform.position = Vector3.Lerp(zombieStateMachine.transform.position, zombieStateMachine.transform.position + headToTarget, Time.deltaTime); return(AIStateType.Feeding); }
public static void SetSimulationSpace(ParticleSystem particleSystem, ParticleSystemSimulationSpace simulationSpace) { #if UNITY_5_5_OR_NEWER ParticleSystem.MainModule mainModule = particleSystem.main; mainModule.simulationSpace = simulationSpace; #else particleSystem.simulationSpace = simulationSpace; #endif }
protected void Emit() { if (!this.hasCachingEnded) { return; } this.ParticlesToEmitThisFrame += this.EmissionRate * Time.get_deltaTime(); Vector3 position = ((Component)this.spriteRenderer).get_gameObject().get_transform().get_position(); Vector3 vector3_1 = position; Quaternion rotation = ((Component)this.spriteRenderer).get_gameObject().get_transform().get_rotation(); Vector3 lossyScale = ((Component)this.spriteRenderer).get_gameObject().get_transform().get_lossyScale(); ParticleSystemSimulationSpace simulationSpace = this.SimulationSpace; int particlesCacheCount = this.particlesCacheCount; float particleStartSize = this.particleStartSize; int particlesToEmitThisFrame = (int)this.ParticlesToEmitThisFrame; if (this.particlesCacheCount <= 0) { return; } Color[] particleInitColorCache = this.particleInitColorCache; Vector3[] initPositionsCache = this.particleInitPositionsCache; Vector3 zero = Vector3.get_zero(); for (int index1 = 0; index1 < particlesToEmitThisFrame; ++index1) { int index2 = Random.Range(0, particlesCacheCount); if (this.useBetweenFramesPrecision) { float num = Random.Range(0.0f, 1f); vector3_1 = Vector3.Lerp(this.lastTransformPosition, position, num); } ParticleSystem.EmitParams emitParams = (ParticleSystem.EmitParams)null; if (this.UsePixelSourceColor) { ((ParticleSystem.EmitParams) ref emitParams).set_startColor(Color32.op_Implicit(particleInitColorCache[index2])); } ((ParticleSystem.EmitParams) ref emitParams).set_startSize(particleStartSize); if (simulationSpace == 1) { Vector3 vector3_2 = initPositionsCache[index2]; zero.x = vector3_2.x * lossyScale.x; zero.y = vector3_2.y * lossyScale.y; ((ParticleSystem.EmitParams) ref emitParams).set_position(Vector3.op_Addition(Quaternion.op_Multiply(rotation, zero), vector3_1)); this.particlesSystem.Emit(emitParams, 1); } else { ((ParticleSystem.EmitParams) ref emitParams).set_position(initPositionsCache[index2]); this.particlesSystem.Emit(emitParams, 1); } } this.ParticlesToEmitThisFrame -= (float)particlesToEmitThisFrame; this.lastTransformPosition = position; }
public void SetSimulation(ParticleSystemSimulationSpace space) { for (int i = 0; i < simulated.Length; i++) { simulated[i].Stop(true); var main = simulated[i].main; main.simulationSpace = space; simulated[i].Play(true); } }
protected override void ReadFromImpl(object obj) { base.ReadFromImpl(obj); ParticleSystem.ForceOverLifetimeModule uo = (ParticleSystem.ForceOverLifetimeModule)obj; enabled = uo.enabled; x = uo.x; y = uo.y; z = uo.z; xMultiplier = uo.xMultiplier; yMultiplier = uo.yMultiplier; zMultiplier = uo.zMultiplier; space = uo.space; randomized = uo.randomized; }
protected void Emit() { if (!this.hasCachingEnded) { return; } this.ParticlesToEmitThisFrame += this.EmissionRate * Time.get_deltaTime(); Vector3 position = ((Transform)this.currentRectTransform).get_position(); Quaternion rotation = ((Transform)this.currentRectTransform).get_rotation(); Vector3 localScale = ((Transform)this.currentRectTransform).get_localScale(); ParticleSystemSimulationSpace simulationSpace = this.SimulationSpace; int particlesCacheCount = this.particlesCacheCount; float particleStartSize = this.particleStartSize; int particlesToEmitThisFrame = (int)this.ParticlesToEmitThisFrame; if (this.particlesCacheCount <= 0) { return; } Color[] particleInitColorCache = this.particleInitColorCache; Vector3[] initPositionsCache = this.particleInitPositionsCache; Vector3 zero = Vector3.get_zero(); for (int index1 = 0; index1 < particlesToEmitThisFrame; ++index1) { int index2 = Random.Range(0, particlesCacheCount); ParticleSystem.EmitParams emitParams = (ParticleSystem.EmitParams)null; if (this.UsePixelSourceColor) { ((ParticleSystem.EmitParams) ref emitParams).set_startColor(Color32.op_Implicit(particleInitColorCache[index2])); } ((ParticleSystem.EmitParams) ref emitParams).set_startSize(particleStartSize); Vector3 vector3 = initPositionsCache[index2]; if (simulationSpace == 1) { zero.x = (__Null)(vector3.x * (double)this.wMult * localScale.x + this.offsetXY.x); zero.y = (__Null)(vector3.y * (double)this.hMult * localScale.y - this.offsetXY.y); ((ParticleSystem.EmitParams) ref emitParams).set_position(Vector3.op_Addition(Quaternion.op_Multiply(rotation, zero), position)); this.particlesSystem.Emit(emitParams, 1); } else { zero.x = (__Null)(vector3.x * (double)this.wMult + this.offsetXY.x); zero.y = (__Null)(vector3.y * (double)this.hMult - this.offsetXY.y); ((ParticleSystem.EmitParams) ref emitParams).set_position(zero); this.particlesSystem.Emit(emitParams, 1); } } this.ParticlesToEmitThisFrame -= (float)particlesToEmitThisFrame; }
//public enum RenderSystemUsing //{ // SpriteRenderer, // ImageRenderer, //} // //protected RenderSystemUsing renderSystemUsing; /// <summary> /// Obtain needed references and define base variables. /// </summary> protected virtual void Awake() { //Find Renderer in current gameObject if non is draggued if (!spriteRenderer) { if (verboseDebug) { Debug.LogWarning("Sprite Renderer not defined, trying to find in same GameObject"); } spriteRenderer = GetComponent <SpriteRenderer>(); if (!spriteRenderer) { if (verboseDebug) { Debug.LogWarning("Sprite Renderer not found"); } } } //Find Particle System in current gameObject if non is draggued if (!particlesSystem) { particlesSystem = GetComponent <ParticleSystem>(); if (!particlesSystem) { if (verboseDebug) { Debug.LogError("No particle system found. Static Sprite Emission won't work"); } return; } } //Set base varibles in the system for this emitter work as expected #if UNITY_5_5_OR_NEWER mainModule = particlesSystem.main; mainModule.loop = false; mainModule.playOnAwake = false; particlesSystem.Stop(); //validate simulation Space SimulationSpace = mainModule.simulationSpace; #else particlesSystem.loop = false; particlesSystem.playOnAwake = false; particlesSystem.Stop(); //validate simulation Space SimulationSpace = particlesSystem.simulationSpace; #endif }
protected override void ReadFromImpl(object obj) { base.ReadFromImpl(obj); ParticleSystem.MainModule uo = (ParticleSystem.MainModule)obj; duration = uo.duration; loop = uo.loop; prewarm = uo.prewarm; startDelay = uo.startDelay; startDelayMultiplier = uo.startDelayMultiplier; startLifetime = uo.startLifetime; startLifetimeMultiplier = uo.startLifetimeMultiplier; startSpeed = uo.startSpeed; startSpeedMultiplier = uo.startSpeedMultiplier; startSize3D = uo.startSize3D; startSize = uo.startSize; startSizeMultiplier = uo.startSizeMultiplier; startSizeX = uo.startSizeX; startSizeXMultiplier = uo.startSizeXMultiplier; startSizeY = uo.startSizeY; startSizeYMultiplier = uo.startSizeYMultiplier; startSizeZ = uo.startSizeZ; startSizeZMultiplier = uo.startSizeZMultiplier; startRotation3D = uo.startRotation3D; startRotation = uo.startRotation; startRotationMultiplier = uo.startRotationMultiplier; startRotationX = uo.startRotationX; startRotationXMultiplier = uo.startRotationXMultiplier; startRotationY = uo.startRotationY; startRotationYMultiplier = uo.startRotationYMultiplier; startRotationZ = uo.startRotationZ; startRotationZMultiplier = uo.startRotationZMultiplier; flipRotation = uo.flipRotation; startColor = uo.startColor; gravityModifier = uo.gravityModifier; gravityModifierMultiplier = uo.gravityModifierMultiplier; simulationSpace = uo.simulationSpace; customSimulationSpace = ToID(uo.customSimulationSpace); simulationSpeed = uo.simulationSpeed; useUnscaledTime = uo.useUnscaledTime; scalingMode = uo.scalingMode; playOnAwake = uo.playOnAwake; maxParticles = uo.maxParticles; emitterVelocityMode = uo.emitterVelocityMode; stopAction = uo.stopAction; cullingMode = uo.cullingMode; ringBufferMode = uo.ringBufferMode; ringBufferLoopRange = uo.ringBufferLoopRange; }
public ParticleData GetPositionByLife(float _normalizedLifeTime, ParticleSystemSimulationSpace _simulationSpace) { appliedNormalizedValue = _normalizedLifeTime * (pointArrayLenght); lowerPoint = Mathf.FloorToInt(appliedNormalizedValue); if (highQualityFollow) { upperPoint = Mathf.Clamp(lowerPoint + 1, 0, pointArrayLenght); t = Mathf.InverseLerp(lowerPoint, upperPoint, appliedNormalizedValue); if (_simulationSpace == ParticleSystemSimulationSpace.World) { cacheReturnPoint = Vector3.Lerp(pointArrayWorld[lowerPoint], pointArrayWorld[upperPoint], t); } else { cacheReturnPoint = Vector3.Lerp(pointArray[lowerPoint], pointArray[upperPoint], t); } if (updateSpeed) { cacheParticleData.speed = Vector3.Lerp(speedAtPoint[lowerPoint], speedAtPoint[upperPoint], t); } } else { if (_simulationSpace == ParticleSystemSimulationSpace.World) { cacheReturnPoint = pointArrayWorld[lowerPoint]; } else { cacheReturnPoint = pointArray[lowerPoint]; } if (updateSpeed) { cacheParticleData.speed = speedAtPoint[lowerPoint]; } } cacheParticleData.position = cacheReturnPoint; return(cacheParticleData); }
/// <summary> /// Obtain needed references and define base variables. /// </summary> protected virtual void Awake() { uiParticleSystem = GetComponent <UIParticleRenderer>(); //uiParticleSystem.GetComponent<UIParticleSystem>().hideFlags = HideFlags.HideInInspector; //Find Renderer in current gameObject if non is draggued if (!imageRenderer) { if (verboseDebug) { Debug.LogWarning("Image Renderer not defined, must be defined in order for the system to work"); } isPlaying = false; } //Find Particle System in current gameObject if non is draggued if (!particlesSystem) { particlesSystem = GetComponent <ParticleSystem>(); if (!particlesSystem) { if (verboseDebug) { Debug.LogError("No particle system found. Static Sprite Emission won't work"); } return; } } //Set base varibles in the system for this emitter work as expected #if UNITY_5_5_OR_NEWER mainModule = particlesSystem.main; mainModule.loop = false; mainModule.playOnAwake = false; particlesSystem.Stop(); //validate simulation Space SimulationSpace = mainModule.simulationSpace; #else particlesSystem.loop = false; particlesSystem.playOnAwake = false; particlesSystem.Stop(); //validate simulation Space SimulationSpace = particlesSystem.simulationSpace; #endif }
private void LateUpdate() { int maxParticles = particleSystemMainModule.maxParticles; if (particles == null || particles.Length < maxParticles) { particles = new ParticleSystem.Particle[maxParticles]; } particleSystem.GetParticles(particles); int particlesCount = particleSystem.particleCount; float maxDistanceSqr = data.maxDistance * data.maxDistance; simulationSpace = particleSystemMainModule.simulationSpace; SimulationSpaceAdjust(simulationSpace); int lrIndex = 0; for (int i = 0; i < particlesCount; i++) { if (lrIndex >= data.maxLineRenderers) { break; } connections = 0; ParticleSystem.Particle p1 = particles[i]; for (int j = i + 1; j < particlesCount; j++) { if (connections >= data.maxConnections || lrIndex >= data.maxLineRenderers) { break; } ParticleSystem.Particle p2 = particles[j]; lrIndex = SetupLineRenderer(maxDistanceSqr, lrIndex, p1, p2); } } for (int i = lrIndex; i < lineRenderers.Count; i++) { lineRenderers[i].enabled = false; } }
protected override void ReadFromImpl(object obj) { base.ReadFromImpl(obj); ParticleSystem.LimitVelocityOverLifetimeModule uo = (ParticleSystem.LimitVelocityOverLifetimeModule)obj; enabled = uo.enabled; limitX = uo.limitX; limitXMultiplier = uo.limitXMultiplier; limitY = uo.limitY; limitYMultiplier = uo.limitYMultiplier; limitZ = uo.limitZ; limitZMultiplier = uo.limitZMultiplier; limit = uo.limit; limitMultiplier = uo.limitMultiplier; dampen = uo.dampen; separateAxes = uo.separateAxes; space = uo.space; drag = uo.drag; dragMultiplier = uo.dragMultiplier; multiplyDragByParticleSize = uo.multiplyDragByParticleSize; multiplyDragByParticleVelocity = uo.multiplyDragByParticleVelocity; }
/// <summary> /// Emit particles based on EmissionRate. /// </summary> protected void Emit() { //safe check if (!hasCachingEnded) { return; } ParticlesToEmitThisFrame += EmissionRate * Time.deltaTime; //getting sprite source as gameobject for pos rot and scale Vector3 transformPos = spriteRenderer.gameObject.transform.position; Vector3 betweenFramesPrecisionPos = transformPos; Quaternion transformRot = spriteRenderer.gameObject.transform.rotation; Vector3 transformScale = spriteRenderer.gameObject.transform.lossyScale; ParticleSystemSimulationSpace currentSimulationSpace = SimulationSpace; int pCount = particlesCacheCount; float pStartSize = particleStartSize; int EmissionCount = (int)ParticlesToEmitThisFrame; if (particlesCacheCount <= 0) { return; } //faster access Color[] colorCache = particleInitColorCache; Vector3[] posCache = particleInitPositionsCache; Vector3 tempV = Vector3.zero; for (int i = 0; i < EmissionCount; i++) { int rnd = Random.Range(0, pCount); if (useBetweenFramesPrecision) { float randomDelta = Random.Range(0, 1f); betweenFramesPrecisionPos = Vector3.Lerp(lastTransformPosition, transformPos, randomDelta); } ParticleSystem.EmitParams em = new ParticleSystem.EmitParams(); if (UsePixelSourceColor) { em.startColor = colorCache[rnd]; } em.startSize = pStartSize; //if particles are set to World we must remove original particle calculation and apply the new transform modifiers. if (currentSimulationSpace == ParticleSystemSimulationSpace.World) { Vector3 origPos = posCache[rnd]; tempV.x = origPos.x * transformScale.x; tempV.y = origPos.y * transformScale.y; em.position = transformRot * tempV + betweenFramesPrecisionPos; particlesSystem.Emit(em, 1); } else { em.position = posCache[rnd]; particlesSystem.Emit(em, 1); } } //sustract integer particles emitted and leave the float bit ParticlesToEmitThisFrame -= EmissionCount; lastTransformPosition = transformPos; }
// Update is called once per frame void LateUpdate() { int maxParticles = particleSystemMainModule.maxParticles; if (particles == null || particles.Length < maxParticles) { particles = new ParticleSystem.Particle[maxParticles]; } int lrIndex = 0; int lineRendererCount = lineRenderers.Count; if (lineRendererCount > maxLineRendereres) { for (int i = maxLineRendereres; i < lineRendererCount; i++) { Destroy(lineRenderers[i].gameObject); } int removedCount = lineRendererCount - maxLineRendereres; lineRenderers.RemoveRange(maxLineRendereres, removedCount); lineRendererCount -= removedCount; } if (maxConnections > 0 && maxLineRendereres > 0) { particleSystem.GetParticles(particles); int particleCount = particleSystem.particleCount; float maxDistanceSqr = maxDistance * maxDistance; Vector3 p1_position, p2_position; ParticleSystemSimulationSpace simulationSpace = particleSystemMainModule.simulationSpace; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: { _transform = transform; break; } case ParticleSystemSimulationSpace.Custom: { _transform = particleSystemMainModule.customSimulationSpace; break; } case ParticleSystemSimulationSpace.World: { _transform = transform; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported Simulation Space '{0}'.", System.Enum.GetName(typeof(ParticleSystemSimulationSpace), particleSystemMainModule.simulationSpace))); } } for (int i = 0; i < particleCount; i++) { if (lrIndex >= maxLineRendereres) { break; } p1_position = particles[i].position; int connections = 0; for (int j = i + 1; j < particleCount; j++) { p2_position = particles[j].position; float distanceSqr = Vector3.SqrMagnitude(p1_position - p2_position); if (distanceSqr <= maxDistanceSqr) { LineRenderer lr; if (lrIndex == lineRendererCount) { lr = Instantiate(lineRendererTemplate, _transform, false); lineRenderers.Add(lr); lineRendererCount++; } lr = lineRenderers[lrIndex]; lr.enabled = true; lr.useWorldSpace = simulationSpace == ParticleSystemSimulationSpace.World ? true : false; lr.SetPosition(0, p1_position); lr.SetPosition(1, p2_position); lr.startColor = particles[i].color; lr.endColor = particles[j].color; lrIndex++; connections++; if (connections >= maxConnections || lrIndex >= maxLineRendereres) { break; } } } } } for (int i = lrIndex; i < lineRendererCount; i++) { lineRenderers[i].enabled = false; } }
/// <summary> /// Emit particles based on EmissionRate. /// </summary> protected void Emit() { //safe check if (!hasCachingEnded) { return; } ParticlesToEmitThisFrame += EmissionRate * Time.deltaTime; //getting sprite source as gameobject for pos rot and scale Vector3 transformPos = currentRectTransform.position; Quaternion transformRot = currentRectTransform.rotation; Vector3 transformScale = currentRectTransform.localScale; ParticleSystemSimulationSpace currentSimulationSpace = SimulationSpace; int pCount = particlesCacheCount; float pStartSize = particleStartSize; int EmissionCount = (int)ParticlesToEmitThisFrame; if (particlesCacheCount <= 0) { return; } //faster access Color[] colorCache = particleInitColorCache; Vector3[] posCache = particleInitPositionsCache; Vector3 tempV = Vector3.zero; for (int i = 0; i < EmissionCount; i++) { int rnd = Random.Range(0, pCount); ParticleSystem.EmitParams em = new ParticleSystem.EmitParams(); if (UsePixelSourceColor) { em.startColor = colorCache[rnd]; } em.startSize = pStartSize; Vector3 origPos = posCache[rnd]; //if particles are set to World we must remove original particle calculation and apply the new transform modifiers. if (currentSimulationSpace == ParticleSystemSimulationSpace.World) { tempV.x = (origPos.x * wMult) * transformScale.x + offsetXY.x; tempV.y = (origPos.y * hMult) * transformScale.y - offsetXY.y; em.position = transformRot * tempV + transformPos; particlesSystem.Emit(em, 1); } else { tempV.x = (origPos.x * wMult) + offsetXY.x; tempV.y = (origPos.y * hMult) - offsetXY.y; em.position = tempV; particlesSystem.Emit(em, 1); } } //sustract integer particles emitted and leave the float bit ParticlesToEmitThisFrame -= EmissionCount; }
// ... void LateUpdate() { if (trianglesMeshFilter) { switch (particleSystemMainModule.simulationSpace) { case ParticleSystemSimulationSpace.World: { // Make sure this is always at origin, or triangle mesh moves out of sync since // the mesh triangle vertices are already set to the world space particle positions. trianglesMeshFilter.transform.position = Vector3.zero; break; } case ParticleSystemSimulationSpace.Local: { // In local space it should follow me. trianglesMeshFilter.transform.position = transform.position; trianglesMeshFilter.transform.rotation = transform.rotation; break; } case ParticleSystemSimulationSpace.Custom: { // In custom space it should follow the custom transform. trianglesMeshFilter.transform.position = particleSystemMainModule.customSimulationSpace.position; trianglesMeshFilter.transform.rotation = particleSystemMainModule.customSimulationSpace.rotation; break; } } } // Filter doesn't exist but mesh is there? That means the filter reference was lost. Clear the mesh. // AKA... If mesh filter is gone (deleted and/or reference nulled), clear the mesh. else if (trianglesMesh) { trianglesMesh.Clear(); } int lineRenderersCount = lineRenderers.Count; // In case max line renderers value is changed at runtime -> destroy extra. if (lineRenderersCount > maxLineRenderers) { for (int i = maxLineRenderers; i < lineRenderersCount; i++) { Destroy(lineRenderers[i].gameObject); } lineRenderers.RemoveRange(maxLineRenderers, lineRenderersCount - maxLineRenderers); //lineRendererData.RemoveRange(maxLineRenderers, lineRenderersCount - maxLineRenderers); lineRenderersCount -= lineRenderersCount - maxLineRenderers; } if (alwaysUpdate || visible) { // Prevent constant allocations so long as max particle count doesn't change. int maxParticles = particleSystemMainModule.maxParticles; if (particles == null || particles.Length < maxParticles) { particles = new ParticleSystem.Particle[maxParticles]; particlePositions = new Vector3[maxParticles]; particleColours = new Color[maxParticles]; particleSizes = new float[maxParticles]; } float deltaTime = Time.deltaTime; timer += deltaTime; if (timer >= delay) { timer = 0.0f; int lrIndex = 0; allConnectedParticles.Clear(); // Only update if drawing/making connections. if (maxConnections > 0 && maxLineRenderers > 0) { particleSystem.GetParticles(particles); //particleSystem.GetCustomParticleData(customParticleData, ParticleSystemCustomData.Custom1); int particleCount = particleSystem.particleCount; float maxDistanceSqr = maxDistance * maxDistance; ParticleSystemSimulationSpace simulationSpace = particleSystemMainModule.simulationSpace; ParticleSystemScalingMode scalingMode = particleSystemMainModule.scalingMode; Transform customSimulationSpaceTransform = particleSystemMainModule.customSimulationSpace; Color lineRendererStartColour = lineRendererTemplate.startColor; Color lineRendererEndColour = lineRendererTemplate.endColor; float lineRendererStartWidth = lineRendererTemplate.startWidth * lineRendererTemplate.widthMultiplier; float lineRendererEndWidth = lineRendererTemplate.endWidth * lineRendererTemplate.widthMultiplier; // Save particle properties in a quick loop (accessing these is expensive and loops significantly more later, so it's better to save them once now). for (int i = 0; i < particleCount; i++) { particlePositions[i] = particles[i].position; particleColours[i] = particles[i].GetCurrentColor(particleSystem); particleSizes[i] = particles[i].GetCurrentSize(particleSystem); // Default is 0.0f, so if default, this is a new particle and I need to assign a custom ID. //if (customParticleData[i].x == 0.0f) //{ // // ++value -> increment first, then return that value. // // That way it won't be zero (default) the first time I use it. // customParticleData[i] = new Vector4(++uniqueParticleID, 0, 0, 0); //} } //particleSystem.SetCustomParticleData(customParticleData, ParticleSystemCustomData.Custom1); Vector3 p1p2_difference; // If in world space, there's no need to do any of the extra calculations... simplify the loop! if (simulationSpace == ParticleSystemSimulationSpace.World) { for (int i = 0; i < particleCount; i++) { if (lrIndex == maxLineRenderers) { break; } Color particleColour = particleColours[i]; Color lineStartColour = Color.LerpUnclamped(lineRendererStartColour, particleColour, colourFromParticle); float lineStartColourOriginalAlpha = Mathf.LerpUnclamped(lineRendererStartColour.a, particleColour.a, alphaFromParticle); lineStartColour.a = lineStartColourOriginalAlpha; float lineStartWidth = Mathf.LerpUnclamped(lineRendererStartWidth, particleSizes[i], widthFromParticle); int connections = 0; int[] connectedParticles = new int[maxConnections + 1]; for (int j = i + 1; j < particleCount; j++) { p1p2_difference.x = particlePositions[i].x - particlePositions[j].x; p1p2_difference.y = particlePositions[i].y - particlePositions[j].y; p1p2_difference.z = particlePositions[i].z - particlePositions[j].z; //float distanceSqr = Vector3.SqrMagnitude(p1p2_difference); float distanceSqr = p1p2_difference.x * p1p2_difference.x + p1p2_difference.y * p1p2_difference.y + p1p2_difference.z * p1p2_difference.z; if (distanceSqr <= maxDistanceSqr) { LineRenderer lr; if (lrIndex == lineRenderersCount) { lr = Instantiate(lineRendererTemplate, _transform, false); lineRenderers.Add(lr); lineRenderersCount++; } lr = lineRenderers[lrIndex]; lr.enabled = true; lr.SetPosition(0, particlePositions[i]); lr.SetPosition(1, particlePositions[j]); float alphaAttenuation = alphaOverNormalizedDistance.Evaluate(distanceSqr / maxDistanceSqr); lineStartColour.a = lineStartColourOriginalAlpha * alphaAttenuation; lr.startColor = lineStartColour; particleColour = particleColours[j]; Color lineEndColour = Color.LerpUnclamped(lineRendererEndColour, particleColour, colourFromParticle); lineEndColour.a = Mathf.LerpUnclamped(lineRendererEndColour.a, particleColour.a, alphaFromParticle); lr.endColor = lineEndColour; lr.startWidth = lineStartWidth; lr.endWidth = Mathf.LerpUnclamped(lineRendererEndWidth, particleSizes[j], widthFromParticle); lrIndex++; connections++; // Intentionally taken AFTER connections++ (because index = 0 is the i'th / line origin particle). connectedParticles[connections] = j; if (connections == maxConnections || lrIndex == maxLineRenderers) { break; } } } if (connections >= 2) { connectedParticles[0] = i; allConnectedParticles.Add(connectedParticles); } } } else { Vector3 position = Vector3.zero; Quaternion rotation = Quaternion.identity; Vector3 localScale = Vector3.one; Transform simulationSpaceTransform = _transform; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: { position = simulationSpaceTransform.position; rotation = simulationSpaceTransform.rotation; localScale = simulationSpaceTransform.localScale; break; } case ParticleSystemSimulationSpace.Custom: { simulationSpaceTransform = customSimulationSpaceTransform; position = simulationSpaceTransform.position; rotation = simulationSpaceTransform.rotation; localScale = simulationSpaceTransform.localScale; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", simulationSpace)); } } // I put these here so I can take out the default exception case. // Else I'd have a compiler error for potentially unassigned variables. Vector3 p1_position = Vector3.zero; Vector3 p2_position = Vector3.zero; for (int i = 0; i < particleCount; i++) { if (lrIndex == maxLineRenderers) { break; } switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: case ParticleSystemSimulationSpace.Custom: { switch (scalingMode) { case ParticleSystemScalingMode.Hierarchy: { p1_position = simulationSpaceTransform.TransformPoint(particlePositions[i]); break; } case ParticleSystemScalingMode.Local: { // Order is important. //p1_position = Vector3.Scale(particlePositions[i], localScale); p1_position.x = particlePositions[i].x * localScale.x; p1_position.y = particlePositions[i].y * localScale.y; p1_position.z = particlePositions[i].z * localScale.z; p1_position = rotation * p1_position; //p1_position += position; p1_position.x += position.x; p1_position.y += position.y; p1_position.z += position.z; break; } case ParticleSystemScalingMode.Shape: { // Order is important. p1_position = rotation * particlePositions[i]; //p1_position += position; p1_position.x += position.x; p1_position.y += position.y; p1_position.z += position.z; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", scalingMode)); } } break; } } Color particleColour = particleColours[i]; Color lineStartColour = Color.LerpUnclamped(lineRendererStartColour, particleColour, colourFromParticle); float lineStartColourOriginalAlpha = Mathf.LerpUnclamped(lineRendererStartColour.a, particleColour.a, alphaFromParticle); lineStartColour.a = lineStartColourOriginalAlpha; float lineStartWidth = Mathf.LerpUnclamped(lineRendererStartWidth, particleSizes[i], widthFromParticle); int connections = 0; int[] connectedParticles = new int[maxConnections + 1]; for (int j = i + 1; j < particleCount; j++) { // Note that because particles array is not sorted by distance, // but rather by spawn time (I think), the connections made are // not necessarily the closest. switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: case ParticleSystemSimulationSpace.Custom: { switch (scalingMode) { case ParticleSystemScalingMode.Hierarchy: { p2_position = simulationSpaceTransform.TransformPoint(particlePositions[j]); break; } case ParticleSystemScalingMode.Local: { // Order is important. //p2_position = Vector3.Scale(particlePositions[j], localScale); p2_position.x = particlePositions[j].x * localScale.x; p2_position.y = particlePositions[j].y * localScale.y; p2_position.z = particlePositions[j].z * localScale.z; p2_position = rotation * p2_position; //p2_position += position; p2_position.x += position.x; p2_position.y += position.y; p2_position.z += position.z; break; } case ParticleSystemScalingMode.Shape: { // Order is important. p2_position = rotation * particlePositions[j]; //p2_position += position; p2_position.x += position.x; p2_position.y += position.y; p2_position.z += position.z; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", scalingMode)); } } break; } } p1p2_difference.x = particlePositions[i].x - particlePositions[j].x; p1p2_difference.y = particlePositions[i].y - particlePositions[j].y; p1p2_difference.z = particlePositions[i].z - particlePositions[j].z; // Note that distance is always calculated in WORLD SPACE. // Scaling the particle system will stretch the distances // and may require adjusting the maxDistance value. // I could also do it in local space (which may actually make more // sense) by just getting the difference of the positions without // all the transformations. This also provides opportunity for // optimization as I can limit the world space transform calculations // to only happen if a particle is within range. // Think about: Putting in a bool to switch between the two? //float distanceSqr = Vector3.SqrMagnitude(p1p2_difference); float distanceSqr = p1p2_difference.x * p1p2_difference.x + p1p2_difference.y * p1p2_difference.y + p1p2_difference.z * p1p2_difference.z; // If distance to particle within range, add new vertex position. // The larger the max distance, the quicker connections will // reach its max, terminating the loop earlier. So even though more lines have // to be drawn, it's still faster to have a larger maxDistance value because // the call to Vector3.Distance() is expensive. if (distanceSqr <= maxDistanceSqr) { LineRenderer lr; if (lrIndex == lineRenderersCount) { lr = Instantiate(lineRendererTemplate, _transform, false); lineRenderers.Add(lr); lineRenderersCount++; //lineRendererData.Add(new LineRendererData()); } lr = lineRenderers[lrIndex]; //LineRendererData lrd = lineRendererData[lrIndex]; lr.enabled = true; //lrd.previousStartParticleID = lrd.currentStartParticleID; //lrd.previousEndParticleID = lrd.currentEndParticleID; //lrd.currentStartParticleID = customParticleData[i].x; //lrd.currentEndParticleID = customParticleData[j].x; lr.SetPosition(0, p1_position); lr.SetPosition(1, p2_position); //if (lrd.currentStartParticleID != lrd.previousStartParticleID || lrd.currentEndParticleID != lrd.previousEndParticleID) //{ // lrd.timer = 0.0f; //} //if (lrd.timer < 1.0f) //{ // lrd.timer += deltaTime / fadeInTime; //} //if (lrd.timer > 1.0f) //{ // lrd.timer = 1.0f; //} float alphaAttenuation = alphaOverNormalizedDistance.Evaluate(distanceSqr / maxDistanceSqr); //float alphaAttenuation = lrd.timer * alphaOverNormalizedDistance.Evaluate(distanceSqr / maxDistanceSqr); lineStartColour.a = lineStartColourOriginalAlpha * alphaAttenuation; lr.startColor = lineStartColour; particleColour = particleColours[j]; Color lineEndColour = Color.LerpUnclamped(lineRendererEndColour, particleColour, colourFromParticle); lineEndColour.a = Mathf.LerpUnclamped(lineRendererEndColour.a, particleColour.a, alphaFromParticle) * alphaAttenuation; lr.endColor = lineEndColour; lr.startWidth = lineStartWidth; lr.endWidth = Mathf.LerpUnclamped(lineRendererEndWidth, particleSizes[j], widthFromParticle); //lineRendererData[lrIndex] = lrd; lrIndex++; connections++; // Intentionally taken AFTER connections++ (because index = 0 is the i'th / line origin particle). connectedParticles[connections] = j; if (connections == maxConnections || lrIndex == maxLineRenderers) { break; } } } if (connections >= 2) { connectedParticles[0] = i; allConnectedParticles.Add(connectedParticles); } } } } // Disable remaining line renderers from the pool that weren't used. for (int i = lrIndex; i < lineRenderersCount; i++) { if (lineRenderers[i].enabled) { lineRenderers[i].enabled = false; } } // I check against the filter rather than the mesh because the mesh should always exist as long as the filter reference is there. // This way I can stop drawing/updating should the filter reference be lost. if (trianglesMeshFilter) { // Triangles mesh. // For efficiency (and my own general laziness), I only bother taking the first triangle formed. // It doesn't matter all that much since this is an abstract effect anyway. int vertexCount = allConnectedParticles.Count * 3; Vector3[] vertices = new Vector3[vertexCount]; int[] triangles = new int[vertexCount]; Vector2[] uv = new Vector2[vertexCount]; Color[] colours = new Color[vertexCount]; float maxDistanceSqr = (maxDistance * maxDistance) * maxDistanceTriangleBias; for (int i = 0; i < allConnectedParticles.Count; i++) { int[] connectedParticles = allConnectedParticles[i]; float distanceSqr = 0.0f; if (trianglesDistanceCheck) { Vector3 particlePositionA = particlePositions[connectedParticles[1]]; Vector3 particlePositionB = particlePositions[connectedParticles[2]]; //distance = Vector3.Distance(particlePositionA, particlePositionB); Vector3 difference; difference.x = particlePositionA.x - particlePositionB.x; difference.y = particlePositionA.y - particlePositionB.y; difference.z = particlePositionA.z - particlePositionB.z; distanceSqr = difference.x * difference.x + difference.y * difference.y + difference.z * difference.z; } if (distanceSqr < maxDistanceSqr) { int i3 = i * 3; vertices[i3 + 0] = particlePositions[connectedParticles[0]]; vertices[i3 + 1] = particlePositions[connectedParticles[1]]; vertices[i3 + 2] = particlePositions[connectedParticles[2]]; uv[i3 + 0] = new Vector2(0.0f, 0.0f); uv[i3 + 1] = new Vector2(0.0f, 1.0f); uv[i3 + 2] = new Vector2(1.0f, 1.0f); triangles[i3 + 0] = i3 + 0; triangles[i3 + 1] = i3 + 1; triangles[i3 + 2] = i3 + 2; colours[i3 + 0] = particleColours[connectedParticles[0]]; colours[i3 + 1] = particleColours[connectedParticles[1]]; colours[i3 + 2] = particleColours[connectedParticles[2]]; colours[i3 + 0] = Color.LerpUnclamped(Color.white, particleColours[connectedParticles[0]], triangleColourFromParticle); colours[i3 + 1] = Color.LerpUnclamped(Color.white, particleColours[connectedParticles[1]], triangleColourFromParticle); colours[i3 + 2] = Color.LerpUnclamped(Color.white, particleColours[connectedParticles[2]], triangleColourFromParticle); colours[i3 + 0].a = Mathf.LerpUnclamped(1.0f, particleColours[connectedParticles[0]].a, triangleAlphaFromParticle); colours[i3 + 1].a = Mathf.LerpUnclamped(1.0f, particleColours[connectedParticles[1]].a, triangleAlphaFromParticle); colours[i3 + 2].a = Mathf.LerpUnclamped(1.0f, particleColours[connectedParticles[2]].a, triangleAlphaFromParticle); } } trianglesMesh.Clear(); trianglesMesh.vertices = vertices; trianglesMesh.uv = uv; trianglesMesh.triangles = triangles; trianglesMesh.colors = colours; } } } }
// ... protected virtual void LateUpdate() { _radius = scaledRadius; radiusSqr = _radius * _radius; forceDeltaTime = force * Time.deltaTime; transformPosition = transform.position + offset; // SELECTIVE. // If manually assigned a set of systems, use those no matter what. if (_particleSystems.Count != 0) { // If editor array size changed, clear and add again. if (particleSystems.Count != _particleSystems.Count) { particleSystems.Clear(); particleSystems.AddRange(_particleSystems); } // Else if array size is the same, then re-assign from // the editor array. I do this in case the elements are different // even though the size is the same. else { for (int i = 0; i < _particleSystems.Count; i++) { particleSystems[i] = _particleSystems[i]; } } } // LOCAL. // Else if attached to particle system, use only that. // Obviously, this will only happen if there are no systems specified in the array. else if (particleSystem) { // If just one element, assign as local PS component. if (particleSystems.Count == 1) { particleSystems[0] = particleSystem; } // Else, clear entire array and add only the one. else { particleSystems.Clear(); particleSystems.Add(particleSystem); } } // GLOBAL. // Else, take all the ones from the entire scene. // This is the most expensive since it searches the entire scene // and also requires an allocation for every frame due to not knowing // if the particle systems are all the same from the last frame unless // I had a list to compare to from last frame. In that case, I'm not sure // if the performance would be better or worse. Do a test later? else { particleSystems.Clear(); particleSystems.AddRange(FindObjectsOfType <ParticleSystem>()); } parameters = new GetForceParameters(); particleSystemsCount = particleSystems.Count; // If first frame (array is null) or length is less than the number of systems, initialize size of array. // I never shrink the array. Not sure if that's potentially super bad? I could always throw in a public // bool as an option to allow shrinking since there's a performance benefit for each, but depends on the // implementation case. if (particleSystemParticles == null || particleSystemParticles.Length < particleSystemsCount) { particleSystemParticles = new ParticleSystem.Particle[particleSystemsCount][]; particleSystemMainModules = new ParticleSystem.MainModule[particleSystemsCount]; particleSystemRenderers = new Renderer[particleSystemsCount]; particleSystemExternalForcesMultipliers = new float[particleSystemsCount]; for (int i = 0; i < particleSystemsCount; i++) { particleSystemMainModules[i] = particleSystems[i].main; particleSystemRenderers[i] = particleSystems[i].GetComponent <Renderer>(); particleSystemExternalForcesMultipliers[i] = particleSystems[i].externalForces.multiplier; } } for (int i = 0; i < particleSystemsCount; i++) { if (!particleSystemRenderers[i].isVisible && !alwaysUpdate) { continue; } int maxParticles = particleSystemMainModules[i].maxParticles; if (particleSystemParticles[i] == null || particleSystemParticles[i].Length < maxParticles) { particleSystemParticles[i] = new ParticleSystem.Particle[maxParticles]; } currentParticleSystem = particleSystems[i]; PerParticleSystemSetup(); int particleCount = currentParticleSystem.GetParticles(particleSystemParticles[i]); ParticleSystemSimulationSpace simulationSpace = particleSystemMainModules[i].simulationSpace; ParticleSystemScalingMode scalingMode = particleSystemMainModules[i].scalingMode; // I could also store the transforms in an array similar to what I do with modules. // Or, put all of those together into a struct and make an array out of that since // they'll always be assigned/updated at the same time. Transform currentParticleSystemTransform = currentParticleSystem.transform; Transform customSimulationSpaceTransform = particleSystemMainModules[i].customSimulationSpace; // If in world space, there's no need to do any of the extra calculations... simplify the loop! if (simulationSpace == ParticleSystemSimulationSpace.World) { for (int j = 0; j < particleCount; j++) { parameters.particlePosition = particleSystemParticles[i][j].position; parameters.scaledDirectionToAffectorCenter.x = transformPosition.x - parameters.particlePosition.x; parameters.scaledDirectionToAffectorCenter.y = transformPosition.y - parameters.particlePosition.y; parameters.scaledDirectionToAffectorCenter.z = transformPosition.z - parameters.particlePosition.z; parameters.distanceToAffectorCenterSqr = parameters.scaledDirectionToAffectorCenter.sqrMagnitude; if (parameters.distanceToAffectorCenterSqr < radiusSqr) { float distanceToCenterNormalized = parameters.distanceToAffectorCenterSqr / radiusSqr; float distanceScale = scaleForceByDistance.Evaluate(distanceToCenterNormalized); Vector3 force = GetForce(); float forceScale = (forceDeltaTime * distanceScale) * particleSystemExternalForcesMultipliers[i]; force.x *= forceScale; force.y *= forceScale; force.z *= forceScale; Vector3 particleVelocity = particleSystemParticles[i][j].velocity; particleVelocity.x += force.x; particleVelocity.y += force.y; particleVelocity.z += force.z; particleSystemParticles[i][j].velocity = particleVelocity; } } } else { Vector3 particleSystemPosition = Vector3.zero; Quaternion particleSystemRotation = Quaternion.identity; Vector3 particleSystemLocalScale = Vector3.one; Transform simulationSpaceTransform = currentParticleSystemTransform; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: { particleSystemPosition = simulationSpaceTransform.position; particleSystemRotation = simulationSpaceTransform.rotation; particleSystemLocalScale = simulationSpaceTransform.localScale; break; } case ParticleSystemSimulationSpace.Custom: { simulationSpaceTransform = customSimulationSpaceTransform; particleSystemPosition = simulationSpaceTransform.position; particleSystemRotation = simulationSpaceTransform.rotation; particleSystemLocalScale = simulationSpaceTransform.localScale; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", simulationSpace)); } } for (int j = 0; j < particleCount; j++) { parameters.particlePosition = particleSystemParticles[i][j].position; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: case ParticleSystemSimulationSpace.Custom: { switch (scalingMode) { case ParticleSystemScalingMode.Hierarchy: { parameters.particlePosition = simulationSpaceTransform.TransformPoint(particleSystemParticles[i][j].position); break; } case ParticleSystemScalingMode.Local: { // Order is important. parameters.particlePosition = Vector3.Scale(parameters.particlePosition, particleSystemLocalScale); parameters.particlePosition = particleSystemRotation * parameters.particlePosition; parameters.particlePosition = parameters.particlePosition + particleSystemPosition; break; } case ParticleSystemScalingMode.Shape: { parameters.particlePosition = particleSystemRotation * parameters.particlePosition; parameters.particlePosition = parameters.particlePosition + particleSystemPosition; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", scalingMode)); } } break; } } parameters.scaledDirectionToAffectorCenter.x = transformPosition.x - parameters.particlePosition.x; parameters.scaledDirectionToAffectorCenter.y = transformPosition.y - parameters.particlePosition.y; parameters.scaledDirectionToAffectorCenter.z = transformPosition.z - parameters.particlePosition.z; parameters.distanceToAffectorCenterSqr = parameters.scaledDirectionToAffectorCenter.sqrMagnitude; //particleSystemParticles[i][j].velocity += forceDeltaTime * Vector3.Normalize(parameters.scaledDirectionToAffectorCenter); if (parameters.distanceToAffectorCenterSqr < radiusSqr) { // 0.0f -> 0.99...f; float distanceToCenterNormalized = parameters.distanceToAffectorCenterSqr / radiusSqr; // Evaluating a curve within a loop which is very likely to exceed a few thousand // iterations produces a noticeable FPS drop (around minus 2 - 5). Might be a worthwhile // optimization to check outside all loops if the curve is constant (all keyframes same value), // and then run a different block of code if true that uses that value as a stored float without // having to call Evaluate(t). float distanceScale = scaleForceByDistance.Evaluate(distanceToCenterNormalized); // Expanded vector operations for optimization. I think this is already done by // the compiler, but it's nice to have for the editor anyway. Vector3 force = GetForce(); float forceScale = (forceDeltaTime * distanceScale) * particleSystemExternalForcesMultipliers[i]; force.x *= forceScale; force.y *= forceScale; force.z *= forceScale; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: case ParticleSystemSimulationSpace.Custom: { switch (scalingMode) { case ParticleSystemScalingMode.Hierarchy: { force = simulationSpaceTransform.InverseTransformVector(force); break; } case ParticleSystemScalingMode.Local: { // Order is important. // Notice how rotation and scale orders are reversed. force = Quaternion.Inverse(particleSystemRotation) * force; force = Vector3.Scale(force, new Vector3( 1.0f / particleSystemLocalScale.x, 1.0f / particleSystemLocalScale.y, 1.0f / particleSystemLocalScale.z)); break; } case ParticleSystemScalingMode.Shape: { force = Quaternion.Inverse(particleSystemRotation) * force; break; } // This would technically never execute since it's checked earlier (above). default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", scalingMode)); } } break; } } Vector3 particleVelocity = particleSystemParticles[i][j].velocity; particleVelocity.x += force.x; particleVelocity.y += force.y; particleVelocity.z += force.z; particleSystemParticles[i][j].velocity = particleVelocity; } } } currentParticleSystem.SetParticles(particleSystemParticles[i], particleCount); } }
protected override JSONObject ToJSON(WXHierarchyContext context) { ParticleSystemRenderer particleSystemRenderer = particleSys.GetComponent <ParticleSystemRenderer>(); JSONObject json = new JSONObject(JSONObject.Type.OBJECT); JSONObject data = new JSONObject(JSONObject.Type.OBJECT); json.AddField("type", getTypeName()); json.AddField("data", data); JSONObject materials = new JSONObject(JSONObject.Type.ARRAY); data.AddField("materials", materials); Material[] mats = particleSystemRenderer.sharedMaterials; foreach (Material material in mats) { if (material != null) { WXMaterial materialConverter = new WXMaterial(material, particleSystemRenderer); string materialPath = materialConverter.Export(context.preset); materials.Add(materialPath); context.AddResource(materialPath); } } JSONObject modCommon = new JSONObject(JSONObject.Type.OBJECT); JSONObject modCommonData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("common", modCommonData); modCommonData.AddField("startSize3D", particleSys.main.startSize3D); if (particleSys.main.startSize3D) { modCommonData.AddField("startSizeX", ParseMinMaxCurve(particleSys.main.startSizeX)); modCommonData.AddField("startSizeY", ParseMinMaxCurve(particleSys.main.startSizeY)); modCommonData.AddField("startSizeZ", ParseMinMaxCurve(particleSys.main.startSizeZ)); } else { modCommonData.AddField("startSize", ParseMinMaxCurve(particleSys.main.startSize)); } modCommonData.AddField("startColor", ParseMinMaxGradient(particleSys.main.startColor)); modCommonData.AddField("startLifetime", ParseMinMaxCurve(particleSys.main.startLifetime)); modCommonData.AddField("startRotation3D", particleSys.main.startRotation3D); if (particleSys.main.startRotation3D) { modCommonData.AddField("startRotationX", ParseMinMaxCurve(particleSys.main.startRotationX, (float)(180 / Math.PI))); modCommonData.AddField("startRotationY", ParseMinMaxCurve(particleSys.main.startRotationY, (float)(180 / Math.PI))); modCommonData.AddField("startRotationZ", ParseMinMaxCurve(particleSys.main.startRotationZ, (float)(180 / Math.PI))); } else { modCommonData.AddField("startRotationZ", ParseMinMaxCurve(particleSys.main.startRotation, (float)(180 / Math.PI))); } modCommonData.AddField("startSpeed", ParseMinMaxCurve(particleSys.main.startSpeed)); modCommonData.AddField("gravityModifier", ParseMinMaxCurve(particleSys.main.gravityModifier)); #if UNITY_2018_1_OR_NEWER modCommonData.AddField("randomizeRotation", particleSys.main.flipRotation); #endif modCommonData.AddField("randomSeed", particleSys.randomSeed); modCommonData.AddField("autoRandomSeed", particleSys.useAutoRandomSeed); ParticleSystemScalingMode pScalingMode = particleSys.main.scalingMode; int pScalingModeNum = 0; switch (pScalingMode) { case ParticleSystemScalingMode.Hierarchy: pScalingModeNum = 0; break; case ParticleSystemScalingMode.Local: pScalingModeNum = 1; break; case ParticleSystemScalingMode.Shape: pScalingModeNum = 2; break; } modCommonData.AddField("scalingMode", pScalingModeNum); ParticleSystemSimulationSpace simulationSpace = particleSys.main.simulationSpace; int simulationSpaceNum = 0; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: simulationSpaceNum = 0; break; case ParticleSystemSimulationSpace.World: simulationSpaceNum = 1; break; case ParticleSystemSimulationSpace.Custom: simulationSpaceNum = 2; break; } modCommonData.AddField("simulationSpace", simulationSpaceNum); JSONObject emitter = new JSONObject(JSONObject.Type.OBJECT); JSONObject emitterData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("emitter", emitterData); emitterData.AddField("playOnAwake", particleSys.main.playOnAwake); emitterData.AddField("looping", particleSys.main.loop); emitterData.AddField("duration", particleSys.main.duration); emitterData.AddField("startDelay", ParseMinMaxCurve(particleSys.main.startDelay)); if (particleSys.emission.enabled) { JSONObject burst = new JSONObject(JSONObject.Type.ARRAY); emitterData.AddField("bursts", burst); int count = particleSys.emission.burstCount; ParticleSystem.Burst[] bursts = new ParticleSystem.Burst[count]; particleSys.emission.GetBursts(bursts); for (int i = 0; i < count; i++) { //burst.Add(ParseBurst(particleSys.emission.GetBurst(i))); burst.Add(ParseBurst(bursts[i])); } emitterData.AddField("rateOverTime", ParseMinMaxCurve(particleSys.emission.rateOverTime)); } emitterData.AddField("maxParticles", particleSys.main.maxParticles); if (particleSystemRenderer.enabled) { JSONObject renderer = new JSONObject(JSONObject.Type.OBJECT); JSONObject rendererData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("renderer", rendererData); ParticleSystemRenderMode pRenderMode = particleSystemRenderer.renderMode; int pRenderModeNum = 0; switch (pRenderMode) { case ParticleSystemRenderMode.Billboard: pRenderModeNum = 1; break; case ParticleSystemRenderMode.Stretch: pRenderModeNum = 2; rendererData.AddField("cameraScale", particleSystemRenderer.cameraVelocityScale); rendererData.AddField("speedScale", particleSystemRenderer.velocityScale); rendererData.AddField("lengthScale", particleSystemRenderer.lengthScale); break; case ParticleSystemRenderMode.HorizontalBillboard: pRenderModeNum = 3; break; case ParticleSystemRenderMode.VerticalBillboard: pRenderModeNum = 4; break; case ParticleSystemRenderMode.Mesh: Mesh mesh = particleSystemRenderer.mesh; if (mesh != null) { WXMesh meshConverter = new WXMesh(mesh); string meshPath = meshConverter.Export(context.preset); rendererData.AddField("mesh", meshPath); rendererData.AddField("meshCount", particleSystemRenderer.meshCount); context.AddResource(meshPath); } else { Debug.LogError(string.Format("{0} mesh is null", particleSys.name)); } pRenderModeNum = 5; break; case ParticleSystemRenderMode.None: pRenderModeNum = 0; break; default: pRenderModeNum = 1; break; } rendererData.AddField("renderMode", pRenderModeNum); int mode = 1; switch (particleSystemRenderer.alignment) { case ParticleSystemRenderSpace.View: mode = 1; break; case ParticleSystemRenderSpace.World: mode = 2; break; case ParticleSystemRenderSpace.Local: mode = 3; break; case ParticleSystemRenderSpace.Facing: mode = 4; break; #if UNITY_2017_1_OR_NEWER case ParticleSystemRenderSpace.Velocity: mode = 5; break; #endif default: break; } rendererData.AddField("renderAlignment", mode); mode = 0; switch (particleSystemRenderer.sortMode) { case ParticleSystemSortMode.None: mode = 0; break; case ParticleSystemSortMode.Distance: mode = 1; break; case ParticleSystemSortMode.OldestInFront: mode = 2; break; case ParticleSystemSortMode.YoungestInFront: mode = 3; break; default: break; } rendererData.AddField("sortMode", mode); rendererData.AddField("sortingFudge", particleSystemRenderer.sortingFudge); rendererData.AddField("normalDirection", particleSystemRenderer.normalDirection); rendererData.AddField("minParticleSize", particleSystemRenderer.minParticleSize); rendererData.AddField("maxParticleSize", particleSystemRenderer.maxParticleSize); var flipValue = TryGetContainProperty(particleSystemRenderer, "flip"); if (flipValue != null) { rendererData.AddField("flip", GetVect3((Vector3)flipValue)); } else { renderer.AddField("flip", GetVect3(new Vector3(0, 0, 0))); } //rendererData.AddField("flip", GetVect3(particleSystemRenderer.flip)); rendererData.AddField("pivot", GetVect3(particleSystemRenderer.pivot)); var allowRollData = TryGetContainProperty(particleSystemRenderer, "allowRoll"); if (allowRollData != null) { rendererData.AddField("allowRoll", (bool)allowRollData); } else { rendererData.AddField("allowRoll", false); } } else { String info = "entity: " + particleSys.gameObject.name + " 的粒子组件没有renderer模块,不可导出;请加上renderer模块,或删除该粒子组件"; ErrorUtil.ExportErrorReporter.create() .setGameObject(particleSys.gameObject) .setHierarchyContext(context) .error(0, "粒子组件没有renderer模块,不可导出;请加上renderer模块,或删除该粒子组件"); } if (particleSys.rotationOverLifetime.enabled) { JSONObject rotationByLife = new JSONObject(JSONObject.Type.OBJECT); JSONObject rotationByLifeData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("rotationByLife", rotationByLifeData); rotationByLifeData.AddField("separateAxes", particleSys.rotationOverLifetime.separateAxes); if (particleSys.rotationOverLifetime.separateAxes) { rotationByLifeData.AddField("x", ParseMinMaxCurve(particleSys.rotationOverLifetime.x, (float)(180 / Math.PI))); rotationByLifeData.AddField("y", ParseMinMaxCurve(particleSys.rotationOverLifetime.y, (float)(180 / Math.PI))); rotationByLifeData.AddField("z", ParseMinMaxCurve(particleSys.rotationOverLifetime.z, (float)(180 / Math.PI))); } else { rotationByLifeData.AddField("z", ParseMinMaxCurve(particleSys.rotationOverLifetime.z, (float)(180 / Math.PI))); } } if (particleSys.sizeOverLifetime.enabled) { JSONObject sizeOverLifetime = new JSONObject(JSONObject.Type.OBJECT); JSONObject sizeOverLifetimeData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("sizeByLife", sizeOverLifetimeData); sizeOverLifetimeData.AddField("separateAxes", particleSys.sizeOverLifetime.separateAxes); if (particleSys.sizeOverLifetime.separateAxes) { sizeOverLifetimeData.AddField("x", ParseMinMaxCurve(particleSys.sizeOverLifetime.x)); sizeOverLifetimeData.AddField("y", ParseMinMaxCurve(particleSys.sizeOverLifetime.y)); sizeOverLifetimeData.AddField("z", ParseMinMaxCurve(particleSys.sizeOverLifetime.z)); } else { sizeOverLifetimeData.AddField("x", ParseMinMaxCurve(particleSys.sizeOverLifetime.size)); } } if (particleSys.velocityOverLifetime.enabled) { JSONObject speedByLifeData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("speedByLife", speedByLifeData); switch (particleSys.velocityOverLifetime.space) { case ParticleSystemSimulationSpace.Local: speedByLifeData.AddField("space", 1); break; case ParticleSystemSimulationSpace.World: speedByLifeData.AddField("space", 2); break; case ParticleSystemSimulationSpace.Custom: break; default: break; } speedByLifeData.AddField("x", ParseMinMaxCurve(particleSys.velocityOverLifetime.x)); speedByLifeData.AddField("y", ParseMinMaxCurve(particleSys.velocityOverLifetime.y)); speedByLifeData.AddField("z", ParseMinMaxCurve(particleSys.velocityOverLifetime.z)); #if UNITY_2018_1_OR_NEWER speedByLifeData.AddField("orbitalX", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalX)); speedByLifeData.AddField("orbitalY", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalY)); speedByLifeData.AddField("orbitalZ", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalZ)); speedByLifeData.AddField("orbitalOffsetX", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalOffsetX)); speedByLifeData.AddField("orbitalOffsetY", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalOffsetY)); speedByLifeData.AddField("orbitalOffsetZ", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalOffsetZ)); speedByLifeData.AddField("radial", ParseMinMaxCurve(particleSys.velocityOverLifetime.radial)); #endif #if UNITY_2017_1_OR_NEWER speedByLifeData.AddField("speedScale", ParseMinMaxCurve(particleSys.velocityOverLifetime.speedModifier)); #endif } if (particleSys.limitVelocityOverLifetime.enabled) { JSONObject speedLimitByLifeData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("speedLimitByLife", speedLimitByLifeData); speedLimitByLifeData.AddField("separateAxes", particleSys.limitVelocityOverLifetime.separateAxes); if (particleSys.limitVelocityOverLifetime.separateAxes) { speedLimitByLifeData.AddField("x", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.limitX, particleSys.limitVelocityOverLifetime.limitXMultiplier)); speedLimitByLifeData.AddField("y", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.limitY, particleSys.limitVelocityOverLifetime.limitYMultiplier)); speedLimitByLifeData.AddField("z", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.limitZ, particleSys.limitVelocityOverLifetime.limitZMultiplier)); } else { speedLimitByLifeData.AddField("x", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.limit, particleSys.limitVelocityOverLifetime.limitMultiplier)); } speedLimitByLifeData.AddField("dampen", particleSys.limitVelocityOverLifetime.dampen); switch (particleSys.limitVelocityOverLifetime.space) { case ParticleSystemSimulationSpace.Local: speedLimitByLifeData.AddField("space", 1); break; case ParticleSystemSimulationSpace.World: speedLimitByLifeData.AddField("space", 2); break; case ParticleSystemSimulationSpace.Custom: break; default: break; } #if UNITY_2017_1_OR_NEWER speedLimitByLifeData.AddField("drag", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.drag)); speedLimitByLifeData.AddField("dragMultiplyBySize", particleSys.limitVelocityOverLifetime.multiplyDragByParticleSize); speedLimitByLifeData.AddField("dragMultiplyBySpeed", particleSys.limitVelocityOverLifetime.multiplyDragByParticleVelocity); #endif } if (particleSys.colorOverLifetime.enabled) { JSONObject colorOverLifetime = new JSONObject(JSONObject.Type.OBJECT); JSONObject colorOverLifetimeData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("colorByLife", colorOverLifetimeData); colorOverLifetimeData.AddField("gColor", ParseMinMaxGradient(particleSys.colorOverLifetime.color)); } if (particleSys.shape.enabled) { JSONObject shapeData = new JSONObject(JSONObject.Type.OBJECT); var haveShape = true; if (particleSys.shape.shapeType == ParticleSystemShapeType.Cone || particleSys.shape.shapeType == ParticleSystemShapeType.ConeVolume || particleSys.shape.shapeType == ParticleSystemShapeType.ConeVolumeShell || particleSys.shape.shapeType == ParticleSystemShapeType.ConeShell) { shapeData.AddField("shape", ParseConeShape(particleSys.shape)); } else if (particleSys.shape.shapeType == ParticleSystemShapeType.Sphere || particleSys.shape.shapeType == ParticleSystemShapeType.SphereShell) { shapeData.AddField("shape", ParseSphereShape(particleSys.shape)); } else if (particleSys.shape.shapeType == ParticleSystemShapeType.Circle || particleSys.shape.shapeType == ParticleSystemShapeType.CircleEdge) { shapeData.AddField("shape", ParseCircleShape(particleSys.shape)); } else if (particleSys.shape.shapeType == ParticleSystemShapeType.Box || particleSys.shape.shapeType == ParticleSystemShapeType.BoxEdge || particleSys.shape.shapeType == ParticleSystemShapeType.BoxShell) { shapeData.AddField("shape", ParseBox(particleSys.shape)); } else if (particleSys.shape.shapeType == ParticleSystemShapeType.Hemisphere || particleSys.shape.shapeType == ParticleSystemShapeType.HemisphereShell) { shapeData.AddField("shape", ParseHemisphere(particleSys.shape)); } // else if (particleSys.shape.shapeType == ParticleSystemShapeType.SingleSidedEdge) { // shapeData.AddField("shape", ParseSingleSidedEdge(particleSys.shape)); // } else { var parentChain = go.name; var parent = go.transform.parent; while (parent) { parentChain += " -> " + parent.gameObject.name; parent = parent.parent; } Debug.LogError("unSupport shape (" + particleSys.shape.shapeType.ToString() + ") at: " + parentChain); haveShape = false; } if (haveShape) { data.AddField("emitterShape", shapeData); } } if (particleSys.textureSheetAnimation.enabled) { JSONObject textureSheetAnimationData = new JSONObject(JSONObject.Type.OBJECT); data.AddField("textureSheetAnimation", textureSheetAnimationData); int mode = 1; #if UNITY_2017_1_OR_NEWER mode = 1; switch (particleSys.textureSheetAnimation.mode) { case ParticleSystemAnimationMode.Grid: mode = 1; break; case ParticleSystemAnimationMode.Sprites: mode = 2; break; default: break; } textureSheetAnimationData.AddField("mode", mode); #endif JSONObject vec2 = new JSONObject(JSONObject.Type.ARRAY); vec2.Add(particleSys.textureSheetAnimation.numTilesX); vec2.Add(particleSys.textureSheetAnimation.numTilesY); textureSheetAnimationData.AddField("tiles", vec2); mode = 1; switch (particleSys.textureSheetAnimation.animation) { case ParticleSystemAnimationType.WholeSheet: mode = 1; break; case ParticleSystemAnimationType.SingleRow: mode = 2; break; default: break; } textureSheetAnimationData.AddField("animationType", mode); textureSheetAnimationData.AddField("randomRow", particleSys.textureSheetAnimation.useRandomRow); textureSheetAnimationData.AddField("row", particleSys.textureSheetAnimation.rowIndex); //mode = 1; //switch (particleSys.textureSheetAnimation.timeMode) //{ // case ParticleSystemAnimationTimeMode.Lifetime: // mode = 1; // break; // case ParticleSystemAnimationTimeMode.Speed: // mode = 2; // break; // case ParticleSystemAnimationTimeMode.FPS: // mode = 3; // break; // default: // break; //} textureSheetAnimationData.AddField("timeMode", 1); if (mode == 1) { textureSheetAnimationData.AddField("frameOverTime", ParseMinMaxCurve(particleSys.textureSheetAnimation.frameOverTime, particleSys.textureSheetAnimation.numTilesX * particleSys.textureSheetAnimation.numTilesY)); } else { textureSheetAnimationData.AddField("frameOverTime", ParseMinMaxCurve(particleSys.textureSheetAnimation.frameOverTime, particleSys.textureSheetAnimation.numTilesX)); } textureSheetAnimationData.AddField("startFrame", ParseMinMaxCurve(particleSys.textureSheetAnimation.startFrame)); textureSheetAnimationData.AddField("cycles", particleSys.textureSheetAnimation.cycleCount); mode = 0; var a = particleSys.textureSheetAnimation.uvChannelMask; var b = a & UVChannelFlags.UV0; if ((a & UVChannelFlags.UV0) != 0) { mode += 1; } if ((a & UVChannelFlags.UV1) != 0) { mode += 2; } if ((a & UVChannelFlags.UV2) != 0) { mode += 3; } if ((a & UVChannelFlags.UV3) != 0) { mode += 4; } textureSheetAnimationData.AddField("affectedUVChannels", mode); } if (particleSys.subEmitters.enabled) { JSONObject subEmittersData = new JSONObject(JSONObject.Type.ARRAY); data.AddField("subEmitters", subEmittersData); int count = particleSys.subEmitters.subEmittersCount; for (int i = 0; i < count; i++) { ParticleSystemSubEmitterProperties properties = particleSys.subEmitters.GetSubEmitterProperties(i); ParticleSystemSubEmitterType type = particleSys.subEmitters.GetSubEmitterType(i); JSONObject res = new JSONObject(JSONObject.Type.OBJECT); int typeNum = 0; switch (type) { case ParticleSystemSubEmitterType.Birth: typeNum = 0; break; case ParticleSystemSubEmitterType.Collision: typeNum = 1; break; case ParticleSystemSubEmitterType.Death: typeNum = 2; break; default: break; } res.AddField("type", typeNum); int propertiesNum = 0; switch (properties) { case ParticleSystemSubEmitterProperties.InheritNothing: propertiesNum = 0; break; case ParticleSystemSubEmitterProperties.InheritEverything: propertiesNum = 1; break; case ParticleSystemSubEmitterProperties.InheritColor: propertiesNum = 2; break; case ParticleSystemSubEmitterProperties.InheritSize: propertiesNum = 3; break; case ParticleSystemSubEmitterProperties.InheritRotation: propertiesNum = 4; break; default: break; } res.AddField("properties", propertiesNum); subEmittersData.Add(res); } } return(json); }
public void LateUpdate() { int maxParticles = _mainModule.maxParticles; if (_system == null || _particles.Length < maxParticles) { _particles = new ParticleSystem.Particle[maxParticles]; } int lrIdx = 0; int lineRendererCount = _lineRenderers.Count; if (lineRendererCount > MaxLineRenderers) { for (int i = MaxLineRenderers; i < lineRendererCount; i++) { Destroy(_lineRenderers[i].gameObject); } int removeCount = lineRendererCount - MaxLineRenderers; _lineRenderers.RemoveRange(MaxLineRenderers, removeCount); lineRendererCount -= removeCount; } if (MaxConnections > 0 && MaxLineRenderers > 0) { _system.GetParticles(_particles); int particleCount = _system.particleCount; float maxDistanceSqr = MaxDistance * MaxDistance; ParticleSystemSimulationSpace simulationSpace = _mainModule.simulationSpace; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: { _transform = transform; break; } case ParticleSystemSimulationSpace.Custom: { _transform = _mainModule.customSimulationSpace; break; } case ParticleSystemSimulationSpace.World: { _transform = transform; break; } default: Debug.LogError("Simulation space doesn't manage."); break; } for (int i = 0; i < particleCount; ++i) { if (lrIdx == MaxLineRenderers) { break; } Vector3 p1 = _particles[i].position; int connections = 0; for (int j = i + 1; j < particleCount; ++j) { Vector3 p2 = _particles[j].position; float distanceSqr = Vector3.Magnitude(p1 - p2); if (distanceSqr <= maxDistanceSqr) { LineRenderer lr; if (lrIdx == lineRendererCount) { lr = Instantiate(LineRendererTemplate, _transform, false); _lineRenderers.Add(lr); lineRendererCount++; } lr = _lineRenderers[lrIdx]; lr.enabled = true; lr.useWorldSpace = simulationSpace == ParticleSystemSimulationSpace.World; lr.SetPosition(0, p1); lr.SetPosition(1, p2); lrIdx++; connections++; if (connections >= MaxConnections) { break; } } } } } for (int i = lrIdx; i < _lineRenderers.Count; ++i) { _lineRenderers[i].enabled = false; } }
public ParticleData GetPositionByLife(float _normalizedLifeTime, ParticleSystemSimulationSpace _simulationSpace) { appliedNormalizedValue = _normalizedLifeTime*(pointArrayLenght); lowerPoint = Mathf.FloorToInt(appliedNormalizedValue); if (highQualityFollow) { upperPoint = Mathf.Clamp(lowerPoint+1,0,pointArrayLenght); t = Mathf.InverseLerp(lowerPoint,upperPoint,appliedNormalizedValue); if (_simulationSpace == ParticleSystemSimulationSpace.World) cacheReturnPoint = Vector3.Lerp(pointArrayWorld[lowerPoint],pointArrayWorld[upperPoint], t); else cacheReturnPoint = Vector3.Lerp(pointArray[lowerPoint],pointArray[upperPoint], t); if (updateSpeed) { cacheParticleData.speed = Vector3.Lerp(speedAtPoint[lowerPoint],speedAtPoint[upperPoint],t); } } else { if (_simulationSpace == ParticleSystemSimulationSpace.World) cacheReturnPoint = pointArrayWorld[lowerPoint]; else cacheReturnPoint = pointArray[lowerPoint]; if (updateSpeed) { cacheParticleData.speed = speedAtPoint[lowerPoint]; } } cacheParticleData.position = cacheReturnPoint; return cacheParticleData; }
// ... void LateUpdate() { int lineRenderersCount = lineRenderers.Count; // In case max line renderers value is changed at runtime -> destroy extra. if (lineRenderersCount > maxLineRenderers) { for (int i = maxLineRenderers; i < lineRenderersCount; i++) { Destroy(lineRenderers[i].gameObject); } lineRenderers.RemoveRange(maxLineRenderers, lineRenderersCount - maxLineRenderers); lineRenderersCount -= lineRenderersCount - maxLineRenderers; } if (alwaysUpdate || visible) { // Prevent constant allocations so long as max particle count doesn't change. int maxParticles = particleSystemMainModule.maxParticles; if (particles == null || particles.Length < maxParticles) { particles = new ParticleSystem.Particle[maxParticles]; particlePositions = new Vector3[maxParticles]; particleColours = new Color[maxParticles]; particleSizes = new float[maxParticles]; } timer += Time.deltaTime; if (timer >= delay) { timer = 0.0f; int lrIndex = 0; // Only update if drawing/making connections. if (maxConnections > 0 && maxLineRenderers > 0) { particleSystem.GetParticles(particles); int particleCount = particleSystem.particleCount; float maxDistanceSqr = maxDistance * maxDistance; ParticleSystemSimulationSpace simulationSpace = particleSystemMainModule.simulationSpace; ParticleSystemScalingMode scalingMode = particleSystemMainModule.scalingMode; Transform customSimulationSpaceTransform = particleSystemMainModule.customSimulationSpace; Color lineRendererStartColour = lineRendererTemplate.startColor; Color lineRendererEndColour = lineRendererTemplate.endColor; float lineRendererStartWidth = lineRendererTemplate.startWidth * lineRendererTemplate.widthMultiplier; float lineRendererEndWidth = lineRendererTemplate.endWidth * lineRendererTemplate.widthMultiplier; // Save particle properties in a quick loop (accessing these is expensive and loops significantly more later, so it's better to save them once now). for (int i = 0; i < particleCount; i++) { particlePositions[i] = particles[i].position; particleColours[i] = particles[i].GetCurrentColor(particleSystem); particleSizes[i] = particles[i].GetCurrentSize(particleSystem); } Vector3 p1p2_difference; // If in world space, there's no need to do any of the extra calculations... simplify the loop! if (simulationSpace == ParticleSystemSimulationSpace.World) { for (int i = 0; i < particleCount; i++) { if (lrIndex == maxLineRenderers) { break; } Color particleColour = particleColours[i]; Color lineStartColour = Color.LerpUnclamped(lineRendererStartColour, particleColour, colourFromParticle); lineStartColour.a = Mathf.LerpUnclamped(lineRendererStartColour.a, particleColour.a, alphaFromParticle); float lineStartWidth = Mathf.LerpUnclamped(lineRendererStartWidth, particleSizes[i], widthFromParticle); int connections = 0; for (int j = i + 1; j < particleCount; j++) { p1p2_difference.x = particlePositions[i].x - particlePositions[j].x; p1p2_difference.y = particlePositions[i].y - particlePositions[j].y; p1p2_difference.z = particlePositions[i].z - particlePositions[j].z; //float distanceSqr = Vector3.SqrMagnitude(p1p2_difference); float distanceSqr = p1p2_difference.x * p1p2_difference.x + p1p2_difference.y * p1p2_difference.y + p1p2_difference.z * p1p2_difference.z; if (distanceSqr <= maxDistanceSqr) { LineRenderer lr; if (lrIndex == lineRenderersCount) { lr = Instantiate(lineRendererTemplate, _transform, false); lineRenderers.Add(lr); lineRenderersCount++; } lr = lineRenderers[lrIndex]; lr.enabled = true; lr.SetPosition(0, particlePositions[i]); lr.SetPosition(1, particlePositions[j]); lr.startColor = lineStartColour; particleColour = particleColours[j]; Color lineEndColour = Color.LerpUnclamped(lineRendererEndColour, particleColour, colourFromParticle); lineEndColour.a = Mathf.LerpUnclamped(lineRendererEndColour.a, particleColour.a, alphaFromParticle); lr.endColor = lineEndColour; lr.startWidth = lineStartWidth; lr.endWidth = Mathf.LerpUnclamped(lineRendererEndWidth, particleSizes[j], widthFromParticle); lrIndex++; connections++; if (connections == maxConnections || lrIndex == maxLineRenderers) { break; } } } } } else { Vector3 position = Vector3.zero; Quaternion rotation = Quaternion.identity; Vector3 localScale = Vector3.one; Transform simulationSpaceTransform = _transform; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: { position = simulationSpaceTransform.position; rotation = simulationSpaceTransform.rotation; localScale = simulationSpaceTransform.localScale; break; } case ParticleSystemSimulationSpace.Custom: { simulationSpaceTransform = customSimulationSpaceTransform; position = simulationSpaceTransform.position; rotation = simulationSpaceTransform.rotation; localScale = simulationSpaceTransform.localScale; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", simulationSpace)); } } // I put these here so I can take out the default exception case. // Else I'd have a compiler error for potentially unassigned variables. Vector3 p1_position = Vector3.zero; Vector3 p2_position = Vector3.zero; for (int i = 0; i < particleCount; i++) { if (lrIndex == maxLineRenderers) { break; } switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: case ParticleSystemSimulationSpace.Custom: { switch (scalingMode) { case ParticleSystemScalingMode.Hierarchy: { p1_position = simulationSpaceTransform.TransformPoint(particlePositions[i]); break; } case ParticleSystemScalingMode.Local: { // Order is important. //p1_position = Vector3.Scale(particlePositions[i], localScale); p1_position.x = particlePositions[i].x * localScale.x; p1_position.y = particlePositions[i].y * localScale.y; p1_position.z = particlePositions[i].z * localScale.z; p1_position = rotation * p1_position; //p1_position += position; p1_position.x += position.x; p1_position.y += position.y; p1_position.z += position.z; break; } case ParticleSystemScalingMode.Shape: { // Order is important. p1_position = rotation * particlePositions[i]; //p1_position += position; p1_position.x += position.x; p1_position.y += position.y; p1_position.z += position.z; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", scalingMode)); } } break; } } Color particleColour = particleColours[i]; Color lineStartColour = Color.LerpUnclamped(lineRendererStartColour, particleColour, colourFromParticle); lineStartColour.a = Mathf.LerpUnclamped(lineRendererStartColour.a, particleColour.a, alphaFromParticle); float lineStartWidth = Mathf.LerpUnclamped(lineRendererStartWidth, particleSizes[i], widthFromParticle); int connections = 0; for (int j = i + 1; j < particleCount; j++) { // Note that because particles array is not sorted by distance, // but rather by spawn time (I think), the connections made are // not necessarily the closest. switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: case ParticleSystemSimulationSpace.Custom: { switch (scalingMode) { case ParticleSystemScalingMode.Hierarchy: { p2_position = simulationSpaceTransform.TransformPoint(particlePositions[j]); break; } case ParticleSystemScalingMode.Local: { // Order is important. //p2_position = Vector3.Scale(particlePositions[j], localScale); p2_position.x = particlePositions[j].x * localScale.x; p2_position.y = particlePositions[j].y * localScale.y; p2_position.z = particlePositions[j].z * localScale.z; p2_position = rotation * p2_position; //p2_position += position; p2_position.x += position.x; p2_position.y += position.y; p2_position.z += position.z; break; } case ParticleSystemScalingMode.Shape: { // Order is important. p2_position = rotation * particlePositions[j]; //p2_position += position; p2_position.x += position.x; p2_position.y += position.y; p2_position.z += position.z; break; } default: { throw new System.NotSupportedException( string.Format("Unsupported scaling mode '{0}'.", scalingMode)); } } break; } } p1p2_difference.x = particlePositions[i].x - particlePositions[j].x; p1p2_difference.y = particlePositions[i].y - particlePositions[j].y; p1p2_difference.z = particlePositions[i].z - particlePositions[j].z; // Note that distance is always calculated in WORLD SPACE. // Scaling the particle system will stretch the distances // and may require adjusting the maxDistance value. // I could also do it in local space (which may actually make more // sense) by just getting the difference of the positions without // all the transformations. This also provides opportunity for // optimization as I can limit the world space transform calculations // to only happen if a particle is within range. // Think about: Putting in a bool to switch between the two? //float distanceSqr = Vector3.SqrMagnitude(p1p2_difference); float distanceSqr = p1p2_difference.x * p1p2_difference.x + p1p2_difference.y * p1p2_difference.y + p1p2_difference.z * p1p2_difference.z; // If distance to particle within range, add new vertex position. // The larger the max distance, the quicker connections will // reach its max, terminating the loop earlier. So even though more lines have // to be drawn, it's still faster to have a larger maxDistance value because // the call to Vector3.Distance() is expensive. if (distanceSqr <= maxDistanceSqr) { LineRenderer lr; if (lrIndex == lineRenderersCount) { lr = Instantiate(lineRendererTemplate, _transform, false); lineRenderers.Add(lr); lineRenderersCount++; } lr = lineRenderers[lrIndex]; lr.enabled = true; lr.SetPosition(0, p1_position); lr.SetPosition(1, p2_position); lr.startColor = lineStartColour; particleColour = particleColours[j]; Color lineEndColour = Color.LerpUnclamped(lineRendererEndColour, particleColour, colourFromParticle); lineEndColour.a = Mathf.LerpUnclamped(lineRendererEndColour.a, particleColour.a, alphaFromParticle); lr.endColor = lineEndColour; lr.startWidth = lineStartWidth; lr.endWidth = Mathf.LerpUnclamped(lineRendererEndWidth, particleSizes[j], widthFromParticle); lrIndex++; connections++; if (connections == maxConnections || lrIndex == maxLineRenderers) { break; } } } } } } // Disable remaining line renderers from the pool that weren't used. for (int i = lrIndex; i < lineRenderersCount; i++) { if (lineRenderers[i].enabled) { lineRenderers[i].enabled = false; } } } } }
static public void Draw(LightParticleSystem2D id, Camera camera) { ParticleSystem.Particle particle; Vector2 size, pos; ParticleSystem particleSystem = id.GetParticleSystem(); if (particleSystem == null) { return; } ParticleSystemRenderer particleSystemRenderer = id.GetParticleSystemRenderer(); if (particleSystemRenderer == null) { return; } ParticleSystemSimulationSpace simulationSpace = particleSystem.main.simulationSpace; if (id.particleArray == null || id.particleArray.Length < particleSystem.main.maxParticles) { id.particleArray = new ParticleSystem.Particle[particleSystem.main.maxParticles]; } int particlesAlive = particleSystem.GetParticles(id.particleArray); Texture texture = particleSystemRenderer.sharedMaterial.mainTexture; if (id.customParticle) { texture = id.customParticle; } Vector2 offset = -camera.transform.position; Vector2 pOffset = offset; float rotation = id.transform.eulerAngles.z * Mathf.Deg2Rad; Color color = id.color; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: pOffset.x += id.transform.position.x; pOffset.y += id.transform.position.y; break; } Material material = Lighting2D.materials.GetAdditive(); material.SetColor("_TintColor", color); material.mainTexture = texture; material.SetPass(0); GL.Begin(GL.QUADS); for (int p = 0; p < particlesAlive; p++) { particle = id.particleArray [p]; if (particle.remainingLifetime < 0.1f) { continue; } size.x = (particle.GetCurrentSize(particleSystem) * id.scale) / 2; size.y = size.x; switch (simulationSpace) { case ParticleSystemSimulationSpace.Local: pos = particle.position; float angle = Mathf.Atan2(pos.y, pos.x) + rotation; float distance = pos.magnitude; pos.x = Mathf.Cos(angle) * distance; pos.y = Mathf.Sin(angle) * distance; pos.x *= id.transform.localScale.x; pos.y *= id.transform.localScale.y; break; case ParticleSystemSimulationSpace.World: pos = particle.position; break; default: pos = Vector2.zero; break; } pos.x += pOffset.x; pos.y += pOffset.y; //if (InCamera(camera, pos, size.x) == false) { //continue; //} Particle.DrawPass(material, pos, size, particle.rotation, 0); } GL.End(); }
/// <summary> /// Starts the playback of this Playground Recorder with specified starting point, playback speed and if looping should occur. /// </summary> /// <param name="fromNormalizedTime">From normalized time in recording.</param> /// <param name="speed">The speed of the playback.</param> /// <param name="repeat">If set to <c>true</c> then enable looping.</param> public void Play (float fromNormalizedTime, float speed, bool repeat) { if (!_hasPlaygroundSystem) return; if (!_isReplaying && localSpaceOnPlayback) { _previousSimulationSpace = playgroundSystem.shurikenParticleSystem.simulationSpace; playgroundSystem.shurikenParticleSystem.simulationSpace = ParticleSystemSimulationSpace.Local; } playgroundSystem.inPlayback = true; playbackSpeed = speed; loopPlayback = repeat; playHead = fromNormalizedTime; _isReplaying = true; StopRecording(); StartPlayback(); if (playHead >= 1f) playHead = 0; if (Application.isPlaying) StartCoroutine(PlayRecordedFrames(playHead)); }