9 [RequireComponent(typeof(CanvasRenderer), typeof(ParticleSystem))]
10 [AddComponentMenu(
"UI/Effects/Extensions/UIParticleSystem")]
11 public class UIParticleSystem : MaskableGraphic
13 [Tooltip(
"Having this enabled run the system in LateUpdate rather than in Update making it faster but less precise (more clunky)")]
14 public bool fixedTime =
true;
16 [Tooltip(
"Enables 3d rotation for the particles")]
17 public bool use3dRotation =
false;
19 private Transform _transform;
20 private ParticleSystem pSystem;
21 private ParticleSystem.Particle[] particles;
22 private UIVertex[] _quad =
new UIVertex[4];
24 private ParticleSystem.TextureSheetAnimationModule textureSheetAnimation;
25 private int textureSheetAnimationFrames;
26 private Vector2 textureSheetAnimationFrameSize;
27 private ParticleSystemRenderer pRenderer;
28 private bool isInitialised =
false;
30 private Material currentMaterial;
32 private Texture currentTexture;
35 private ParticleSystem.MainModule mainModule;
38 public override Texture mainTexture
42 return currentTexture;
46 protected bool Initialize()
49 if (_transform ==
null)
51 _transform = transform;
55 pSystem = GetComponent<ParticleSystem>();
63 mainModule = pSystem.main;
64 if (pSystem.main.maxParticles > 14000)
66 mainModule.maxParticles = 14000;
69 if (pSystem.maxParticles > 14000)
70 pSystem.maxParticles = 14000;
73 pRenderer = pSystem.GetComponent<ParticleSystemRenderer>();
74 if (pRenderer !=
null)
75 pRenderer.enabled =
false;
79 var foundShader = Shader.Find(
"UI Extensions/Particles/Additive");
82 material =
new Material(foundShader);
86 currentMaterial = material;
87 if (currentMaterial && currentMaterial.HasProperty(
"_MainTex"))
89 currentTexture = currentMaterial.mainTexture;
90 if (currentTexture ==
null)
91 currentTexture = Texture2D.whiteTexture;
93 material = currentMaterial;
96 mainModule.scalingMode = ParticleSystemScalingMode.Hierarchy;
98 pSystem.scalingMode = ParticleSystemScalingMode.Hierarchy;
103#if UNITY_5_5_OR_NEWER
104 if (particles ==
null)
105 particles =
new ParticleSystem.Particle[pSystem.main.maxParticles];
107 if (particles ==
null)
108 particles =
new ParticleSystem.Particle[pSystem.maxParticles];
111 imageUV =
new Vector4(0, 0, 1, 1);
114 textureSheetAnimation = pSystem.textureSheetAnimation;
115 textureSheetAnimationFrames = 0;
116 textureSheetAnimationFrameSize =
Vector2.zero;
117 if (textureSheetAnimation.enabled)
119 textureSheetAnimationFrames = textureSheetAnimation.numTilesX * textureSheetAnimation.numTilesY;
120 textureSheetAnimationFrameSize =
new Vector2(1f / textureSheetAnimation.numTilesX, 1f / textureSheetAnimation.numTilesY);
126 protected override void Awake()
134 protected override void OnPopulateMesh(VertexHelper vh)
137 if (!Application.isPlaying)
148 if (!gameObject.activeInHierarchy)
153 if (!isInitialised && !pSystem.main.playOnAwake)
155 pSystem.Stop(
false, ParticleSystemStopBehavior.StopEmittingAndClear);
156 isInitialised =
true;
163 int count = pSystem.GetParticles(particles);
165 for (
int i = 0; i < count; ++i)
167 ParticleSystem.Particle particle = particles[i];
170#if UNITY_5_5_OR_NEWER
171 Vector2 position = (mainModule.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
173 Vector2 position = (pSystem.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
175 float rotation = -particle.rotation * Mathf.Deg2Rad;
176 float rotation90 = rotation + Mathf.PI / 2;
177 Color32 color = particle.GetCurrentColor(pSystem);
178 float size = particle.GetCurrentSize(pSystem) * 0.5f;
181#if UNITY_5_5_OR_NEWER
182 if (mainModule.scalingMode == ParticleSystemScalingMode.Shape)
183 position /= canvas.scaleFactor;
185 if (pSystem.scalingMode == ParticleSystemScalingMode.Shape)
186 position /= canvas.scaleFactor;
191 if (textureSheetAnimation.enabled)
193#if UNITY_5_5_OR_NEWER
194 float frameProgress = 1 - (particle.remainingLifetime / particle.startLifetime);
196 if (textureSheetAnimation.frameOverTime.curveMin !=
null)
198 frameProgress = textureSheetAnimation.frameOverTime.curveMin.Evaluate(1 - (particle.remainingLifetime / particle.startLifetime));
200 else if (textureSheetAnimation.frameOverTime.curve !=
null)
202 frameProgress = textureSheetAnimation.frameOverTime.curve.Evaluate(1 - (particle.remainingLifetime / particle.startLifetime));
204 else if (textureSheetAnimation.frameOverTime.constant > 0)
206 frameProgress = textureSheetAnimation.frameOverTime.constant - (particle.remainingLifetime / particle.startLifetime);
209 float frameProgress = 1 - (particle.lifetime / particle.startLifetime);
212 frameProgress = Mathf.Repeat(frameProgress * textureSheetAnimation.cycleCount, 1);
215 switch (textureSheetAnimation.animation)
218 case ParticleSystemAnimationType.WholeSheet:
219 frame = Mathf.FloorToInt(frameProgress * textureSheetAnimationFrames);
222 case ParticleSystemAnimationType.SingleRow:
223 frame = Mathf.FloorToInt(frameProgress * textureSheetAnimation.numTilesX);
225 int row = textureSheetAnimation.rowIndex;
229 frame += row * textureSheetAnimation.numTilesX;
234 frame %= textureSheetAnimationFrames;
236 particleUV.x = (frame % textureSheetAnimation.numTilesX) * textureSheetAnimationFrameSize.x;
237 particleUV.y = 1.0f - Mathf.FloorToInt(frame / textureSheetAnimation.numTilesX) * textureSheetAnimationFrameSize.y;
238 particleUV.z = particleUV.x + textureSheetAnimationFrameSize.x;
239 particleUV.w = particleUV.y + textureSheetAnimationFrameSize.y;
242 temp.x = particleUV.x;
243 temp.y = particleUV.y;
245 _quad[0] = UIVertex.simpleVert;
246 _quad[0].color = color;
249 temp.x = particleUV.x;
250 temp.y = particleUV.w;
251 _quad[1] = UIVertex.simpleVert;
252 _quad[1].color = color;
255 temp.x = particleUV.z;
256 temp.y = particleUV.w;
257 _quad[2] = UIVertex.simpleVert;
258 _quad[2].color = color;
261 temp.x = particleUV.z;
262 temp.y = particleUV.y;
263 _quad[3] = UIVertex.simpleVert;
264 _quad[3].color = color;
270 corner1.x = position.x - size;
271 corner1.y = position.y - size;
272 corner2.x = position.x + size;
273 corner2.y = position.y + size;
277 _quad[0].position = temp;
280 _quad[1].position = temp;
283 _quad[2].position = temp;
286 _quad[3].position = temp;
293#if UNITY_5_5_OR_NEWER
294 Vector3 pos3d = (mainModule.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
296 Vector3 pos3d = (pSystem.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
300#if UNITY_5_5_OR_NEWER
301 if (mainModule.scalingMode == ParticleSystemScalingMode.Shape)
302 position /= canvas.scaleFactor;
304 if (pSystem.scalingMode == ParticleSystemScalingMode.Shape)
305 position /= canvas.scaleFactor;
318 _quad[0].position = pos3d + particleRotation * verts[0];
319 _quad[1].position = pos3d + particleRotation * verts[1];
320 _quad[2].position = pos3d + particleRotation * verts[2];
321 _quad[3].position = pos3d + particleRotation * verts[3];
326 Vector2 right =
new Vector2(Mathf.Cos(rotation), Mathf.Sin(rotation)) * size;
327 Vector2 up =
new Vector2(Mathf.Cos(rotation90), Mathf.Sin(rotation90)) * size;
329 _quad[0].position = position - right - up;
330 _quad[1].position = position - right + up;
331 _quad[2].position = position + right + up;
332 _quad[3].position = position + right - up;
336 vh.AddUIVertexQuad(_quad);
340 private void Update()
342 if (!fixedTime && Application.isPlaying)
344 pSystem.Simulate(Time.unscaledDeltaTime,
false,
false,
true);
347 if ((currentMaterial !=
null && currentTexture != currentMaterial.mainTexture) ||
348 (material !=
null && currentMaterial !=
null && material.shader != currentMaterial.shader))
356 private void LateUpdate()
358 if (!Application.isPlaying)
366 pSystem.Simulate(Time.unscaledDeltaTime,
false,
false,
true);
368 if ((currentMaterial !=
null && currentTexture != currentMaterial.mainTexture) ||
369 (material !=
null && currentMaterial !=
null && material.shader != currentMaterial.shader))
376 if (material == currentMaterial)
382 protected override void OnDestroy()
384 currentMaterial =
null;
385 currentTexture =
null;
388 public void StartParticleEmission()
393 public void StopParticleEmission()
395 pSystem.Stop(
false, ParticleSystemStopBehavior.StopEmittingAndClear);
398 public void PauseParticleEmission()
400 pSystem.Stop(
false, ParticleSystemStopBehavior.StopEmitting);
Credit Erdener Gonenc - @PixelEnvision.