public static SpriteSet Trail(StoryboardLayer layer, OsbSprite sprite, double startTime, double endTime, double timeBetweenSprites, double fadeInTime, double duration, double fadeOutTime, bool cutWhenSpriteDisappears) { SpriteSet trail = layer.CreateSpriteSet(); for (double t = startTime; t < endTime; t += timeBetweenSprites) { if (sprite.OpacityAt(t) == 0) { continue; } var trailSprite = layer.CreateSprite(sprite.TexturePath, OsbOrigin.Centre, sprite.PositionAt(t)); double s = fadeInTime; double d = duration; double e = fadeOutTime; double up = sprite.OpacityAt(t); double down = 0; if (cutWhenSpriteDisappears) { if (sprite.CommandsEndTime <= t + fadeInTime) { // sprite doesn't get to fade in fully s = sprite.CommandsEndTime - t; up = InterpolatingFunctions.Double(0, up, (sprite.CommandsEndTime - t) / (t + fadeInTime)); } else if (sprite.CommandsEndTime <= t + fadeInTime + duration) { // sprite doesn't get to fade out d = sprite.CommandsEndTime - (t + fadeInTime); e = 0; } else if (sprite.CommandsEndTime <= t + fadeInTime + duration + fadeOutTime) { // sprite doesn't get to fade out fully e = sprite.CommandsEndTime - (t + fadeInTime + duration); down = InterpolatingFunctions.Double(up, 0, (sprite.CommandsEndTime - (t + fadeInTime + duration)) / (fadeOutTime)); } } if (s == 0 && e == 0) { trailSprite.Fade(t, t + d, 1, 1); } else { if (s != 0 && d != 0) { trailSprite.Fade(t, t + s, 0, up); } if (e != 0) { trailSprite.Fade(t + d, t + d + e, up, down); } } trail.AddSprite(trailSprite); } return(trail); }
public override void GenerateStates(double time, CameraState cameraState, Object3dState object3dState) { var wvp = object3dState.WorldTransform * cameraState.ViewProjection; var screenPosition = cameraState.ToScreen(wvp, Vector3.Zero); var angle = 0.0; switch (RotationMode) { case RotationMode.UnitX: { var unitXPosition = cameraState.ToScreen(wvp, Vector3.UnitX); var delta = unitXPosition - screenPosition; angle += (float)Math.Atan2(delta.Y, delta.X); } break; case RotationMode.UnitY: { var unitYPosition = cameraState.ToScreen(wvp, Vector3.UnitY); var delta = unitYPosition - screenPosition; angle += (float)Math.Atan2(delta.Y, delta.X) - Math.PI * 0.5; } break; } var previousState = Generator.EndState; var rotation = InterpolatingFunctions.DoubleAngle(previousState?.Rotation ?? 0 - SpriteRotation.ValueAt(previousState?.Time ?? time), angle, 1) + SpriteRotation.ValueAt(time); var scale = SpriteScale.ValueAt(time) * object3dState.WorldTransform.ExtractScale().Xy *(float)(cameraState.FocusDistance / screenPosition.W) * (float)cameraState.ResolutionScale; var opacity = screenPosition.W < 0 ? 0 : object3dState.Opacity; if (UseDistanceFade) { opacity *= cameraState.OpacityAt(screenPosition.W); } Generator.Add(new CommandGenerator.State() { Time = time, Position = screenPosition.Xy, Scale = scale, Rotation = rotation, Color = object3dState.Color, Opacity = opacity, Additive = Additive, }); }
public override void GenerateStates(double time, CameraState cameraState, Object3dState object3dState) { var wvp = object3dState.WorldTransform * cameraState.ViewProjection; var startVector = cameraState.ToScreen(wvp, StartPosition.ValueAt(time)); var endVector = cameraState.ToScreen(wvp, EndPosition.ValueAt(time)); var delta = endVector.Xy - startVector.Xy; var length = delta.Length; if (length == 0) { return; } var angle = Math.Atan2(delta.Y, delta.X); var rotation = InterpolatingFunctions.DoubleAngle(GeneratorBody.EndState?.Rotation ?? 0, angle, 1); var thickness = Thickness.ValueAt(time); var scaleFactor = object3dState.WorldTransform.ExtractScale().Y *(float)cameraState.ResolutionScale; var startScale = scaleFactor * (float)(cameraState.FocusDistance / startVector.W) * thickness * StartThickness.ValueAt(time); var endScale = scaleFactor * (float)(cameraState.FocusDistance / endVector.W) * thickness * EndThickness.ValueAt(time); var totalHeight = Math.Max(startScale, endScale); var bodyHeight = Math.Min(startScale, endScale); var edgeHeight = (totalHeight - bodyHeight) * 0.5f; var flip = startScale < endScale; var ignoreEdges = edgeHeight < EdgeOverlap; if (ignoreEdges) { bodyHeight += edgeHeight * 2; } var opacity = startVector.W < 0 && endVector.W < 0 ? 0 : object3dState.Opacity; if (UseDistanceFade) { opacity *= Math.Max(cameraState.OpacityAt(startVector.W), cameraState.OpacityAt(endVector.W)); } // Body var bitmapBody = StoryboardObjectGenerator.Current.GetMapsetBitmap(spriteBody.GetTexturePathAt(time)); var bodyScale = new Vector2(length / bitmapBody.Width, bodyHeight / bitmapBody.Height); var positionBody = startVector.Xy + delta * 0.5f; var bodyOpacity = opacity; GeneratorBody.Add(new CommandGenerator.State() { Time = time, Position = positionBody, Scale = bodyScale, Rotation = rotation, Color = object3dState.Color, Opacity = bodyOpacity, Additive = Additive, }); // Edges if (SpritePathEdge != null) { var bitmapEdge = StoryboardObjectGenerator.Current.GetMapsetBitmap(spriteTopEdge.GetTexturePathAt(time)); var edgeScale = new Vector2(length / bitmapEdge.Width, edgeHeight / bitmapEdge.Height); var edgeOffset = new Vector2((float)Math.Cos(angle - Math.PI * 0.5), (float)Math.Sin(angle - Math.PI * 0.5)) * (bodyHeight * 0.5f - EdgeOverlap); var positionTop = positionBody + edgeOffset; var positionBottom = positionBody - edgeOffset; var edgeOpacity = ignoreEdges ? 0 : opacity; GeneratorTopEdge.Add(new CommandGenerator.State() { Time = time, Position = positionTop, Scale = edgeScale, Rotation = rotation, Color = object3dState.Color, Opacity = edgeOpacity, FlipH = flip, Additive = Additive, }); GeneratorBottomEdge.Add(new CommandGenerator.State() { Time = time, Position = positionBottom, Scale = edgeScale, Rotation = rotation, Color = object3dState.Color, Opacity = edgeOpacity, Additive = Additive, FlipH = flip, FlipV = true, }); } // Caps if (SpritePathCap != null) { var bitmapCap = StoryboardObjectGenerator.Current.GetMapsetBitmap(spriteStartCap.GetTexturePathAt(time)); var startCapScale = new Vector2(startScale / bitmapCap.Width, startScale / bitmapCap.Height); var endCapScale = new Vector2(endScale / bitmapCap.Width, endScale / bitmapCap.Height); var capOffset = OrientedCaps ? new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * CapOverlap : Vector2.Zero; if (OrientedCaps) { startCapScale.X *= 0.5f; endCapScale.X *= 0.5f; } var startCapOpacity = startScale > 0.5f ? opacity : 0; var endCapOpacity = endScale > 0.5f ? opacity : 0; GeneratorStartCap.Add(new CommandGenerator.State() { Time = time, Position = startVector.Xy + capOffset, Scale = startCapScale, Rotation = OrientedCaps ? rotation + Math.PI : 0, Color = object3dState.Color, Opacity = startCapOpacity, Additive = Additive, }); GeneratorEndCap.Add(new CommandGenerator.State() { Time = time, Position = endVector.Xy - capOffset, Scale = endCapScale, Rotation = OrientedCaps ? rotation + Math.PI : 0, Color = object3dState.Color, Opacity = endCapOpacity, Additive = Additive, FlipH = OrientedCaps, }); } }
public override void GenerateStates(double time, CameraState cameraState, Object3dState object3dState) { var wvp = object3dState.WorldTransform * cameraState.ViewProjection; var startVector = cameraState.ToScreen(wvp, StartPosition.ValueAt(time)); var endVector = cameraState.ToScreen(wvp, EndPosition.ValueAt(time)); var delta = endVector.Xy - startVector.Xy; var length = delta.Length; if (length == 0) { return; } var angle = Math.Atan2(delta.Y, delta.X); var rotation = InterpolatingFunctions.DoubleAngle(Generator.EndState?.Rotation ?? 0, angle, 1); var bitmap = StoryboardObjectGenerator.Current.GetMapsetBitmap(sprite.GetTexturePathAt(time)); var scale = new Vector2(length / bitmap.Width, Thickness.ValueAt(time)); var opacity = startVector.W < 0 && endVector.W < 0 ? 0 : object3dState.Opacity; if (UseDistanceFade) { opacity *= Math.Max(cameraState.OpacityAt(startVector.W), cameraState.OpacityAt(endVector.W)); } Vector2 position; switch (sprite.Origin) { default: case OsbOrigin.TopLeft: case OsbOrigin.CentreLeft: case OsbOrigin.BottomLeft: position = startVector.Xy; break; case OsbOrigin.TopCentre: case OsbOrigin.Centre: case OsbOrigin.BottomCentre: position = startVector.Xy + delta * 0.5f; break; case OsbOrigin.TopRight: case OsbOrigin.CentreRight: case OsbOrigin.BottomRight: position = endVector.Xy; break; } Generator.Add(new CommandGenerator.State() { Time = time, Position = position, Scale = scale, Rotation = rotation, Color = object3dState.Color, Opacity = opacity, Additive = Additive, }); }
void Section4_1() { // circle int s = 62840; int e = 63468; float fade = 1; layer = GetLayer(""); maskLayer = GetLayer("masks"); maskLayer2 = GetLayer("masks2"); var downwardsMovement = new Movement(OsbEasing.OutExpo, s, e, Vectors.Centre + Vectors.up(100), Vectors.Centre); var ring1 = maskLayer2.CreateSprite(Sprites.Circle, OsbOrigin.Centre, downwardsMovement.StartPosition); var ring1Mask = maskLayer2.CreateSprite(Sprites.Circle, OsbOrigin.Centre, downwardsMovement.StartPosition); int circleWidth = GetMapsetBitmap(Sprites.Circle).Width; float width = 350.0f; float width2 = 250.0f; float scale = width / circleWidth; float thickness = 10; float lineThickness = thickness * 0.71f; float maskScale = (width - thickness * 2) / circleWidth / scale; ring1.Fade(s, e, fade, fade); ring1.Scale(OsbEasing.OutExpo, s, e - Timing.beat(s), scale, scale / width * width2); ring1.Move(downwardsMovement); ring1Mask.Fade(s, e, 1, 1); ring1Mask.Color(s, Color4.Black); ring1Mask.Scale(OsbEasing.OutExpo, s, e - Timing.beat(s), scale * maskScale, scale * maskScale / width * width2); ring1Mask.Move(downwardsMovement); // 3d ring float startOfRotation = e - 1.25f * (float)Timing.beat(s); var inOutExpo = OsbEasing.InOutExpo.ToEasingFunction(); var outExpo = OsbEasing.OutExpo.ToEasingFunction(); Func <float, float, Vector3> moving3DCircle = (float t, float time) => { float tilt = time < startOfRotation ? 0 : (float)inOutExpo((time - startOfRotation) / (e - startOfRotation)); Vector3 centre = downwardsMovement.PositionAtTime(time).withZ(0); float radius = (MathHelper.Clamp( InterpolatingFunctions.Float(width, width2, outExpo((time - s) / (e - Timing.beat(s) - s))), width2, width ) - thickness) / 2; Vector3 rot1 = new Vector3( 5 * (float)Math.PI / 16, (float)Math.PI / 2, 0 ); Vector3 rot2 = new Vector3( 5 * (float)Math.PI / 16, (float)Math.PI / 4, 0 ); Vector3 rot = Vector3.Lerp(rot1, rot2, tilt); var res = radius * new Vector3( (float)Math.Cos(-t), (float)Math.Sin(-t), 0 ).rotateX(rot.X).rotateY(rot.Y).rotateZ(rot.Z) + centre; return(res); }; int count = 200; float dotScale = lineThickness / circleWidth; for (int i = 0; i < count; i++) { var sprite = layer.CreateSprite(Sprites.Circle, OsbOrigin.Centre); sprite.Fade(s, e, 1, 1); for (float t = s; t < e; t += delta) { float t2 = t + delta < e ? t + delta : e; Vector3 p1 = moving3DCircle( i * 2 * (float)Math.PI / count, t ); Vector3 p2 = moving3DCircle( i * 2 * (float)Math.PI / count, t2 ); sprite.Move3D( OsbEasing.None, t, t2, p1, p2, FOV, (_sprite, _p1, _p2) => { float scale1 = dotScale / _p1.normalisedVector.Length; float scale2 = dotScale / _p2.normalisedVector.Length; if (scale1 != scale2) { _sprite.Scale(t, t2, scale1, scale2); } } ); } } // dotted line through the sphere count = 35; float opacity = 1; float lineAppearStart = s + (float)Timing.beat(s) / 3; float appearDelay = (float)Timing.beat(s) / 2 / count; float length = width2 + 2 * 70; float dottedLineThickness = 1.2f; SpriteSet axisDottedLine = maskLayer.CreateSpriteSet( Sprites.Pixel, _ => OsbOrigin.TopCentre, Patterns.Line2D(Vectors.Centre + Vectors.up(length / 2), Vectors.Centre + Vectors.down(length / 2), count), count ); var dotMovement = new Movement(OsbEasing.OutQuint, s + Timing.beat(s) / 3, e, Vectors.Centre + Vectors.up(100), Vectors.Centre); axisDottedLine.MoveRelative(dotMovement - Vectors.Centre); axisDottedLine.ScaleVec((int)lineAppearStart, new Vector2(dottedLineThickness, length / count / 2)); axisDottedLine.Fade( OsbEasing.None, i => lineAppearStart + i * appearDelay, i => lineAppearStart + i * appearDelay + 100, 0, opacity ); axisDottedLine.Fade(e, 0); SpriteSet gradientMask = maskLayer.CreateSpriteSet(Sprites.TransparentGradient, _ => OsbOrigin.CentreRight, 2); gradientMask.Rotate(lineAppearStart, i => Math.PI / 2 + i * Math.PI); float gradientWidth = GetMapsetBitmap(Sprites.TransparentGradient).Width; gradientMask.ScaleVec(lineAppearStart, new Vector2(length / 2 / gradientWidth, dottedLineThickness)); gradientMask.AddSprites( Sprites.Pixel, i => (i % 2 == 0 ? OsbOrigin.BottomCentre : OsbOrigin.TopCentre), i => Vectors.Centre + (i % 2 == 0 ? 1 : -1) * Vectors.up(length / 2), 2 ); float gradientExtension = Vectors.Centre.Y - length / 2; gradientMask.ScaleVec(lineAppearStart, new Vector2(dottedLineThickness, gradientExtension), 2); gradientMask.Color(lineAppearStart, Color4.Black); gradientMask.Fade(lineAppearStart, e, 1.0, 1.0); SpriteSet cover = maskLayer.CreateSpriteSet(Sprites.Pixel, 2); cover.Move(i => downwardsMovement.ResampledSection(lineAppearStart, e, delta) + Vectors.up((width2 - lineThickness) / 2) * (i % 2 == 0 ? 1 : -1)); cover.Fade(lineAppearStart, e, 1.0, 1.0); cover.ScaleVec(lineAppearStart, new Vector2(dottedLineThickness, lineThickness)); // point cloud count = 50; float pointScale = 0.2f; var pattern = Patterns.PointCloudGlobe(Vectors.Centre.withZ(0), 500, new Random(RandomSeed)); var points = new List <Vector3>(); for (int i = 0; i < count; i++) { points.Add(pattern(i)); } SpriteSet pointCloud = layer.CreateSpriteSet( Sprites.Particle, _ => OsbOrigin.Centre, i => points[i].project(Vectors.ScreenSize, Vectors.Centre, FOV).screenSpaceVector, count ); pointCloud.Fade(startOfRotation, startOfRotation + Timing.beat(s) / 2, 0, 0.6); pointCloud.Fade(e, 0); pointCloud.Scale(startOfRotation, 5); for (float t = startOfRotation; t < e; t += delta) { float t2 = t + delta < e ? t + delta : e; float angle = (float)(-Math.PI / 4 * inOutExpo((t - startOfRotation) / (e - startOfRotation))); float angle2 = (float)(-Math.PI / 4 * inOutExpo((t2 - startOfRotation) / (e - startOfRotation))); pointCloud.Move3D( OsbEasing.None, t, t2, i => points[i].rotateY(angle, Vectors.Centre3D), i => points[i].rotateY(angle2, 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); } } ); } foreach (var sprite in pointCloud.Sprites) { SpriteSet trail = Effects.Trail(layer, sprite, startOfRotation, e, 1000.0 / 60, 0, 0, 150, true); trail.UseScaleOf(sprite); } }
public override void GenerateStates(double time, CameraState cameraState, Object3dState object3dState) { var wvp = object3dState.WorldTransform * cameraState.ViewProjection; if (FixedEdge >= 0) { edgeIndex = FixedEdge; } Vector4 vector0, vector1, vector2; switch (edgeIndex) { case 0: vector0 = cameraState.ToScreen(wvp, Position0.ValueAt(time)); vector1 = cameraState.ToScreen(wvp, Position1.ValueAt(time)); vector2 = cameraState.ToScreen(wvp, Position2.ValueAt(time)); break; case 1: vector2 = cameraState.ToScreen(wvp, Position0.ValueAt(time)); vector0 = cameraState.ToScreen(wvp, Position1.ValueAt(time)); vector1 = cameraState.ToScreen(wvp, Position2.ValueAt(time)); break; case 2: vector1 = cameraState.ToScreen(wvp, Position0.ValueAt(time)); vector2 = cameraState.ToScreen(wvp, Position1.ValueAt(time)); vector0 = cameraState.ToScreen(wvp, Position2.ValueAt(time)); break; default: throw new InvalidOperationException(); } var cross = (vector2.X - vector0.X) * (vector1.Y - vector0.Y) - (vector2.Y - vector0.Y) * (vector1.X - vector0.X); if (cross > 0) { if (Generator0.EndState != null) { Generator0.EndState.Opacity = 0; } if (Generator1.EndState != null) { Generator1.EndState.Opacity = 0; } return; } var bitmap = StoryboardObjectGenerator.Current.GetMapsetBitmap(sprite0.GetTexturePathAt(time)); var switchedEdge = false; for (var i = 0; i < 3; i++) { var delta = vector2.Xy - vector0.Xy; var deltaLength = delta.Length; var normalizedDelta = delta / deltaLength; var delta2 = vector1.Xy - vector0.Xy; var dot = Vector2.Dot(normalizedDelta, delta2); if (dot <= 0 || dot > deltaLength) { if (FixedEdge >= 0) { if (Generator0.EndState != null) { Generator0.EndState.Opacity = 0; } if (Generator1.EndState != null) { Generator1.EndState.Opacity = 0; } break; } var temp = vector0; vector0 = vector1; vector1 = vector2; vector2 = temp; edgeIndex = (edgeIndex + 1) % 3; switchedEdge = true; continue; } var position = project(vector0.Xy, vector2.Xy, vector1.Xy); var scale0 = new Vector2((vector2.Xy - position).Length / bitmap.Width, (vector1.Xy - position).Length / bitmap.Height); var scale1 = new Vector2((vector0.Xy - position).Length / bitmap.Width, scale0.Y); var angle = Math.Atan2(delta.Y, delta.X); var rotation = InterpolatingFunctions.DoubleAngle(Generator0.EndState?.Rotation ?? 0, angle, 1); var opacity = vector0.W < 0 && vector1.W < 0 && vector2.W < 0 ? 0 : object3dState.Opacity; if (UseDistanceFade) { opacity *= (cameraState.OpacityAt(vector0.W) + cameraState.OpacityAt(vector1.W) + cameraState.OpacityAt(vector2.W)) / 3; } if (switchedEdge) { if (Generator0.EndState != null) { Generator0.EndState.Opacity = 0; } if (Generator1.EndState != null) { Generator1.EndState.Opacity = 0; } } Generator0.Add(new CommandGenerator.State() { Time = time, Position = position, Scale = scale0, Rotation = rotation, Color = object3dState.Color, Opacity = switchedEdge ? 0 : opacity, Additive = Additive, }); Generator1.Add(new CommandGenerator.State() { Time = time, Position = position, Scale = scale1, Rotation = rotation, Color = object3dState.Color, Opacity = switchedEdge ? 0 : opacity, Additive = Additive, FlipH = true, }); break; } }