/// <summary> /// Sets the parent (particle system's) translation, rotation and scale (uniform) /// The module can choose to inherit, use or ignore any of the elements /// </summary> /// <param name="translation">Particle System's translation (from the Transform component)</param> /// <param name="rotation">Particle System's quaternion rotation (from the Transform component)</param> /// <param name="scale">Particle System's uniform scale (from the Transform component)</param> public virtual void SetParentTrs(ref Vector3 translation, ref Quaternion rotation, float scale) { var hasPos = InheritLocation.HasFlag(InheritLocation.Position); var hasRot = InheritLocation.HasFlag(InheritLocation.Rotation); var hasScl = InheritLocation.HasFlag(InheritLocation.Scale); WorldScale = (hasScl) ? ParticleLocator.Scale * scale : ParticleLocator.Scale; WorldRotation = (hasRot) ? ParticleLocator.Rotation * rotation : ParticleLocator.Rotation; var offsetTranslation = ParticleLocator.Translation * WorldScale; WorldRotation.Rotate(ref offsetTranslation); WorldPosition = (hasPos) ? translation + offsetTranslation : offsetTranslation; }
public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity) { if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.Velocity) || !pool.FieldExists(ParticleFields.RandomSeed)) { return; } var posField = pool.GetField(ParticleFields.Position); var velField = pool.GetField(ParticleFields.Velocity); var rndField = pool.GetField(ParticleFields.RandomSeed); var range = (float)(Angle * Math.PI / 180f); var magnitude = WorldScale.X; var i = startIdx; while (i != endIdx) { var particle = pool.FromIndex(i); var randSeed = particle.Get(rndField); var x = (randSeed.GetFloat(RandomOffset.Offset2A + SeedOffset) - 0.5f) * range; var z = (randSeed.GetFloat(RandomOffset.Offset2B + SeedOffset) - 0.5f) * range; var u = (randSeed.GetFloat(RandomOffset.Offset2A + SeedOffset) - 0.5f) * range; var v = (randSeed.GetFloat(RandomOffset.Offset2B + SeedOffset) - 0.5f) * Math.PI; // var particleRandPos = new Vector3(x, 1, z); var xz = (float)Math.Sin(u); var particleRandPos = new Vector3((float)Math.Cos(v) * xz, (float)Math.Sqrt(1 - u * u), (float)Math.Sin(v) * xz); particleRandPos.Normalize(); particleRandPos *= magnitude; WorldRotation.Rotate(ref particleRandPos); (*((Vector3 *)particle[posField])) = particleRandPos + WorldPosition; (*((Vector3 *)particle[velField])) = particleRandPos * Strength; i = (i + 1) % maxCapacity; } }
public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity) { if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.RandomSeed)) { return; } var posField = pool.GetField(ParticleFields.Position); var rndField = pool.GetField(ParticleFields.RandomSeed); var leftCorner = PositionMin * WorldScale; var xAxis = new Vector3(PositionMax.X * WorldScale.X - leftCorner.X, 0, 0); var yAxis = new Vector3(0, PositionMax.Y * WorldScale.Y - leftCorner.Y, 0); var zAxis = new Vector3(0, 0, PositionMax.Z * WorldScale.Z - leftCorner.Z); if (!WorldRotation.IsIdentity) { WorldRotation.Rotate(ref leftCorner); WorldRotation.Rotate(ref xAxis); WorldRotation.Rotate(ref yAxis); WorldRotation.Rotate(ref zAxis); } leftCorner += WorldPosition; var i = startIdx; while (i != endIdx) { var particle = pool.FromIndex(i); var randSeed = particle.Get(rndField); var particleRandPos = leftCorner; particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset); particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset); particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset); (*((Vector3 *)particle[posField])) = particleRandPos; i = (i + 1) % maxCapacity; } }
/// <inheritdoc /> public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity) { if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.RandomSeed)) { return; } // Collect the total number of living particles in the parent pool which have a Position field var parentPool = Parent?.Pool; var parentParticlesCount = parentPool?.LivingParticles ?? 0; var posFieldParent = parentPool?.GetField(ParticleFields.Position) ?? ParticleFieldAccessor <Vector3> .Invalid(); if (!posFieldParent.IsValid()) { parentParticlesCount = 0; } var oldPosFieldParent = parentPool?.GetField(ParticleFields.OldPosition) ?? ParticleFieldAccessor <Vector3> .Invalid(); var spawnControlField = GetSpawnControlField(); var posField = pool.GetField(ParticleFields.Position); var rndField = pool.GetField(ParticleFields.RandomSeed); var oldField = pool.GetField(ParticleFields.OldPosition); var leftCorner = PositionMin * WorldScale; var xAxis = new Vector3(PositionMax.X * WorldScale.X - leftCorner.X, 0, 0); var yAxis = new Vector3(0, PositionMax.Y * WorldScale.Y - leftCorner.Y, 0); var zAxis = new Vector3(0, 0, PositionMax.Z * WorldScale.Z - leftCorner.Z); if (!WorldRotation.IsIdentity) { WorldRotation.Rotate(ref leftCorner); WorldRotation.Rotate(ref xAxis); WorldRotation.Rotate(ref yAxis); WorldRotation.Rotate(ref zAxis); } // Already inheriting from parent if (parentParticlesCount == 0) { leftCorner += WorldPosition; } var sequentialParentIndex = 0; var sequentialParentParticles = 0; var parentIndex = 0; // Interpolation - if parent particle has OldPosition field var stepF = 0f; var stepTotal = 0f; var positionDistance = new Vector3(0, 0, 0); var i = startIdx; while (i != endIdx) { var particle = pool.FromIndex(i); var randSeed = particle.Get(rndField); var particleRandPos = leftCorner; particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset); particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset); particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset); if (parentParticlesCount > 0) { var parentParticlePosition = new Vector3(0, 0, 0); // Spawn is fixed - parent particles have spawned a very specific number of children each if (spawnControlField.IsValid()) { // Interpolation - if parent particle has OldPosition field while (sequentialParentParticles == 0) { // Early out - no more fixed number children. Rest of the particles (if any) are skipped intentionally if (sequentialParentIndex >= parentParticlesCount) { return; } parentIndex = sequentialParentIndex; var tempParentParticle = parentPool.FromIndex(parentIndex); sequentialParentIndex++; var childrenAttribute = (*((ParticleChildrenAttribute *)tempParentParticle[spawnControlField])); sequentialParentParticles = (int)childrenAttribute.ParticlesToEmit; if (oldPosFieldParent.IsValid()) { stepF = (sequentialParentParticles > 0) ? (1f / (float)sequentialParentParticles) : 1; stepTotal = 0f; positionDistance = ((*((Vector3 *)tempParentParticle[oldPosFieldParent])) - (*((Vector3 *)tempParentParticle[posFieldParent]))); } } sequentialParentParticles--; var parentParticle = parentPool.FromIndex(parentIndex); parentParticlePosition = (*((Vector3 *)parentParticle[posFieldParent])); parentParticlePosition += positionDistance * stepTotal; stepTotal += stepF; } // Spawn is not fixed - pick a parent at random else { parentIndex = (int)(parentParticlesCount * randSeed.GetFloat(RandomOffset.Offset1A + ParentSeedOffset)); var parentParticle = parentPool.FromIndex(parentIndex); parentParticlePosition = (*((Vector3 *)parentParticle[posFieldParent])); } // Convert from Local -> World space if needed if (Parent.SimulationSpace == EmitterSimulationSpace.Local) { WorldRotation.Rotate(ref parentParticlePosition); parentParticlePosition *= WorldScale.X; parentParticlePosition += WorldPosition; } particleRandPos += parentParticlePosition; } (*((Vector3 *)particle[posField])) = particleRandPos; if (oldField.IsValid()) { (*((Vector3 *)particle[oldField])) = particleRandPos; } i = (i + 1) % maxCapacity; } }
/// <inheritdoc /> public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity) { if (!pool.FieldExists(ParticleFields.Velocity) || !pool.FieldExists(ParticleFields.RandomSeed)) { return; } // Collect the total number of living particles in the parent pool which have a Velocity field var parentPool = Parent?.Pool; var parentParticlesCount = parentPool?.LivingParticles ?? 0; var velFieldParent = parentPool?.GetField(ParticleFields.Velocity) ?? ParticleFieldAccessor <Vector3> .Invalid(); if (!velFieldParent.IsValid()) { parentParticlesCount = 0; } var spawnControlField = GetSpawnControlField(); var velField = pool.GetField(ParticleFields.Velocity); var rndField = pool.GetField(ParticleFields.RandomSeed); var leftCorner = VelocityMin * WorldScale; var xAxis = new Vector3(VelocityMax.X * WorldScale.X - leftCorner.X, 0, 0); var yAxis = new Vector3(0, VelocityMax.Y * WorldScale.Y - leftCorner.Y, 0); var zAxis = new Vector3(0, 0, VelocityMax.Z * WorldScale.Z - leftCorner.Z); if (!WorldRotation.IsIdentity) { WorldRotation.Rotate(ref leftCorner); WorldRotation.Rotate(ref xAxis); WorldRotation.Rotate(ref yAxis); WorldRotation.Rotate(ref zAxis); } var sequentialParentIndex = 0; var sequentialParentParticles = 0; var parentIndex = 0; var i = startIdx; while (i != endIdx) { var particle = pool.FromIndex(i); var randSeed = particle.Get(rndField); var particleRandVel = leftCorner; particleRandVel += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset); particleRandVel += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset); particleRandVel += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset); if (parentParticlesCount > 0) { var parentParticleVelocity = new Vector3(0, 0, 0); // Spawn is fixed - parent particles have spawned a very specific number of children each if (spawnControlField.IsValid()) { while (sequentialParentParticles == 0) { // Early out - no more fixed number children. Rest of the particles (if any) are skipped intentionally if (sequentialParentIndex >= parentParticlesCount) { return; } parentIndex = sequentialParentIndex; var tempParentParticle = parentPool.FromIndex(parentIndex); sequentialParentIndex++; var childrenAttribute = (*((ParticleChildrenAttribute *)tempParentParticle[spawnControlField])); sequentialParentParticles = (int)childrenAttribute.ParticlesToEmit; } sequentialParentParticles--; var parentParticle = parentPool.FromIndex(parentIndex); parentParticleVelocity = (*((Vector3 *)parentParticle[velFieldParent])); } // Spawn is not fixed - pick a parent at random else { parentIndex = (int)(parentParticlesCount * randSeed.GetFloat(RandomOffset.Offset1A + ParentSeedOffset)); var parentParticle = parentPool.FromIndex(parentIndex); parentParticleVelocity = (*((Vector3 *)parentParticle[velFieldParent])); } // Convert from Local -> World space if needed if (Parent.SimulationSpace == EmitterSimulationSpace.Local) { WorldRotation.Rotate(ref parentParticleVelocity); parentParticleVelocity *= WorldScale.X; } particleRandVel += parentParticleVelocity * ParentVelocityFactor; } (*((Vector3 *)particle[velField])) = particleRandVel; i = (i + 1) % maxCapacity; } }
/// <inheritdoc /> public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity) { if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.RandomSeed)) { return; } var posField = pool.GetField(ParticleFields.Position); var oldField = pool.GetField(ParticleFields.OldPosition); var rndField = pool.GetField(ParticleFields.RandomSeed); var leftCorner = PositionMin * WorldScale; var xAxis = new Vector3(PositionMax.X * WorldScale.X - leftCorner.X, 0, 0); var yAxis = new Vector3(0, PositionMax.Y * WorldScale.Y - leftCorner.Y, 0); var zAxis = new Vector3(0, 0, PositionMax.Z * WorldScale.Z - leftCorner.Z); if (!WorldRotation.IsIdentity) { WorldRotation.Rotate(ref leftCorner); WorldRotation.Rotate(ref xAxis); WorldRotation.Rotate(ref yAxis); WorldRotation.Rotate(ref zAxis); } leftCorner += WorldPosition; var i = startIdx; if (Interpolate) { // Interpolate positions between the old and the new one var positionDistance = (hasBegun) ? oldPosition - WorldPosition : Vector3.Zero; oldPosition = WorldPosition; hasBegun = true; var totalCountLessOne = (startIdx < endIdx) ? (endIdx - startIdx - 1) : (endIdx - startIdx + maxCapacity - 1); var stepF = (totalCountLessOne > 1) ? (1f / totalCountLessOne) : 1f; var step = 0f; while (i != endIdx) { var particle = pool.FromIndex(i); var randSeed = particle.Get(rndField); var particleRandPos = leftCorner; particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset); particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset); particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset); particleRandPos += positionDistance * step; step += stepF; (*((Vector3 *)particle[posField])) = particleRandPos; if (oldField.IsValid()) { (*((Vector3 *)particle[oldField])) = particleRandPos; } i = (i + 1) % maxCapacity; } } else { // Do not interpolate position while (i != endIdx) { var particle = pool.FromIndex(i); var randSeed = particle.Get(rndField); var particleRandPos = leftCorner; particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset); particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset); particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset); (*((Vector3 *)particle[posField])) = particleRandPos; if (oldField.IsValid()) { (*((Vector3 *)particle[oldField])) = particleRandPos; } i = (i + 1) % maxCapacity; } } }
/// <inheritdoc /> public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity) { if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.RandomSeed)) { return; } var posField = pool.GetField(ParticleFields.Position); var rndField = pool.GetField(ParticleFields.RandomSeed); var arcOffset = new Vector3(0, ArcHeight, 0); if (!WorldRotation.IsIdentity) { WorldRotation.Rotate(ref arcOffset); } var leftCorner = PositionMin * WorldScale; var xAxis = new Vector3(PositionMax.X * WorldScale.X - leftCorner.X, 0, 0); var yAxis = new Vector3(0, PositionMax.Y * WorldScale.Y - leftCorner.Y, 0); var zAxis = new Vector3(0, 0, PositionMax.Z * WorldScale.Z - leftCorner.Z); if (!WorldRotation.IsIdentity) { WorldRotation.Rotate(ref leftCorner); WorldRotation.Rotate(ref xAxis); WorldRotation.Rotate(ref yAxis); WorldRotation.Rotate(ref zAxis); } var targetCornerAdd = Target?.WorldMatrix.TranslationVector - WorldPosition ?? FallbackTarget; var totalCountLessOne = (FixedLength > 0) ? (FixedLength - 1) : (startIdx < endIdx) ? (endIdx - startIdx - 1) : (endIdx - startIdx + maxCapacity - 1); var stepF = (totalCountLessOne > 1) ? (1f / totalCountLessOne) : 1f; var step = -stepF; var i = startIdx; while (i != endIdx) { var particle = pool.FromIndex(i); var randSeed = particle.Get(rndField); if (Sequential) { step += stepF; if (FixedLength > 0) { step = (i % FixedLength) * stepF; } } else { step = randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset); } var positionOffsetFactor = (float)Math.Sin(step * Math.PI); var particleRandPos = leftCorner * positionOffsetFactor + targetCornerAdd * step + arcOffset * positionOffsetFactor + WorldPosition; particleRandPos += xAxis * positionOffsetFactor * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset); particleRandPos += yAxis * positionOffsetFactor * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset); particleRandPos += zAxis * positionOffsetFactor * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset); (*((Vector3 *)particle[posField])) = particleRandPos; i = (i + 1) % maxCapacity; } }