Skip to content

Instantly share code, notes, and snippets.

@dkun7944
Created July 31, 2023 03:36
Show Gist options
  • Save dkun7944/2f793643e469029fb4e7d700f0645ffc to your computer and use it in GitHub Desktop.
Save dkun7944/2f793643e469029fb4e7d700f0645ffc to your computer and use it in GitHub Desktop.
AirDrop iOS 17 Swift.Shader Animation
//
// airdrop.metal
// Airdrop Demo
//
// Created by Daniel Kuntz on 7/30/23.
//
#include <metal_stdlib>
#include <SwiftUI/SwiftUI_Metal.h>
using namespace metal;
[[ stitchable ]] half4 airdrop(float2 position, SwiftUI::Layer layer, float t, float2 viewSize) {
float2 position_yflip = float2(position.x, viewSize.y - position.y);
float uv_y_dynamic_island_offset = 0.46;
float t2 = pow(t, 2);
float t3 = pow(t, 3);
// Normalized pixel coordinates (from 0 to 1)
float2 uv = position_yflip / viewSize;
float2 uv_stretch = float2(uv.x+((uv.x-0.5)*pow(uv.y,6)*t3*0.1), uv.y * (uv.y * pow((1-(t2*0.01)), 8.0)) + (1-uv.y) * uv.y);
uv_stretch = mix(uv, uv_stretch, smoothstep(1.1, 1.0, t));
float4 color = float4(layer.sample(uv_stretch * viewSize));
float2 bang_offset = float2(0.0);
float bang_d = 0.0;
if (t >= 1.0) {
float aT = t - 1.0;
float2 uv2 = uv;
uv2 -= 0.5;
uv2.x *= viewSize.x / viewSize.y;
uv2.x -= 0.1;
float2 uv_bang = float2(uv2.x, uv2.y);
float2 uv_bang_origin = float2(uv_bang.x, uv_bang.y-uv_y_dynamic_island_offset);
bang_d = (aT*0.16)/length(uv_bang_origin);
bang_d = smoothstep(0.09, 0.05, bang_d) * smoothstep(0.04, 0.07, bang_d) * (uv.y+0.05);
bang_offset = float2(-8.0*bang_d*uv2.x, -4.0*bang_d*(uv2.y-0.4))*0.1;
float bang_d2 = ((aT-0.085) * 0.14)/length(uv_bang_origin);
bang_d2 = smoothstep(0.09, 0.05, bang_d2) * smoothstep(0.04, 0.07, bang_d2) * (uv.y+0.05);
bang_offset += float2(-8.0*bang_d2*uv2.x, -4.0*bang_d2*(uv2.y-0.4))*-0.02;
}
float2 uv_stretch_bang = uv_stretch+bang_offset;
color = float4(layer.sample(uv_stretch_bang * viewSize));
color += bang_d*500.0 * smoothstep(1.05, 1.1, t);
float Pi = 6.28318530718 * 2;
float Directions = 60.0;
float Quality = 10.0;
float Radius = t2*0.1 * pow(uv.y, 6.0) * 0.5;
Radius *= smoothstep(1.3, 0.9, t);
Radius += bang_d*0.05;
// Blur calculations
for( float d=0.0; d<Pi; d+=Pi/Directions)
{
for(float i=1.0/Quality; i<=1.0; i+=1.0/Quality)
{
float2 blurPos = (uv_stretch_bang + float2(cos(d),sin(d))*Radius*i);
color += float4(layer.sample(blurPos*viewSize));
}
}
color /= Quality * Directions;
uv -= 0.5;
uv.x *= viewSize.x / viewSize.y;
uv.x -= 0.1;
float2 lighten_uv = float2(uv.x*0.65, uv.y - t + 0.5);
float d = smoothstep(0, 0.6, 0.1/length(lighten_uv)-uv_y_dynamic_island_offset)*0.25;
float t_smooth = smoothstep(0.0, 0.3, t);
d *= t_smooth;
color = color + float4(color.r*d, color.g*d, 0.0, 1.0); // yellow blob
float2 lighten2_uv = float2(uv.x*0.4, uv.y-uv_y_dynamic_island_offset);
float d2 = smoothstep(0, 0.5, pow(1-length(lighten2_uv), 28))*0.5;
float t2_smooth = smoothstep(0.0, 1.0, t2)*1.;
d2 *= t2_smooth;
d2 *= smoothstep(1.13, 1.0, t);
color = float4(color.rgb*(1-d2), 1.0) + float4(float3(d2), 1.0); // white blob
return half4(color);
}
//
// ContentView.swift
// Airdrop Demo
//
// Created by Daniel Kuntz on 7/30/23.
//
import SwiftUI
struct ContentView: View {
@State private var timer: Timer?
@State private var t: Float = 0.0
private let shaderFunction = ShaderFunction(library: .default, name: "airdrop")
var body: some View {
VStack {
Image("mick")
.resizable()
.aspectRatio(contentMode: .fill)
.scaleEffect(x: 1.0, y: -1.0)
.layerEffect(
Shader(function: shaderFunction,
arguments: [
.float(t),
.float2(Float(UIScreen.main.bounds.width),
Float(UIScreen.main.bounds.height))
]), maxSampleOffset: CGSize(width: 800.0, height: 800.0)
)
}
.ignoresSafeArea()
.onAppear {
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { _ in
t = (t + 0.01).truncatingRemainder(dividingBy: 2.0)
})
}
}
}
#Preview {
ContentView()
}
@mlajtos
Copy link

mlajtos commented Jul 31, 2023

float Pi = 6.28318530718 * 2;

!

@superkeka
Copy link

superkeka commented Jul 31, 2023

🤣
Domenico-Fetti_Archimedes_1620

@SwCake1
Copy link

SwCake1 commented Oct 9, 2023

This animation is so cool, thank you for sharing, Daniel!
It uses SwiftUI with ShaderFunction that's available only from iOS 17. I wonder, is it possible to use it with older versions of iOS with UIKit?

@dkun7944
Copy link
Author

dkun7944 commented Oct 9, 2023 via email

@SwCake1
Copy link

SwCake1 commented Oct 10, 2023

Awesome, I'll find out, thank you for direction👍

@GalaxyAX
Copy link

The animation rendering is really bad. There seems to be something wrong with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment