mixedreality/com.microsoft.mixedreality..../Core/Utilities/Lines/Renderers/ParticleSystemLineRenderer.cs

234 lines
7.3 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Utilities
{
/// <summary>
/// attaches a set of particles to the line
/// </summary>
[RequireComponent(typeof(ParticleSystem))]
[AddComponentMenu("Scripts/MRTK/Core/ParticleSystemLineRenderer")]
public class ParticleSystemLineRenderer : BaseMixedRealityLineRenderer
{
private const int GlobalMaxParticles = 2048;
[Header("Particle Settings")]
[SerializeField]
private Material lineMaterial;
public Material LineMaterial
{
get { return lineMaterial; }
set { lineMaterial = value; }
}
[SerializeField]
[Range(128, GlobalMaxParticles)]
private int maxParticles = GlobalMaxParticles;
public int MaxParticles
{
get { return maxParticles; }
set { maxParticles = Mathf.Clamp(value, 128, GlobalMaxParticles); }
}
[Header("Noise settings")]
[SerializeField]
private bool particleNoiseOnDisabled = true;
public bool ParticleNoiseOnDisabled
{
get { return particleNoiseOnDisabled; }
set { particleNoiseOnDisabled = value; }
}
[SerializeField]
private Vector3 noiseStrength = Vector3.one;
public Vector3 NoiseStrength
{
get { return noiseStrength; }
set { noiseStrength = value; }
}
[SerializeField]
private float noiseFrequency = 1.2f;
public float NoiseFrequency
{
get { return noiseFrequency; }
set { noiseFrequency = value; }
}
[Range(1, 10)]
[SerializeField]
private int noiseOcatives = 3;
public int NoiseOcatives
{
get { return noiseOcatives; }
set { noiseOcatives = Mathf.Clamp(value, 1, 10); }
}
[SerializeField]
[Range(-10f, 10f)]
private float noiseSpeed = 1f;
public float NoiseSpeed
{
get { return noiseSpeed; }
set { noiseSpeed = Mathf.Clamp(value, -10f, 10f); }
}
[SerializeField]
[Range(0.01f, 0.5f)]
private float lifetimeAfterDisabled = 0.25f;
public float LifetimeAfterDisabled
{
get { return lifetimeAfterDisabled; }
set { lifetimeAfterDisabled = Mathf.Clamp(value, 0.01f, 0.5f); }
}
[SerializeField]
private Gradient decayGradient = new Gradient();
public Gradient DecayGradient
{
get { return decayGradient; }
set { decayGradient = value; }
}
[SerializeField]
[HideInInspector]
private ParticleSystem particles;
[SerializeField]
[HideInInspector]
private ParticleSystemRenderer mainParticleRenderer;
public ParticleSystemRenderer MainParticleRenderer
{
get
{
if (particles == null)
{
particles = gameObject.EnsureComponent<ParticleSystem>();
}
if (mainParticleRenderer == null)
{
mainParticleRenderer = particles.EnsureComponent<ParticleSystemRenderer>();
}
return mainParticleRenderer;
}
set { mainParticleRenderer = value; }
}
private readonly ParticleSystem.Particle[] mainParticleArray = new ParticleSystem.Particle[GlobalMaxParticles];
private ParticleSystem.NoiseModule mainNoiseModule;
private float decayStartTime = 0f;
private void OnEnable()
{
if (particles == null)
{
particles = gameObject.EnsureComponent<ParticleSystem>();
}
mainNoiseModule = particles.noise;
ParticleSystem.EmissionModule emission = particles.emission;
emission.rateOverTime = new ParticleSystem.MinMaxCurve(0);
emission.rateOverDistance = new ParticleSystem.MinMaxCurve(0);
emission.enabled = true;
ParticleSystem.MainModule main = particles.main;
main.loop = false;
main.playOnAwake = false;
main.maxParticles = Mathf.Min(maxParticles, GlobalMaxParticles);
main.simulationSpace = ParticleSystemSimulationSpace.World;
ParticleSystem.ShapeModule shape = particles.shape;
shape.enabled = false;
MainParticleRenderer.sharedMaterial = lineMaterial;
MainParticleRenderer.enabled = true;
// Initialize our particles
for (int i = 0; i < mainParticleArray.Length; i++)
{
ParticleSystem.Particle particle = mainParticleArray[i];
particle.startColor = Color.white;
particle.startSize = 1f;
particle.startLifetime = float.MaxValue;
particle.remainingLifetime = float.MaxValue;
particle.velocity = Vector3.zero;
particle.angularVelocity = 0;
mainParticleArray[i] = particle;
}
}
/// <inheritdoc />
protected override void UpdateLine()
{
if (!LineDataSource.enabled)
{
mainNoiseModule.enabled = particleNoiseOnDisabled;
mainNoiseModule.strengthX = noiseStrength.x;
mainNoiseModule.strengthY = noiseStrength.y;
mainNoiseModule.strengthZ = noiseStrength.z;
mainNoiseModule.octaveCount = noiseOcatives;
mainNoiseModule.scrollSpeed = noiseSpeed;
mainNoiseModule.frequency = noiseFrequency;
if (decayStartTime < 0)
{
decayStartTime = Time.unscaledTime;
}
}
else
{
mainNoiseModule.enabled = false;
decayStartTime = -1;
}
if (LineDataSource.enabled)
{
for (int i = 0; i < LineStepCount; i++)
{
float normalizedDistance = GetNormalizedPointAlongLine(i);
ParticleSystem.Particle particle = mainParticleArray[i];
particle.position = LineDataSource.GetPoint(normalizedDistance);
particle.startColor = GetColor(normalizedDistance);
particle.startSize = GetWidth(normalizedDistance);
mainParticleArray[i] = particle;
}
}
else
{
int numDecayingParticles = particles.GetParticles(mainParticleArray);
for (int i = 0; i < numDecayingParticles; i++)
{
float normalizedDistance = (1f / (LineStepCount - 1)) * i;
mainParticleArray[i].startColor = decayGradient.Evaluate((Time.unscaledTime - decayStartTime) / lifetimeAfterDisabled) * GetColor(normalizedDistance);
}
}
particles.SetParticles(mainParticleArray, LineStepCount);
}
private void OnDisable()
{
MainParticleRenderer.enabled = false;
}
}
}