Particle controller that applies a vortex force to particles. It computes a cylindrical projection around an axis and accelerates particles tangentially to induce rotation, with configurable center, axis, strength and responsiveness and an option to use local or world space.
using Sandbox;
public class VortexForce() : ParticleController
{
[Property]
public Vector3 VortexCenterOffset { get; set; }
[Property]
public Vector3 Axis { get; set; } = Vector3.Up;
/// <summary>
/// When true the Axis and center offset follow the controller's rotation/position,
/// so the vortex tilts and moves with the emitter. When false they are world-space.
/// </summary>
[Property]
public bool LocalSpace { get; set; } = false;
[Property]
public ParticleFloat Strength { get; set; } = 100f;
[Property]
public ParticleFloat Responsiveness { get; set; } = 1f;
protected override void OnParticleStep(Particle particle, float delta)
{
var vortexCenter = LocalSpace
? WorldTransform.PointToWorld(VortexCenterOffset)
: WorldPosition + VortexCenterOffset;
var axis = LocalSpace ? WorldTransform.NormalToWorld(Axis) : Axis;
var r = particle.Position - vortexCenter;
var rPlane = r - Vector3.Dot(r, axis) / Vector3.Dot(axis, axis) * axis;
if (rPlane.LengthSquared < 0.0001f)
return;
var tangent = Vector3.Cross(axis, rPlane.Normal);
var strength = Strength.Evaluate(delta, 6555f);
var responsiveness = Responsiveness.Evaluate(delta, 6555f);
var currentTangentialSpeed = Vector3.Dot(particle.Velocity, tangent);
var targetDelta = (strength - currentTangentialSpeed) * responsiveness;
particle.Velocity += tangent * targetDelta * delta;
}
}