private void Ring3D(int s, int e) { int count = 50; float pointScale = 0.2f; Vector3 initialRingRotation = new Vector3( (float)Math.PI / 4, (float)Math.PI / 3, 0 ); Vector3 ringRotationSpeed = new Vector3( 0.01f, 0.02f, 0.03f ); Vector3 ringRotation = Vector3.Zero; Func <float, int, Vector3> ringPattern = (float t, int i) => Patterns.Circle3D(Vectors.Centre3D, 200, initialRingRotation, 2 * (float)Math.PI / count, t)(i); SpriteSet ring = layer.CreateSpriteSet( Sprites.Particle, _ => OsbOrigin.Centre, i => ringPattern(0, i).project(FOV).screenSpaceVector, count ); ring.Fade(s, s + Timing.beat(s) / 2, 0, 1.0f); ring.Fade(e, 0); ring.Scale(s, 0.5); float spinSpeed = 2; for (float t = s; t < e; t += delta) { float t2 = t + delta < e ? t + delta : e; float spin = spinSpeed * (t - s) / 1000.0f; float spin2 = spinSpeed * (t2 - s) / 1000.0f; ring.Move3D( OsbEasing.None, t, t2, i => ringPattern(spin, i).rotate3D(ringRotation, Vectors.Centre3D), i => ringPattern(spin2, i).rotate3D(ringRotation + ringRotationSpeed, Vectors.Centre3D), FOV, (_sprite, _p1, _p2) => { float scale1 = pointScale / _p1.normalisedVector.Length; float scale2 = pointScale / _p2.normalisedVector.Length; if (scale1 != scale2) { _sprite.Scale(t, t2, scale1, scale2); } } ); ringRotation += ringRotationSpeed; } }