public override void OnEvent(float power) { if (persistentEmitters == null) { return; } if ((overRideInputs || power > 0) && activated) { UpdateEmitters(power); for (int i = 0; i < persistentEmitters.Count; i++) { PersistentKSPShurikenEmitter pkse = persistentEmitters[i]; pkse.emitting = true; if (pkse.pe != null) { ParticleSystem.EmissionModule em = pkse.pe.emission; em.enabled = false; } } } else { for (int j = 0; j < persistentEmitters.Count; j++) { PersistentKSPShurikenEmitter pkse = persistentEmitters[j]; pkse.emitting = false; if (pkse.pe != null) { ParticleSystem.EmissionModule em = pkse.pe.emission; em.enabled = false; } } } }
private void LateUpdate() { for (int i = 0; i < persistentEmittersShuriken.Count; i++) { PersistentKSPShurikenEmitter em = persistentEmittersShuriken[i]; if (em.endTime > 0 && em.endTime < Time.fixedTime) { em.EmissionStop(); } // If the gameObject is null clean up the emitter if (em.go == null || em.pe == null) { Remove(em); Destroy(em.go); i--; } // if not and the transform parent is null ( Emitter detached from part so the particle are not removed instantly ) // then the emitter won't be updated by the effect Update Call. So update it here else if (em.emitOnUpdate && em.go.transform.parent == null) { em.EmitterOnUpdate(Vector3.zero); if (em.pe.particleCount == 0) { Remove(em); Destroy(em.go); i--; } } } }
public static void Remove(PersistentKSPShurikenEmitter pkpe) { FloatingOrigin.UnregisterParticleSystem(pkpe.pe); persistentEmittersShuriken.Remove(pkpe); Log.dbg("Removed 1 PersistentKSPParticleEmitter. Count = {0}", persistentEmittersShuriken.Count); }
public static void Remove(PersistentKSPShurikenEmitter pkpe) { FloatingOrigin.UnregisterParticleSystem(pkpe.pe); persistentEmittersShuriken.Remove(pkpe); //print("[SmokeScreen PersistentEmitterManager]: Removed 1 PersistentKSPParticleEmitter. Count = " + persistentEmitters.Count); }
// First, I tried to emit particles on regular Update, but stuff was weird, and the plume still appeared out of sync with frame draws // According to https://docs.unity3d.com/Manual/ExecutionOrder.html // LateUpdate is the last thing that happens before frame draw. That makes it as synced to frame draws, as possible // LateUpdate is called after physics calculations too, so the newly emitted plume particles are right where they should be. public void LateUpdate() { if (persistentEmitters == null || hostPart == null || hostPart.Rigidbody == null) { return; } // I think it's important to call this even though it doesn't count active particles // because it calculates how many particles should be removed on next emit pass. SmokeScreenConfig.UpdateParticlesCount(); for (int i = 0; i < persistentEmitters.Count; i++) { PersistentKSPShurikenEmitter emitter = persistentEmitters[i]; if (EmitOnUpdate) { emitter.EmitterOnUpdate(hostPart.Rigidbody.velocity + Krakensbane.GetFrameVelocity()); } } }
public void FixedUpdate() { //Print("FixedUpdate"); if (persistentEmitters == null || hostPart == null || hostPart.Rigidbody == null) { return; } if (singleTimerEnd > 0) { if (Time.fixedTime <= singleTimerEnd) { OnEvent(1f); } else { OnEvent(0f); singleTimerEnd = 0; } } SmokeScreenConfig.UpdateParticlesCount(); //RaycastHit vHit = new RaycastHit(); //Ray vRay = Camera.main.ScreenPointToRay(Input.mousePosition); //if(Physics.Raycast(vRay, out vHit)) //{ // RaycastHit vHit2 = new RaycastHit(); // if (Physics.Raycast(vHit.point + vHit.normal * 10, -vHit.normal, out vHit2)) // Debug.Log(vHit2.collider.name); //} for (int i = 0; i < persistentEmitters.Count; i++) { PersistentKSPShurikenEmitter emitter = persistentEmitters[i]; // This is FixedUpdate, so don't emit here if particles should emit in LateUpdate if (!EmitOnUpdate) { emitter.EmitterOnUpdate(hostPart.Rigidbody.velocity + Krakensbane.GetFrameVelocity()); } } }
public override void OnEvent(float power, int transformIdx) { if (persistentEmitters == null || transformIdx >= persistentEmitters.Count) { return; } if (transformIdx == -1) { OnEvent(power); return; } PersistentKSPShurikenEmitter pkse = persistentEmitters[transformIdx]; if ((overRideInputs || power > 0) && activated) { UpdateEmitters(power); pkse.emitting = true; if (pkse.pe != null) { ParticleSystem.EmissionModule em = pkse.pe.emission; em.enabled = false; } } else { pkse.emitting = false; if (pkse.pe != null) { ParticleSystem.EmissionModule em = pkse.pe.emission; em.enabled = false; } } }
public override void OnInitialize() { //Print("OnInitialize"); // Ship spawned somehow don't call OnLoad... if (node_backup != string.Empty) { Restore(); } List <Transform> transforms = new List <Transform>(hostPart.FindModelTransforms(transformName)); if (transforms.Count == 0) { if (transformName == "partTransform") { transforms.Add(hostPart.partTransform); } else { Log.info("Cannot find transform {0}", transformName); return; } } GameObject model = GameDatabase.Instance.GetModel(modelName); if (model == null) { Log.info("Cannot find model {0}", modelName); return; } model.SetActive(true); KSPParticleEmitter templateKspParticleEmitter = model.GetComponentInChildren <KSPParticleEmitter>(); if (templateKspParticleEmitter == null) { Log.info("Cannot find particle emitter on {0}", modelName); Destroy(model); return; } if (persistentEmitters == null) { persistentEmitters = new List <PersistentKSPShurikenEmitter>(); } if (hostPart.Modules.Contains("ProceduralSRB")) { PartModule pm = hostPart.Modules["ProceduralSRB"]; specialScale = pm.Fields.GetValue <float>("bellScale"); Log.info("Found ProceduralSRB. Rescaling by {0:0.000} final scale {1}:0.000}", specialScale, (fixedScale * specialScale)); } if (hostPart.Modules.Contains("TweakScale")) { PartModule pm = hostPart.Modules["TweakScale"]; float tweakScale = pm.Fields.GetValue <float>("currentScale"); float defaultScale = pm.Fields.GetValue <float>("defaultScale"); specialScale = tweakScale / (defaultScale <= 0 ? 1 : defaultScale); Log.info("Found TweakScale. Rescaling by {0:0.000} final scale {1:0.000}", specialScale, (fixedScale * specialScale)); } for (int i = 0; i < transforms.Count; i++) { GameObject emitterGameObject = i == 0 ? model : Instantiate(model); KSPParticleEmitter childKSPParticleEmitter = emitterGameObject.GetComponentInChildren <KSPParticleEmitter>(); if (childKSPParticleEmitter != null) { ParticleSystem particleSystem = childKSPParticleEmitter.gameObject.GetComponent <ParticleSystem>(); ParticleSystemRenderer particleSystemRenderer = childKSPParticleEmitter.gameObject.GetComponent <ParticleSystemRenderer>(); PersistentKSPShurikenEmitter pkpe = new PersistentKSPShurikenEmitter( emitterGameObject, particleSystem, particleSystemRenderer, childKSPParticleEmitter); // We do the emission and animation ourselves so we disable the KSP code childKSPParticleEmitter.emit = false; childKSPParticleEmitter.SetupProperties(); childKSPParticleEmitter.enabled = false; ParticleSystem.MainModule main = particleSystem.main; main.maxParticles = particleCountLimit; //particleSystemRenderer.alignment = ParticleSystemRenderSpace.View; pkpe.doesAnimateColor = childKSPParticleEmitter.doesAnimateColor; if (childKSPParticleEmitter.doesAnimateColor) { ParticleSystem.ColorOverLifetimeModule col = particleSystem.colorOverLifetime; // This one is annoying. The old particle system animate the color over the whole % life of the particle (0 - 1) // The new one animate it over time. So converted system may not reach the full value // The color is manually set in the update of PersistentKSPShurikenEmitter col.enabled = false; Color[] colors = childKSPParticleEmitter.colorAnimation; pkpe.colors = new Color[colors.Length]; Array.Copy(colors, pkpe.colors, colors.Length); } //try //{ // particleSystemRenderer.renderMode = // (ParticleSystemRenderMode)Enum.Parse(typeof (ParticleSystemRenderMode), renderMode); //} //catch (ArgumentException) //{ // Print("ModelMultiParticleFXExt: " + renderMode + " is not a valid ParticleSystemRenderMode"); //} persistentEmitters.Add(pkpe); DisableCollider(pkpe.go); emitterGameObject.transform.SetParent(transforms[i], false); emitterGameObject.transform.localPosition = localPosition; emitterGameObject.transform.localRotation = Quaternion.Euler(localRotation); emitterGameObject.SetLayerRecursive(layerId); } } list.Add(this); // 1.0 don't seems to properly do this for engines. //OnEvent(0f); }
public void UpdateEmitters(float power) { UpdateInputs(power); for (int i = 0; i < persistentEmitters.Count; i++) { PersistentKSPShurikenEmitter pkpe = persistentEmitters[i]; if (pkpe.go == null) { continue; } float finalScale = fixedScale * specialScale; float finalSizeClamp = sizeClamp + sizeClampCurve.Value(inputs); float sizePower = size.Value(inputs) * finalScale; pkpe.minSize = Mathf.Min(pkpe.minSizeBase * sizePower, finalSizeClamp); pkpe.maxSize = Mathf.Min(pkpe.maxSizeBase * sizePower, finalSizeClamp); float emissionPower = emission.Value(inputs) * emissionMult; pkpe.minEmission = Mathf.FloorToInt(pkpe.minEmissionBase * emissionPower); pkpe.maxEmission = Mathf.FloorToInt(pkpe.maxEmissionBase * emissionPower); float energyPower = energy.Value(inputs); pkpe.minEnergy = pkpe.minEnergyBase * energyPower; pkpe.maxEnergy = pkpe.maxEnergyBase * energyPower; float velocityPower = speed.Value(inputs) * finalScale; pkpe.localVelocity = pkpe.localVelocityBase * velocityPower; pkpe.worldVelocity = pkpe.worldVelocityBase * velocityPower; float forcePower = force.Value(inputs); pkpe.force = pkpe.forceBase * forcePower; ParticleSystem.ForceOverLifetimeModule fol = pkpe.pe.forceOverLifetime; fol.enabled = pkpe.force.sqrMagnitude > 0 || pkpe.rndForce.sqrMagnitude > 0; fol.x = new ParticleSystem.MinMaxCurve(pkpe.forceBase.x, pkpe.force.x + pkpe.rndForce.x); fol.y = new ParticleSystem.MinMaxCurve(pkpe.forceBase.y, pkpe.force.y + pkpe.rndForce.y); fol.z = new ParticleSystem.MinMaxCurve(pkpe.forceBase.z, pkpe.force.z + pkpe.rndForce.z); pkpe.sizeGrow = grow.Value(inputs); float currentScale = scale.Value(inputs) * finalScale; pkpe.shape1D = pkpe.scale1DBase * currentScale; pkpe.shape2D = pkpe.scale2DBase * currentScale; pkpe.shape3D = pkpe.scale3DBase * currentScale; pkpe.sizeClamp = finalSizeClamp; pkpe.randomInitalVelocityOffsetMaxRadius = randomInitalVelocityOffsetMaxRadius + initalVelocityOffsetMaxRadius.Value(inputs); pkpe.randConeEmit = randConeEmit.Value(inputs); pkpe.xyForce = xyForce.Value(inputs); pkpe.zForce = zForce.Value(inputs); pkpe.vRandPosOffset = vRandPosOffset.Value(inputs); pkpe.vPosOffset = vPosOffset.Value(inputs); pkpe.physical = physical && !SmokeScreenConfig.Instance.globalPhysicalDisable; pkpe.initialDensity = initialDensity; pkpe.dragCoefficient = dragCoefficient; pkpe.collide = collide && !SmokeScreenConfig.Instance.globalCollideDisable; pkpe.stickiness = stickiness; pkpe.collideRatio = collideRatio; pkpe.logarithmicGrow = logGrow.Value(inputs); pkpe.logarithmicGrowScale = logGrowScale.Value(inputs); pkpe.decluster = decluster; pkpe.emitOnUpdate = EmitOnUpdate; pkpe.linearGrow = linGrow.Value(inputs); if (alpha.Value(inputs) != 1 || linAlphaDecay.Value(inputs) != 0 || logAlphaDecay.Value(inputs) != 0) { //Color[] cols = new Color[5]; GradientColorKey[] colorKeys = new GradientColorKey[5]; GradientAlphaKey[] alphaKeys = new GradientAlphaKey[5]; for (int t = 0; t < 5; t++) { float a = Mathf.Clamp01(alpha.Value(inputs) * (1 - linAlphaDecay.Value(inputs) * (t / 4f) - Mathf.Log(logAlphaDecay.Value(inputs) * (t / 4f) + 1))); colorKeys[t] = new GradientColorKey(Color.red, t * 0.25f); alphaKeys[t] = new GradientAlphaKey(a, t * 0.25f); } ParticleSystem.ColorOverLifetimeModule col = pkpe.pe.colorOverLifetime; col.enabled = true; Gradient gradient = new Gradient(); gradient.SetKeys(colorKeys, alphaKeys); col.color = new ParticleSystem.MinMaxGradient(gradient); } pkpe.saturationMult = saturationMult.Value(inputs); pkpe.brightnessMult = brightnessMult.Value(inputs); pkpe.alphaMult = alphaMult.Value(inputs); pkpe.go.transform.localPosition = localPosition + offset.Value(inputs) * finalScale * offsetDirection.normalized; pkpe.go.transform.localRotation = Quaternion.Euler(localRotation); } }
public static void Add(PersistentKSPShurikenEmitter pkpe) { persistentEmittersShuriken.Add(pkpe); FloatingOrigin.RegisterParticleSystem(pkpe.pe); }
public override void OnInitialize() { //Print("Init"); // Restore the Curve config from the node content backup // Done because I could not get the serialization of MultiInputCurve to work if (node_backup != string.Empty) { Restore(); } List<Transform> transforms = new List<Transform>(hostPart.FindModelTransforms(transformName)); if (transforms.Count == 0) { Print("Cannot find transform " + transformName); return; } GameObject model = GameDatabase.Instance.GetModel(modelName); if (model == null) { Print("Cannot find model " + modelName); return; } model.SetActive(true); KSPParticleEmitter templateKspParticleEmitter = model.GetComponentInChildren<KSPParticleEmitter>(); if (templateKspParticleEmitter == null) { Print("Cannot find particle emitter on " + modelName); Destroy(model); return; } if (persistentEmitters == null) { persistentEmitters = new List<PersistentKSPShurikenEmitter>(); } if (hostPart.Modules.Contains("ProceduralSRB")) { PartModule pm = hostPart.Modules["ProceduralSRB"]; specialScale = pm.Fields.GetValue<float>("bellScale"); Print("Found ProceduralSRB. Rescaling by " + specialScale.ToString("F3") + " final scale " + (fixedScale * specialScale).ToString("F3")); } for (int i = 0; i < transforms.Count; i++) { GameObject emitterGameObject = Instantiate(model) as GameObject; KSPParticleEmitter childKSPParticleEmitter = emitterGameObject.GetComponentInChildren<KSPParticleEmitter>(); //if (shader != null) //{ // childKSPParticleEmitter.material.shader = shader; // childKSPParticleEmitter.pr.material.shader = shader; //} if (childKSPParticleEmitter != null) { // Destroy them ? childKSPParticleEmitter.pr.enabled = false; childKSPParticleEmitter.pe.enabled = false; childKSPParticleEmitter.enabled = false; ParticleSystem particleSystem = childKSPParticleEmitter.gameObject.AddComponent<ParticleSystem>(); ParticleSystemRenderer particleSystemRenderer = childKSPParticleEmitter.gameObject.GetComponent<ParticleSystemRenderer>(); PersistentKSPShurikenEmitter pkpe = new PersistentKSPShurikenEmitter( emitterGameObject, particleSystem, particleSystemRenderer, templateKspParticleEmitter); particleSystem.simulationSpace = childKSPParticleEmitter.pe.useWorldSpace ? ParticleSystemSimulationSpace.World : ParticleSystemSimulationSpace.Local; particleSystem.maxParticles = particleCountLimit; particleSystemRenderer.material = childKSPParticleEmitter.pr.material; // TODO Actually copy the mode from childKSPParticleEmitter.particleRenderMode? particleSystemRenderer.renderMode = ParticleSystemRenderMode.Billboard; try { childKSPParticleEmitter.particleRenderMode = (ParticleRenderMode)Enum.Parse(typeof(ParticleRenderMode), renderMode); } catch (ArgumentException) { Print("ModelMultiParticleFXExt: " + renderMode + " is not a valid ParticleRenderMode"); } switch (childKSPParticleEmitter.particleRenderMode) { case ParticleRenderMode.Billboard: particleSystemRenderer.renderMode = ParticleSystemRenderMode.Billboard; break; case ParticleRenderMode.Stretch: particleSystemRenderer.renderMode = ParticleSystemRenderMode.Stretch; break; case ParticleRenderMode.SortedBillboard: particleSystemRenderer.renderMode = ParticleSystemRenderMode.Billboard; particleSystemRenderer.sortMode = ParticleSystemSortMode.Distance; break; case ParticleRenderMode.HorizontalBillboard: particleSystemRenderer.renderMode = ParticleSystemRenderMode.HorizontalBillboard; break; case ParticleRenderMode.VerticalBillboard: particleSystemRenderer.renderMode = ParticleSystemRenderMode.VerticalBillboard; break; default: particleSystemRenderer.renderMode = ParticleSystemRenderMode.Billboard; break; } //particleSystemRenderer.alignment = ParticleSystemRenderSpace.View; if (childKSPParticleEmitter.doesAnimateColor) { ParticleSystem.ColorOverLifetimeModule col = particleSystem.colorOverLifetime; col.enabled = true; GradientColorKey[] colorKeys = new GradientColorKey[5]; GradientAlphaKey[] alphaKeys = new GradientAlphaKey[5]; Color[] colors = childKSPParticleEmitter.colorAnimation; float step = 1f / (colors.Length - 1); for (int t = 0; t < colors.Length; t++) { colorKeys[t] = new GradientColorKey(colors[t], t * step); alphaKeys[t] = new GradientAlphaKey(colors[t].a, t * step); } Gradient gradient = new Gradient(); gradient.SetKeys(colorKeys, alphaKeys); col.color = new ParticleSystem.MinMaxGradient(gradient); } //try //{ // particleSystemRenderer.renderMode = // (ParticleSystemRenderMode)Enum.Parse(typeof (ParticleSystemRenderMode), renderMode); //} //catch (ArgumentException) //{ // Print("ModelMultiParticleFXExt: " + renderMode + " is not a valid ParticleSystemRenderMode"); //} persistentEmitters.Add(pkpe); DisableCollider(pkpe.go); emitterGameObject.transform.SetParent(transforms[i]); emitterGameObject.transform.localPosition = localPosition; emitterGameObject.transform.localRotation = Quaternion.Euler(localRotation); emitterGameObject.SetLayerRecursive(layerId); } } Destroy(model); list.Add(this); // 1.0 don't seems to properly do this for engines. OnEvent(0); }