123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- /// Credit glennpow, Zarlang
- /// Sourced from - http://forum.unity3d.com/threads/free-script-particle-systems-in-ui-screen-space-overlay.406862/
- /// Updated by Zarlang with a more robust implementation, including TextureSheet annimation support
- namespace UnityEngine.UI.Extensions.FantasyRPG
- {
- #if UNITY_5_3_OR_NEWER
- [ExecuteInEditMode]
- [RequireComponent(typeof(CanvasRenderer), typeof(ParticleSystem))]
- [AddComponentMenu("UI/Effects/Extensions/UIParticleSystem")]
- public class UIParticleSystem : MaskableGraphic
- {
- [Tooltip("Having this enabled run the system in LateUpdate rather than in Update making it faster but less precise (more clunky)")]
- public bool fixedTime = true;
- [Tooltip("Enables 3d rotation for the particles")]
- public bool use3dRotation = false;
- private Transform _transform;
- private ParticleSystem pSystem;
- private ParticleSystem.Particle[] particles;
- private UIVertex[] _quad = new UIVertex[4];
- private Vector4 imageUV = Vector4.zero;
- private ParticleSystem.TextureSheetAnimationModule textureSheetAnimation;
- private int textureSheetAnimationFrames;
- private Vector2 textureSheetAnimationFrameSize;
- private ParticleSystemRenderer pRenderer;
- private bool isInitialised = false;
- private Material currentMaterial;
- private Texture currentTexture;
- #if UNITY_5_5_OR_NEWER
- private ParticleSystem.MainModule mainModule;
- #endif
- public override Texture mainTexture
- {
- get
- {
- return currentTexture;
- }
- }
- protected bool Initialize()
- {
- // initialize members
- if (_transform == null)
- {
- _transform = transform;
- }
- if (pSystem == null)
- {
- pSystem = GetComponent<ParticleSystem>();
- if (pSystem == null)
- {
- return false;
- }
- #if UNITY_5_5_OR_NEWER
- mainModule = pSystem.main;
- if (pSystem.main.maxParticles > 14000)
- {
- mainModule.maxParticles = 14000;
- }
- #else
- if (pSystem.maxParticles > 14000)
- pSystem.maxParticles = 14000;
- #endif
- pRenderer = pSystem.GetComponent<ParticleSystemRenderer>();
- if (pRenderer != null)
- pRenderer.enabled = false;
- if (material == null)
- {
- var foundShader = Shader.Find("UI Extensions/Particles/Additive");
- if (foundShader)
- {
- material = new Material(foundShader);
- }
- }
- currentMaterial = material;
- if (currentMaterial && currentMaterial.HasProperty("_MainTex"))
- {
- currentTexture = currentMaterial.mainTexture;
- if (currentTexture == null)
- currentTexture = Texture2D.whiteTexture;
- }
- material = currentMaterial;
- // automatically set scaling
- #if UNITY_5_5_OR_NEWER
- mainModule.scalingMode = ParticleSystemScalingMode.Hierarchy;
- #else
- pSystem.scalingMode = ParticleSystemScalingMode.Hierarchy;
- #endif
- particles = null;
- }
- #if UNITY_5_5_OR_NEWER
- if (particles == null)
- particles = new ParticleSystem.Particle[pSystem.main.maxParticles];
- #else
- if (particles == null)
- particles = new ParticleSystem.Particle[pSystem.maxParticles];
- #endif
- imageUV = new Vector4(0, 0, 1, 1);
- // prepare texture sheet animation
- textureSheetAnimation = pSystem.textureSheetAnimation;
- textureSheetAnimationFrames = 0;
- textureSheetAnimationFrameSize = Vector2.zero;
- if (textureSheetAnimation.enabled)
- {
- textureSheetAnimationFrames = textureSheetAnimation.numTilesX * textureSheetAnimation.numTilesY;
- textureSheetAnimationFrameSize = new Vector2(1f / textureSheetAnimation.numTilesX, 1f / textureSheetAnimation.numTilesY);
- }
- return true;
- }
- protected override void Awake()
- {
- base.Awake();
- if (!Initialize())
- enabled = false;
- }
- protected override void OnPopulateMesh(VertexHelper vh)
- {
- #if UNITY_EDITOR
- if (!Application.isPlaying)
- {
- if (!Initialize())
- {
- return;
- }
- }
- #endif
- // prepare vertices
- vh.Clear();
- if (!gameObject.activeInHierarchy)
- {
- return;
- }
- if (!isInitialised && !pSystem.main.playOnAwake)
- {
- pSystem.Stop(false, ParticleSystemStopBehavior.StopEmittingAndClear);
- isInitialised = true;
- }
- Vector2 temp = Vector2.zero;
- Vector2 corner1 = Vector2.zero;
- Vector2 corner2 = Vector2.zero;
- // iterate through current particles
- int count = pSystem.GetParticles(particles);
- for (int i = 0; i < count; ++i)
- {
- ParticleSystem.Particle particle = particles[i];
- // get particle properties
- #if UNITY_5_5_OR_NEWER
- Vector2 position = (mainModule.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
- #else
- Vector2 position = (pSystem.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
- #endif
- float rotation = -particle.rotation * Mathf.Deg2Rad;
- float rotation90 = rotation + Mathf.PI / 2;
- Color32 color = particle.GetCurrentColor(pSystem);
- float size = particle.GetCurrentSize(pSystem) * 0.5f;
- // apply scale
- #if UNITY_5_5_OR_NEWER
- if (mainModule.scalingMode == ParticleSystemScalingMode.Shape)
- position /= canvas.scaleFactor;
- #else
- if (pSystem.scalingMode == ParticleSystemScalingMode.Shape)
- position /= canvas.scaleFactor;
- #endif
- // apply texture sheet animation
- Vector4 particleUV = imageUV;
- if (textureSheetAnimation.enabled)
- {
- #if UNITY_5_5_OR_NEWER
- float frameProgress = 1 - (particle.remainingLifetime / particle.startLifetime);
- if (textureSheetAnimation.frameOverTime.curveMin != null)
- {
- frameProgress = textureSheetAnimation.frameOverTime.curveMin.Evaluate(1 - (particle.remainingLifetime / particle.startLifetime));
- }
- else if (textureSheetAnimation.frameOverTime.curve != null)
- {
- frameProgress = textureSheetAnimation.frameOverTime.curve.Evaluate(1 - (particle.remainingLifetime / particle.startLifetime));
- }
- else if (textureSheetAnimation.frameOverTime.constant > 0)
- {
- frameProgress = textureSheetAnimation.frameOverTime.constant - (particle.remainingLifetime / particle.startLifetime);
- }
- #else
- float frameProgress = 1 - (particle.lifetime / particle.startLifetime);
- #endif
- frameProgress = Mathf.Repeat(frameProgress * textureSheetAnimation.cycleCount, 1);
- int frame = 0;
- switch (textureSheetAnimation.animation)
- {
- case ParticleSystemAnimationType.WholeSheet:
- frame = Mathf.FloorToInt(frameProgress * textureSheetAnimationFrames);
- break;
- case ParticleSystemAnimationType.SingleRow:
- frame = Mathf.FloorToInt(frameProgress * textureSheetAnimation.numTilesX);
- int row = textureSheetAnimation.rowIndex;
- // if (textureSheetAnimation.useRandomRow) { // FIXME - is this handled internally by rowIndex?
- // row = Random.Range(0, textureSheetAnimation.numTilesY, using: particle.randomSeed);
- // }
- frame += row * textureSheetAnimation.numTilesX;
- break;
- }
- frame %= textureSheetAnimationFrames;
- particleUV.x = (frame % textureSheetAnimation.numTilesX) * textureSheetAnimationFrameSize.x;
- particleUV.y = 1.0f - Mathf.FloorToInt(frame / textureSheetAnimation.numTilesX) * textureSheetAnimationFrameSize.y;
- particleUV.z = particleUV.x + textureSheetAnimationFrameSize.x;
- particleUV.w = particleUV.y + textureSheetAnimationFrameSize.y;
- }
- temp.x = particleUV.x;
- temp.y = particleUV.y;
- _quad[0] = UIVertex.simpleVert;
- _quad[0].color = color;
- _quad[0].uv0 = temp;
- temp.x = particleUV.x;
- temp.y = particleUV.w;
- _quad[1] = UIVertex.simpleVert;
- _quad[1].color = color;
- _quad[1].uv0 = temp;
- temp.x = particleUV.z;
- temp.y = particleUV.w;
- _quad[2] = UIVertex.simpleVert;
- _quad[2].color = color;
- _quad[2].uv0 = temp;
- temp.x = particleUV.z;
- temp.y = particleUV.y;
- _quad[3] = UIVertex.simpleVert;
- _quad[3].color = color;
- _quad[3].uv0 = temp;
- if (rotation == 0)
- {
- // no rotation
- corner1.x = position.x - size;
- corner1.y = position.y - size;
- corner2.x = position.x + size;
- corner2.y = position.y + size;
- temp.x = corner1.x;
- temp.y = corner1.y;
- _quad[0].position = temp;
- temp.x = corner1.x;
- temp.y = corner2.y;
- _quad[1].position = temp;
- temp.x = corner2.x;
- temp.y = corner2.y;
- _quad[2].position = temp;
- temp.x = corner2.x;
- temp.y = corner1.y;
- _quad[3].position = temp;
- }
- else
- {
- if (use3dRotation)
- {
- // get particle properties
- #if UNITY_5_5_OR_NEWER
- Vector3 pos3d = (mainModule.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
- #else
- Vector3 pos3d = (pSystem.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
- #endif
- // apply scale
- #if UNITY_5_5_OR_NEWER
- if (mainModule.scalingMode == ParticleSystemScalingMode.Shape)
- position /= canvas.scaleFactor;
- #else
- if (pSystem.scalingMode == ParticleSystemScalingMode.Shape)
- position /= canvas.scaleFactor;
- #endif
- Vector3[] verts = new Vector3[4]
- {
- new Vector3(-size, -size, 0),
- new Vector3(-size, size, 0),
- new Vector3(size, size, 0),
- new Vector3(size, -size, 0)
- };
- Quaternion particleRotation = Quaternion.Euler(particle.rotation3D);
- _quad[0].position = pos3d + particleRotation * verts[0];
- _quad[1].position = pos3d + particleRotation * verts[1];
- _quad[2].position = pos3d + particleRotation * verts[2];
- _quad[3].position = pos3d + particleRotation * verts[3];
- }
- else
- {
- // apply rotation
- Vector2 right = new Vector2(Mathf.Cos(rotation), Mathf.Sin(rotation)) * size;
- Vector2 up = new Vector2(Mathf.Cos(rotation90), Mathf.Sin(rotation90)) * size;
- _quad[0].position = position - right - up;
- _quad[1].position = position - right + up;
- _quad[2].position = position + right + up;
- _quad[3].position = position + right - up;
- }
- }
- vh.AddUIVertexQuad(_quad);
- }
- }
- private void Update()
- {
- if (!fixedTime && Application.isPlaying)
- {
- pSystem.Simulate(Time.unscaledDeltaTime, false, false, true);
- SetAllDirty();
- if ((currentMaterial != null && currentTexture != currentMaterial.mainTexture) ||
- (material != null && currentMaterial != null && material.shader != currentMaterial.shader))
- {
- pSystem = null;
- Initialize();
- }
- }
- }
- private void LateUpdate()
- {
- if (!Application.isPlaying)
- {
- SetAllDirty();
- }
- else
- {
- if (fixedTime)
- {
- pSystem.Simulate(Time.unscaledDeltaTime, false, false, true);
- SetAllDirty();
- if ((currentMaterial != null && currentTexture != currentMaterial.mainTexture) ||
- (material != null && currentMaterial != null && material.shader != currentMaterial.shader))
- {
- pSystem = null;
- Initialize();
- }
- }
- }
- if (material == currentMaterial)
- return;
- pSystem = null;
- Initialize();
- }
- protected override void OnDestroy()
- {
- currentMaterial = null;
- currentTexture = null;
- }
- public void StartParticleEmission()
- {
- pSystem.Play();
- }
- public void StopParticleEmission()
- {
- pSystem.Stop(false, ParticleSystemStopBehavior.StopEmittingAndClear);
- }
- public void PauseParticleEmission()
- {
- pSystem.Stop(false, ParticleSystemStopBehavior.StopEmitting);
- }
- }
- #endif
- }
|