优化hierarchyab和consolemethod,然后是粒子追踪
Signed-off-by: TRADER_FOER <lhf190@outlook.com>
This commit is contained in:
@@ -3,6 +3,7 @@ namespace Dreamteck.Splines
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Profiling;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
[AddComponentMenu("Dreamteck/Splines/Users/Particle Controller")]
|
||||
@@ -21,10 +22,11 @@ namespace Dreamteck.Splines
|
||||
[SerializeField]
|
||||
[HideInInspector]
|
||||
private ParticleSystem _particleSystem;
|
||||
private ParticleSystemRenderer _renderer;
|
||||
public enum EmitPoint { Beginning, Ending, Random, Ordered }
|
||||
public enum MotionType { None, UseParticleSystem, FollowForward, FollowBackward, ByNormal, ByNormalRandomized }
|
||||
public enum Wrap { Default, Loop }
|
||||
private ParticleSystemRenderer _renderer;
|
||||
public enum EmitPoint { Beginning, Ending, Random, Ordered }
|
||||
public enum MotionType { None, UseParticleSystem, FollowForward, FollowBackward, ByNormal, ByNormalRandomized }
|
||||
public enum Wrap { Default, Loop }
|
||||
public enum PathNodeSizeMode { LegacyOffset, ApplyPathNodeSize }
|
||||
|
||||
public bool is3D;
|
||||
public float width = 10f;
|
||||
@@ -50,8 +52,10 @@ namespace Dreamteck.Splines
|
||||
public Wrap wrapMode = Wrap.Default;
|
||||
[HideInInspector]
|
||||
public float minCycles = 1f;
|
||||
[HideInInspector]
|
||||
public float maxCycles = 1f;
|
||||
[HideInInspector]
|
||||
public float maxCycles = 1f;
|
||||
[HideInInspector]
|
||||
public PathNodeSizeMode pathNodeSizeMode = PathNodeSizeMode.LegacyOffset;
|
||||
|
||||
private Dictionary<uint, Particle> _particleDataMap = new Dictionary<uint, Particle>();
|
||||
private ParticleSystem.Particle[] _particles = new ParticleSystem.Particle[0];
|
||||
@@ -59,72 +63,80 @@ namespace Dreamteck.Splines
|
||||
//private Particle[] _controllers = new Particle[0];
|
||||
private int _particleCount = 0;
|
||||
private int _birthIndex = 0;
|
||||
private int _particleDataFrame = 0;
|
||||
private List<Vector4> _customParticleData = new List<Vector4>();
|
||||
private readonly List<uint> _keysToRemove = new List<uint>();
|
||||
private readonly Stack<Particle> _particleDataPool = new Stack<Particle>();
|
||||
private static readonly ProfilerMarker ParticleControllerLateRunMarker = new ProfilerMarker("ParticleController.LateRun");
|
||||
|
||||
protected override void LateRun()
|
||||
{
|
||||
if (_particleSystem == null) return;
|
||||
if (pauseWhenNotVisible)
|
||||
using (ParticleControllerLateRunMarker.Auto())
|
||||
{
|
||||
if (_renderer == null)
|
||||
if (pauseWhenNotVisible)
|
||||
{
|
||||
_renderer = _particleSystem.GetComponent<ParticleSystemRenderer>();
|
||||
if (_renderer == null)
|
||||
{
|
||||
_renderer = _particleSystem.GetComponent<ParticleSystemRenderer>();
|
||||
}
|
||||
if (!_renderer.isVisible) return;
|
||||
}
|
||||
if (!_renderer.isVisible) return;
|
||||
|
||||
int maxParticles = _particleSystem.main.maxParticles;
|
||||
|
||||
if (_particles.Length != maxParticles)
|
||||
{
|
||||
_particles = new ParticleSystem.Particle[maxParticles];
|
||||
if (maxParticles > _particleDataMap.Count)
|
||||
{
|
||||
_particleDataMap = new Dictionary<uint, Particle>(maxParticles);
|
||||
}
|
||||
}
|
||||
|
||||
_particleCount = _particleSystem.GetParticles(_particles);
|
||||
_particleSystem.GetCustomParticleData(_customParticleData, ParticleSystemCustomData.Custom1);
|
||||
|
||||
_particleDataFrame++;
|
||||
bool isLocal = _particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.Local;
|
||||
Transform particleSystemTransform = _particleSystem.transform;
|
||||
|
||||
for (int i = 0; i < _particleCount; i++)
|
||||
{
|
||||
uint seed = _particles[i].randomSeed; // 获取粒子的唯一ID
|
||||
|
||||
if (isLocal) TransformParticle(ref _particles[i], particleSystemTransform);
|
||||
|
||||
// 使用字典来检查粒子是否是新生儿,这是100%可靠的
|
||||
if (!_particleDataMap.TryGetValue(seed, out Particle particleData))
|
||||
{
|
||||
particleData = OnParticleBorn(i, seed);
|
||||
}
|
||||
|
||||
particleData.lastSeenFrame = _particleDataFrame;
|
||||
HandleParticle(i, particleData);
|
||||
|
||||
if (isLocal) InverseTransformParticle(ref _particles[i], particleSystemTransform);
|
||||
}
|
||||
|
||||
// 清理字典中已经死亡的粒子数据,防止内存无限增长
|
||||
if (_particleCount < _particleDataMap.Count)
|
||||
{
|
||||
_keysToRemove.Clear();
|
||||
foreach (var pair in _particleDataMap)
|
||||
{
|
||||
if (pair.Value.lastSeenFrame != _particleDataFrame) _keysToRemove.Add(pair.Key);
|
||||
}
|
||||
foreach (var key in _keysToRemove)
|
||||
{
|
||||
_particleDataPool.Push(_particleDataMap[key]);
|
||||
_particleDataMap.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
_particleSystem.SetCustomParticleData(_customParticleData, ParticleSystemCustomData.Custom1);
|
||||
_particleSystem.SetParticles(_particles, _particleCount);
|
||||
}
|
||||
|
||||
int maxParticles = _particleSystem.main.maxParticles;
|
||||
|
||||
if (_particles.Length != maxParticles)
|
||||
{
|
||||
_particles = new ParticleSystem.Particle[maxParticles];
|
||||
if (maxParticles > _particleDataMap.Count)
|
||||
{
|
||||
_particleDataMap = new Dictionary<uint, Particle>(maxParticles);
|
||||
}
|
||||
}
|
||||
|
||||
_particleCount = _particleSystem.GetParticles(_particles);
|
||||
_particleSystem.GetCustomParticleData(_customParticleData, ParticleSystemCustomData.Custom1);
|
||||
|
||||
HashSet<uint> activeSeeds = new HashSet<uint>();
|
||||
bool isLocal = _particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.Local;
|
||||
Transform particleSystemTransform = _particleSystem.transform;
|
||||
|
||||
for (int i = 0; i < _particleCount; i++)
|
||||
{
|
||||
uint seed = _particles[i].randomSeed; // 获取粒子的唯一ID
|
||||
activeSeeds.Add(seed); // 记录存活的粒子
|
||||
|
||||
if (isLocal) TransformParticle(ref _particles[i], particleSystemTransform);
|
||||
|
||||
// 使用字典来检查粒子是否是新生儿,这是100%可靠的
|
||||
if (!_particleDataMap.ContainsKey(seed))
|
||||
{
|
||||
OnParticleBorn(i, seed);
|
||||
}
|
||||
|
||||
HandleParticle(i, seed);
|
||||
|
||||
if (isLocal) InverseTransformParticle(ref _particles[i], particleSystemTransform);
|
||||
}
|
||||
|
||||
// 清理字典中已经死亡的粒子数据,防止内存无限增长
|
||||
if (activeSeeds.Count < _particleDataMap.Count)
|
||||
{
|
||||
List<uint> keysToRemove = new List<uint>();
|
||||
foreach (var key in _particleDataMap.Keys)
|
||||
{
|
||||
if (!activeSeeds.Contains(key)) keysToRemove.Add(key);
|
||||
}
|
||||
foreach (var key in keysToRemove)
|
||||
{
|
||||
_particleDataMap.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
_particleSystem.SetCustomParticleData(_customParticleData, ParticleSystemCustomData.Custom1);
|
||||
_particleSystem.SetParticles(_particles, _particleCount);
|
||||
}
|
||||
|
||||
void TransformParticle(ref ParticleSystem.Particle particle, Transform trs)
|
||||
@@ -152,23 +164,21 @@ namespace Dreamteck.Splines
|
||||
if (_particleSystem == null) _particleSystem = GetComponent<ParticleSystem>();
|
||||
}
|
||||
|
||||
void HandleParticle(int index, uint seed)
|
||||
void HandleParticle(int index, Particle particleData)
|
||||
{
|
||||
if (!_particleDataMap.TryGetValue(seed, out Particle particleData)) return; // 安全检查
|
||||
|
||||
float lifePercent = _particles[index].remainingLifetime / _particles[index].startLifetime;
|
||||
if (motionType == MotionType.FollowBackward || motionType == MotionType.FollowForward || motionType == MotionType.None)
|
||||
{
|
||||
Evaluate(particleData.GetSplinePercent(wrapMode, _particles[index], motionType), ref evalResult);
|
||||
Vector3 resultRight = evalResult.right;
|
||||
if (!is3D)
|
||||
{
|
||||
_particles[index].position = evalResult.position + extendDirection * particleData.initialOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
_particles[index].position = evalResult.position + particleData.threeDOffset;
|
||||
}
|
||||
Evaluate(particleData.GetSplinePercent(wrapMode, _particles[index], motionType), ref evalResult);
|
||||
if (!is3D)
|
||||
{
|
||||
Vector3 initialOffset = extendDirection * particleData.initialOffset;
|
||||
_particles[index].position = evalResult.position + GetInitialOffset(evalResult, initialOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
_particles[index].position = evalResult.position + GetInitialOffset(evalResult, particleData.threeDOffset);
|
||||
}
|
||||
|
||||
if (apply3DRotation)
|
||||
{
|
||||
@@ -189,16 +199,37 @@ namespace Dreamteck.Splines
|
||||
finalOffset += particleData.startOffset;
|
||||
}
|
||||
}
|
||||
_particles[index].position += resultRight * (finalOffset.x * evalResult.size)
|
||||
+ evalResult.up * (finalOffset.y * evalResult.size);
|
||||
if (finalOffset != Vector2.zero)
|
||||
{
|
||||
_particles[index].position += GetSamplePlaneOffset(evalResult, finalOffset);
|
||||
}
|
||||
_particles[index].velocity = evalResult.forward;
|
||||
_particles[index].startColor = particleData.startColor * evalResult.color;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnParticleBorn(int index, uint seed)
|
||||
private static Vector3 GetSampleSpaceOffset(SplineSample sample, Vector3 offset)
|
||||
{
|
||||
return sample.right * (offset.x * sample.size)
|
||||
+ sample.up * (offset.y * sample.size)
|
||||
+ sample.forward * (offset.z * sample.size);
|
||||
}
|
||||
|
||||
private Vector3 GetInitialOffset(SplineSample sample, Vector3 offset)
|
||||
{
|
||||
return pathNodeSizeMode == PathNodeSizeMode.ApplyPathNodeSize
|
||||
? GetSampleSpaceOffset(sample, offset)
|
||||
: offset;
|
||||
}
|
||||
|
||||
private static Vector3 GetSamplePlaneOffset(SplineSample sample, Vector2 offset)
|
||||
{
|
||||
Particle newParticleData = new Particle();
|
||||
return sample.right * (offset.x * sample.size) + sample.up * (offset.y * sample.size);
|
||||
}
|
||||
|
||||
private Particle OnParticleBorn(int index, uint seed)
|
||||
{
|
||||
Particle newParticleData = _particleDataPool.Count > 0 ? _particleDataPool.Pop() : new Particle();
|
||||
|
||||
Vector4 custom = _customParticleData[index];
|
||||
custom.w = 1;
|
||||
@@ -234,11 +265,13 @@ namespace Dreamteck.Splines
|
||||
if (!is3D)
|
||||
{
|
||||
newParticleData.initialOffset = Random.Range(-width, width);
|
||||
newParticleData.threeDOffset = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
newParticleData.initialOffset = 0f;
|
||||
newParticleData.threeDOffset = new Vector3(
|
||||
Random.Range(-width, width) * extendDirection.x,
|
||||
Random.Range(-width, width) * extendDirection.x,
|
||||
Random.Range(-width, width) * extendDirection.y,
|
||||
Random.Range(-width, width) * extendDirection.z);
|
||||
}
|
||||
@@ -249,10 +282,8 @@ namespace Dreamteck.Splines
|
||||
|
||||
if (!(motionType == MotionType.FollowForward || motionType == MotionType.FollowBackward))
|
||||
{
|
||||
Vector3 right = Vector3.Cross(evalResult.forward, evalResult.up);
|
||||
_particles[index].position = evalResult.position +
|
||||
right * newParticleData.startOffset.x * evalResult.size * scale.x +
|
||||
evalResult.up * newParticleData.startOffset.y * evalResult.size * scale.y;
|
||||
Vector2 scaledStartOffset = new Vector2(newParticleData.startOffset.x * scale.x, newParticleData.startOffset.y * scale.y);
|
||||
_particles[index].position = evalResult.position + GetSamplePlaneOffset(evalResult, scaledStartOffset);
|
||||
}
|
||||
|
||||
float forceX = _particleSystem.forceOverLifetime.x.constantMax;
|
||||
@@ -284,6 +315,7 @@ namespace Dreamteck.Splines
|
||||
_particles[index].velocity = normal * startSpeed + new Vector3(forceX, forceY, forceZ) * time;
|
||||
}
|
||||
//HandleParticle(index);
|
||||
return newParticleData;
|
||||
}
|
||||
|
||||
public class Particle
|
||||
@@ -295,6 +327,7 @@ namespace Dreamteck.Splines
|
||||
internal float cycleSpeed = 0f;
|
||||
internal Color startColor = Color.white;
|
||||
internal double startPercent = 0.0;
|
||||
internal int lastSeenFrame = 0;
|
||||
|
||||
internal double GetSplinePercent(Wrap wrap, ParticleSystem.Particle particle, MotionType motionType)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user