Skip to content

Instantly share code, notes, and snippets.

@Koshimizu-Takehito
Last active January 13, 2025 07:57
Show Gist options
  • Save Koshimizu-Takehito/0a8bd5123fcd081d082081ba1a48489f to your computer and use it in GitHub Desktop.
Save Koshimizu-Takehito/0a8bd5123fcd081d082081ba1a48489f to your computer and use it in GitHub Desktop.
#include <metal_stdlib>
#include <SwiftUI/SwiftUI.h>
using namespace metal;
constant int MAX_RADIUS = 100;
constant int MAX_KERNEL_SIZE = 2 * MAX_RADIUS + 1;
float gaussian(float x, float sigma) {
return exp(-0.5 * x * x / (sigma * sigma)) / (sigma * sqrt(2.0 * M_PI_F));
}
void getKernel(int radius, float sigma, float _kernel[MAX_KERNEL_SIZE]) {
float sum = 0.0;
for (int i = -radius; i <= radius; i++) {
int index = i + MAX_RADIUS;
_kernel[index] = gaussian(float(i), sigma);
sum += _kernel[index];
}
for (int i = MAX_RADIUS - radius; i <= MAX_RADIUS + radius; i++) {
_kernel[i] /= sum;
}
}
[[ stitchable ]] half4 progressiveBlur(
float2 position,
SwiftUI::Layer layer,
float4 box,
float radius
) {
float ratio = min(max(position.y / box.w, 0.0), 1.0);
radius = radius * smoothstep(0, 1, ratio);
if (radius <= 0) {
return layer.sample(position);
}
half4 sum = half4(0);
const int offset = int(radius);
const float sigma = radius / 3.0;
float _kernel[MAX_KERNEL_SIZE];
getKernel(offset, sigma, _kernel);
for (int y = -offset; y <= offset; y++) {
for (int x = -offset; x <= offset; x++) {
float2 point = position + float2(x, y);
sum += layer.sample(point)
* _kernel[y + MAX_RADIUS] * _kernel[x + MAX_RADIUS];
}
}
return sum;
}
import SwiftUI
struct ContentView: View {
let start = Date()
var body: some View {
TimelineView(.animation) { context in
let time = context.date.timeIntervalSince(start)
let radius = 20 * (sin(time - .pi/2) + 1)
Image("waterwheel")
.modifier(ProgressiveBlur(radius: radius))
}
}
}
struct ProgressiveBlur: ViewModifier {
let radius: Double
func body(content: Content) -> some View {
let offset = CGSize(width: radius, height: radius)
let shader = ShaderLibrary
.progressiveBlur(.boundingRect, .float(radius))
content.layerEffect(shader, maxSampleOffset: offset)
}
}
#Preview {
ContentView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment