Skip to content

Instantly share code, notes, and snippets.

@webserveis
Forked from dkun7944/ContentView.swift
Created July 31, 2023 15:43

Revisions

  1. @dkun7944 dkun7944 created this gist Jul 31, 2023.
    43 changes: 43 additions & 0 deletions ContentView.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    //
    // 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()
    }
    84 changes: 84 additions & 0 deletions airdrop.metal
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    //
    // 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);
    }