using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; namespace AmplifyMotion { internal class ParticleState : MotionState { public class Particle { public int refCount; public Matrix4x4 prevLocalToWorld; public Matrix4x4 currLocalToWorld; } public ParticleSystem m_particleSystem; public ParticleSystemRenderer m_renderer; private Mesh m_mesh; private ParticleSystem.Particle[] m_particles; private Dictionary m_particleDict; private List m_listToRemove; private Stack m_particleStack; private int m_capacity; private Matrix4x4 m_localToWorld; private AnimationCurve m_curveLifeTimeSize; private AnimationCurve m_curveSpeedSize; private float m_rangeMinSpeedSize; private float m_rangeMaxSpeedSize; private MaterialDesc[] m_sharedMaterials; public bool m_moved; private bool m_wasVisible; public ParticleState(AmplifyMotionCamera owner, AmplifyMotionObjectBase obj) : base(owner, obj) { m_particleSystem = m_obj.GetComponent(); m_renderer = m_particleSystem.GetComponent().GetComponent(); } private Mesh CreateQuadMesh() { Mesh mesh = new Mesh(); Vector3[] vertices = new Vector3[4] { new Vector3(-0.5f, -0.5f, 0f), new Vector3(0.5f, -0.5f, 0f), new Vector3(0.5f, 0.5f, 0f), new Vector3(-0.5f, 0.5f, 0f) }; int[] triangles = new int[6] { 0, 1, 2, 2, 3, 0 }; Vector2[] uv = new Vector2[4] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0f, 1f), new Vector2(1f, 1f) }; mesh.vertices = vertices; mesh.uv = uv; mesh.triangles = triangles; return mesh; } internal override void Initialize() { if (m_renderer == null) { Debug.LogError("[AmplifyMotion] Invalid Particle Mesh in object " + m_obj.name); m_error = true; return; } base.Initialize(); if (m_renderer.renderMode == ParticleSystemRenderMode.Mesh) { m_mesh = m_renderer.mesh; } else { m_mesh = CreateQuadMesh(); } m_sharedMaterials = ProcessSharedMaterials(m_renderer.sharedMaterials); m_capacity = m_particleSystem.maxParticles; m_particleDict = new Dictionary(m_capacity); m_particles = new ParticleSystem.Particle[m_capacity]; m_listToRemove = new List(m_capacity); m_particleStack = new Stack(m_capacity); for (int i = 0; i < m_capacity; i++) { m_particleStack.Push(new Particle()); } m_curveLifeTimeSize = null; m_curveSpeedSize = null; m_rangeMinSpeedSize = -1f; m_rangeMaxSpeedSize = -1f; if (m_obj.ParticleSystemDesc.sizeOverLifeTimeActive) { m_curveLifeTimeSize = m_obj.ParticleSystemDesc.curveSizeOverLifeTime; } if (m_obj.ParticleSystemDesc.sizeBySpeedActive) { m_curveSpeedSize = m_obj.ParticleSystemDesc.curveBySpeed; m_rangeMinSpeedSize = m_obj.ParticleSystemDesc.speedRangeMin; m_rangeMaxSpeedSize = m_obj.ParticleSystemDesc.speedRangeMax; } m_wasVisible = false; } private Matrix4x4 buildMatrix4x4(ParticleSystem.Particle particle, float sizeParticle) { return Matrix4x4.TRS(particle.position, Quaternion.AngleAxis(particle.rotation, particle.axisOfRotation), new Vector3(sizeParticle, sizeParticle, sizeParticle)); } private Matrix4x4 buildMatrixBillBoard(ParticleSystem.Particle particle, float sizeParticle) { Quaternion quaternion = Quaternion.AngleAxis(particle.rotation, Vector3.back); Quaternion quaternion2 = Quaternion.AngleAxis(particle.rotation, Vector3.forward); Vector3 axis = new Vector3(180f, m_transform.rotation.y, 0f); Quaternion quaternion3 = Quaternion.AngleAxis(particle.rotation, axis); if (m_renderer.renderMode == ParticleSystemRenderMode.Billboard || m_renderer.renderMode == ParticleSystemRenderMode.Stretch) { return Matrix4x4.TRS(particle.position, m_owner.transform.rotation * quaternion, new Vector3(sizeParticle, sizeParticle, sizeParticle)); } if (m_renderer.renderMode == ParticleSystemRenderMode.HorizontalBillboard) { float num = sizeParticle * 0.71428573f; return Matrix4x4.TRS(particle.position, m_transform.rotation * quaternion2, new Vector3(num, num, num)); } if (m_renderer.renderMode == ParticleSystemRenderMode.VerticalBillboard) { float num2 = sizeParticle * 0.71428573f; return Matrix4x4.TRS(particle.position, m_owner.transform.rotation * quaternion3, new Vector3(num2, num2, num2)); } return Matrix4x4.TRS(particle.position, m_owner.transform.rotation * quaternion, new Vector3(sizeParticle, sizeParticle, sizeParticle)); } private void RemoveDeadParticles() { m_listToRemove.Clear(); Dictionary.Enumerator enumerator = m_particleDict.GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; if (current.Value.refCount <= 0) { m_particleStack.Push(current.Value); if (!m_listToRemove.Contains(current.Key)) { m_listToRemove.Add(current.Key); } } else { current.Value.refCount = 0; } } for (int i = 0; i < m_listToRemove.Count; i++) { m_particleDict.Remove(m_listToRemove[i]); } } internal override void UpdateTransform(CommandBuffer updateCB, bool starting) { if (!m_initialized || m_capacity != m_particleSystem.maxParticles) { Initialize(); return; } if (!starting && m_wasVisible) { Dictionary.Enumerator enumerator = m_particleDict.GetEnumerator(); while (enumerator.MoveNext()) { Particle value = enumerator.Current.Value; value.prevLocalToWorld = value.currLocalToWorld; } } m_moved = true; int particles = m_particleSystem.GetParticles(m_particles); float num = 1f / m_particleSystem.startLifetime; for (int i = 0; i < particles; i++) { uint randomSeed = m_particles[i].randomSeed; float num2 = m_particles[i].size; if (m_curveLifeTimeSize != null) { num2 *= m_curveLifeTimeSize.Evaluate(1f - m_particles[i].remainingLifetime * num); } if (m_curveSpeedSize != null && m_rangeMinSpeedSize > 0f && m_rangeMaxSpeedSize > 0f) { num2 = ((!(m_particles[i].velocity.magnitude > m_rangeMinSpeedSize) || !(m_particles[i].velocity.magnitude < m_rangeMaxSpeedSize)) ? (num2 * m_particles[i].size) : (num2 * m_curveSpeedSize.Evaluate(m_particles[i].velocity.magnitude))); } if (m_renderer.renderMode == ParticleSystemRenderMode.Mesh) { Matrix4x4 matrix4x = buildMatrix4x4(m_particles[i], num2); if (m_particleSystem.simulationSpace == ParticleSystemSimulationSpace.World) { m_localToWorld = matrix4x; } else { m_localToWorld = m_transform.localToWorldMatrix * matrix4x; } } else { if (m_particleSystem.simulationSpace == ParticleSystemSimulationSpace.Local) { m_particles[i].position = m_transform.TransformPoint(m_particles[i].position); } Matrix4x4 localToWorld = buildMatrixBillBoard(m_particles[i], num2); m_localToWorld = localToWorld; } Particle value2; if (!m_particleDict.TryGetValue(randomSeed, out value2) && m_particleStack.Count > 0) { value2 = (m_particleDict[randomSeed] = m_particleStack.Pop()); } if (value2 != null) { value2.refCount = 1; value2.currLocalToWorld = m_localToWorld; } } if (starting || !m_wasVisible) { Dictionary.Enumerator enumerator2 = m_particleDict.GetEnumerator(); while (enumerator2.MoveNext()) { Particle value3 = enumerator2.Current.Value; value3.prevLocalToWorld = value3.currLocalToWorld; } } RemoveDeadParticles(); m_wasVisible = m_renderer.isVisible; } internal override void RenderVectors(Camera camera, CommandBuffer renderCB, float scale, Quality quality) { if (!m_initialized || m_error || !m_renderer.isVisible) { return; } bool flag = ((int)m_owner.Instance.CullingMask & (1 << m_obj.gameObject.layer)) != 0; if (flag && (!flag || !m_moved)) { return; } int num = ((!flag) ? 255 : m_owner.Instance.GenerateObjectId(m_obj.gameObject)); renderCB.SetGlobalFloat("_AM_OBJECT_ID", (float)num * 0.003921569f); renderCB.SetGlobalFloat("_AM_MOTION_SCALE", (!flag) ? 0f : scale); int num2 = ((quality != Quality.Mobile) ? 2 : 0); for (int i = 0; i < m_sharedMaterials.Length; i++) { MaterialDesc materialDesc = m_sharedMaterials[i]; int shaderPass = num2 + (materialDesc.coverage ? 1 : 0); materialDesc.propertyBlock.Clear(); if (materialDesc.coverage) { materialDesc.propertyBlock.SetTexture("_MainTex", materialDesc.material.mainTexture); if (materialDesc.cutoff) { materialDesc.propertyBlock.SetFloat("_Cutoff", materialDesc.material.GetFloat("_Cutoff")); } } Dictionary.Enumerator enumerator = m_particleDict.GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; Matrix4x4 value = m_owner.PrevViewProjMatrixRT * current.Value.prevLocalToWorld; renderCB.SetGlobalMatrix("_AM_MATRIX_PREV_MVP", value); renderCB.DrawMesh(m_mesh, current.Value.currLocalToWorld, m_owner.Instance.SolidVectorsMaterial, i, shaderPass); } } } } }