From 40ff9863122308b038a709dd5dc96cab74cf290d Mon Sep 17 00:00:00 2001 From: dnesov Date: Tue, 15 Oct 2024 22:52:20 +0200 Subject: [PATCH] WIP: Use SoA in ParticleSystem --- TestGame/TestGame.cs | 4 +- Voile/Source/Systems/ParticleSystem.cs | 108 ++++++++++++++----------- 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/TestGame/TestGame.cs b/TestGame/TestGame.cs index 3853b62..f59e82e 100644 --- a/TestGame/TestGame.cs +++ b/TestGame/TestGame.cs @@ -90,9 +90,9 @@ public class TestGame : Game { Renderer.BeginBlended(Voile.Rendering.BlendMode.BlendAlpha); - for (int i = 0; i < emitter.Particles.Length; i++) + for (int i = 0; i < emitter.Settings.MaxParticles; i++) { - var particle = emitter.Particles[i]; + var particle = emitter.GetParticle(i); var color = new Color(particle.ColorArgb); diff --git a/Voile/Source/Systems/ParticleSystem.cs b/Voile/Source/Systems/ParticleSystem.cs index 7688f1b..b0ec2bf 100644 --- a/Voile/Source/Systems/ParticleSystem.cs +++ b/Voile/Source/Systems/ParticleSystem.cs @@ -17,10 +17,8 @@ public struct Particle public Vector2 Velocity { get; set; } public float AngularVelocity { get; set; } public float LifeTime { get; set; } = 1.0f; - public float LifeTimeRemaining { get; set; } public float Scale { get; set; } public float Rotation { get; set; } - public bool Alive { get; set; } = true; } public class ParticleEmitterSettings @@ -96,10 +94,6 @@ public class ParticleEmitterSettingsResourceLoader : ResourceLoader public class ParticleEmitter : IUpdatableSystem { - /// - /// A segment of particles this emitter simulates. - /// - public ReadOnlySpan Particles => _particles.AsSpan(); /// /// Origin position in the world of this emitter. /// @@ -108,7 +102,7 @@ public class ParticleEmitter : IUpdatableSystem /// for this emitter. /// public ParticleEmitterSettings Settings => _settingsResource.Value.Settings; - public int ParticleArrayOffset => _particles.Offset; + public int ArrayOffset => _lifetimes.Offset; /// /// Constructs a new . @@ -116,7 +110,7 @@ public class ParticleEmitter : IUpdatableSystem /// World origin position. /// Emitter settings resource. /// Particle segment that this emitter will simulate. - public ParticleEmitter(Vector2 originPosition, ResourceRef settingsResource, ArraySegment particles) + public ParticleEmitter(Vector2 originPosition, ResourceRef settingsResource, ArraySegment positionsSlice, ArraySegment velocitiesSlice, ArraySegment lifetimesSlice) { _originPosition = originPosition; @@ -124,25 +118,36 @@ public class ParticleEmitter : IUpdatableSystem _maxParticles = _settingsResource.Value.Settings.MaxParticles; _particleIndex = _maxParticles - 1; - _particles = particles; + _positions = positionsSlice; + _velocities = velocitiesSlice; + _lifetimes = lifetimesSlice; _random = new LehmerRandom(); } + public Particle GetParticle(int idx) + { + var t = _lifetimes[idx] / Settings.LifeTime; + return new Particle() + { + Position = _positions[idx], + Velocity = _velocities[idx], + Scale = MathUtils.Lerp(Settings.ScaleEnd, Settings.ScaleBegin, t), + ColorArgb = MathUtils.LerpColor(Settings.ColorEnd, Settings.ColorBegin, t).Argb + }; + } + /// /// Restart this emitter. /// /// New particle segment. - public void Restart(ArraySegment particles) + public void Restart() { - for (int i = 0; i < _particles.Count; i++) + for (int i = 0; i < _lifetimes.Count; i++) { - var particle = _particles[i]; - particle.LifeTimeRemaining = 0.0f; + _lifetimes[i] = 0.0f; } - _particles = particles; - _maxParticles = Settings.MaxParticles; _particleIndex = _maxParticles - 1; } @@ -162,44 +167,40 @@ public class ParticleEmitter : IUpdatableSystem for (int i = 0; i < _maxParticles; i++) { - var particle = _particles[i]; + // var particle = _particles[i]; - particle.LifeTimeRemaining = Math.Clamp(particle.LifeTimeRemaining - (float)deltaTime, 0.0f, particle.LifeTime); + _lifetimes[i] = Math.Max(0.0f, _lifetimes[i] - (float)deltaTime); - var t = particle.LifeTimeRemaining / particle.LifeTime; + var t = _lifetimes[i] / Settings.LifeTime; - particle.Velocity += Settings.Gravity * (float)deltaTime; - particle.Position += particle.Velocity * (float)deltaTime; - particle.Rotation += particle.AngularVelocity * (float)deltaTime; - particle.Scale = MathUtils.Lerp(Settings.ScaleEnd, Settings.ScaleBegin, t); + _velocities[i] += Settings.Gravity * (float)deltaTime; + _positions[i] += _velocities[i] * (float)deltaTime; + // particle.Rotation += particle.AngularVelocity * (float)deltaTime; + // particle.Scale = MathUtils.Lerp(Settings.ScaleEnd, Settings.ScaleBegin, t); var color = MathUtils.LerpColor(Settings.ColorEnd, Settings.ColorBegin, t); - particle.ColorArgb = color.Argb; + // particle.ColorArgb = color.Argb; - particle.Velocity -= particle.Velocity * Settings.Damping * (float)deltaTime; - - _particles[i] = particle; + _velocities[i] -= _velocities[i] * Settings.Damping * (float)deltaTime; } } private void Emit() { - Particle particle = _particles[_particleIndex]; - if (!(particle.LifeTimeRemaining <= 0)) return; + // Particle particle = _particles[_particleIndex]; - // particle.Alive = true; - particle.Position = GetEmitPosition(); - particle.Velocity = Settings.Direction * Settings.LinearVelocity; + if (_lifetimes[_particleIndex] > 0) return; - particle.Velocity += Vector2.One * Settings.LinearVelocityRandom * ((float)_random.NextDouble() - 0.5f); + _positions[_particleIndex] = GetEmitPosition(); + _velocities[_particleIndex] = Settings.Direction * Settings.LinearVelocity; - particle.AngularVelocity = Settings.AngularVelocity; - particle.AngularVelocity += 1f * Settings.AngularVelocityRandom * ((float)_random.NextDouble() - 0.5f); + _velocities[_particleIndex] += Vector2.One * Settings.LinearVelocityRandom * ((float)_random.NextDouble() - 0.5f); - particle.LifeTime = Settings.LifeTime; - particle.LifeTimeRemaining = particle.LifeTime; + // particle.AngularVelocity = Settings.AngularVelocity; + // particle.AngularVelocity += 1f * Settings.AngularVelocityRandom * ((float)_random.NextDouble() - 0.5f); + + _lifetimes[_particleIndex] = Settings.LifeTime; - _particles[_particleIndex] = particle; _particleIndex = --_particleIndex <= 0 ? _maxParticles - 1 : --_particleIndex; } @@ -221,7 +222,8 @@ public class ParticleEmitter : IUpdatableSystem private int _maxParticles; private int _particleIndex; private Vector2 _originPosition = Vector2.Zero; - private ArraySegment _particles; + private ArraySegment _positions, _velocities; + private ArraySegment _lifetimes; private ResourceRef _settingsResource; } @@ -246,7 +248,10 @@ public class ParticleSystem : IUpdatableSystem, IDisposable public ParticleSystem() { _particleIndex = ParticleLimit - 1; - _particles = new Particle[ParticleLimit]; + + _particlePositions = new Vector2[ParticleLimit]; + _particleVelocities = new Vector2[ParticleLimit]; + _particleLifetimes = new float[ParticleLimit]; } /// @@ -265,15 +270,16 @@ public class ParticleSystem : IUpdatableSystem, IDisposable return -1; } - var particles = new ArraySegment(_particles, _emitterSliceOffset, settings.MaxParticles); + var positionsSlice = new ArraySegment(_particlePositions, _emitterSliceOffset, settings.MaxParticles); + var velocitiesSlice = new ArraySegment(_particleVelocities, _emitterSliceOffset, settings.MaxParticles); + var lifetimesSlice = new ArraySegment(_particleLifetimes, _emitterSliceOffset, settings.MaxParticles); - for (int i = 0; i < particles.Count; i++) + for (int i = 0; i < lifetimesSlice.Count; i++) { - var particle = particles[i]; - particle.LifeTime = settings.LifeTime; + lifetimesSlice[i] = settings.LifeTime; } - var emitter = new ParticleEmitter(originPosition, settingsResource, particles); + var emitter = new ParticleEmitter(originPosition, settingsResource, positionsSlice, velocitiesSlice, lifetimesSlice); _emitters.Add(emitter); _emitterSliceOffset += settings.MaxParticles; @@ -294,9 +300,8 @@ public class ParticleSystem : IUpdatableSystem, IDisposable } var emitter = _emitters[id]; - var particles = new ArraySegment(_particles, emitter.ParticleArrayOffset, emitter.Settings.MaxParticles); - emitter.Restart(particles); + emitter.Restart(); } /// @@ -316,8 +321,15 @@ public class ParticleSystem : IUpdatableSystem, IDisposable CleanupParticles(); } - private void CleanupParticles() => Array.Clear(_particles); - private Particle[] _particles; + private void CleanupParticles() + { + Array.Clear(_particlePositions); + Array.Clear(_particleVelocities); + Array.Clear(_particleLifetimes); + } + // private Particle[] _particles; + private Vector2[] _particlePositions, _particleVelocities; + private float[] _particleLifetimes; private int _particleIndex; private int _emitterSliceOffset;