295 lines
9.2 KiB
C#
295 lines
9.2 KiB
C#
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<uint, Particle> m_particleDict;
|
|
|
|
private List<uint> m_listToRemove;
|
|
|
|
private Stack<Particle> 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<ParticleSystem>();
|
|
m_renderer = m_particleSystem.GetComponent<Renderer>().GetComponent<ParticleSystemRenderer>();
|
|
}
|
|
|
|
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<uint, Particle>(m_capacity);
|
|
m_particles = new ParticleSystem.Particle[m_capacity];
|
|
m_listToRemove = new List<uint>(m_capacity);
|
|
m_particleStack = new Stack<Particle>(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<uint, Particle>.Enumerator enumerator = m_particleDict.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
KeyValuePair<uint, Particle> 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<uint, Particle>.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<uint, Particle>.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<uint, Particle>.Enumerator enumerator = m_particleDict.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
KeyValuePair<uint, Particle> 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|