|
#include <metal_stdlib> |
|
#include "SwiftUI/SwiftUI.h" |
|
using namespace metal; |
|
// made with claude code |
|
|
|
[[ stitchable ]] half4 shredder(float2 position, SwiftUI::Layer layer, float2 size, float offset) { |
|
float padding = 80; |
|
if (position.y < size.y + padding) { |
|
float2 p = position; |
|
p.y -= max(offset, 0.0); |
|
return layer.sample(p); |
|
} |
|
float stripCount = 35; |
|
float stripWidth = size.x / stripCount; |
|
|
|
float nominalStrip = floor(position.x / stripWidth); |
|
float max_h_shift = 0.2 * min(offset, size.y / 2); |
|
float max_rot_r = 0.1 * (offset / size.y); |
|
float max_rot_dev = max_rot_r * size.y; |
|
float max_curl_dev = stripWidth * 0.5; |
|
float max_dev_pixels = max_h_shift + max_rot_dev + max_curl_dev + 20.0; |
|
float max_dev_strips = max_dev_pixels / stripWidth; |
|
float range_di = ceil(max_dev_strips) + 1.0; |
|
|
|
for (float i = max(nominalStrip - range_di, 0.0); i < min(nominalStrip + range_di, stripCount); i += 1.0) { |
|
float seed1 = fract(sin(i * 127.1) * 43758.5453); |
|
float seed2 = fract(sin(i * 269.5) * 18462.3421); |
|
float seed3 = fract(sin(i * 412.3) * 29571.1247); |
|
float seed4 = fract(sin(i * 531.7) * 67234.8912); |
|
float seed5 = fract(sin(i * 673.2) * 31847.2156); |
|
|
|
float fallDistance = offset * (1.0 + seed1 * 0.1); |
|
|
|
float horizontalShift = (seed2) * offset * 0.1; |
|
|
|
float rotation = (seed3 - 0.5) * 0.1 * (offset / size.y); |
|
|
|
float curlIntensity = (0.3 + seed4) * offset / size.y; |
|
float curlFrequency = 2.0 + seed5 * 1.0; |
|
float curlDirection = (seed4 > 0.5) ? 1.0 : -1.0; |
|
|
|
float originalCenterX = (i + 0.5) * stripWidth; |
|
|
|
float currentCenterX = originalCenterX + horizontalShift; |
|
|
|
float pivotY = size.y * 0.5; |
|
|
|
float localX = position.x - currentCenterX; |
|
float localY = position.y - fallDistance - pivotY; |
|
|
|
float cosR = cos(rotation); |
|
float sinR = sin(rotation); |
|
float origLocalX = localX * cosR - localY * sinR; |
|
float origLocalY = localX * sinR + localY * cosR; |
|
|
|
float normalizedY = (origLocalY + pivotY) / size.y; |
|
|
|
float curlOffset = sin(normalizedY * M_PI_F * curlFrequency) * stripWidth * 0.3 * curlIntensity * curlDirection; |
|
|
|
origLocalX -= curlOffset; |
|
|
|
float sourceX = originalCenterX + origLocalX; |
|
float sourceY = origLocalY + pivotY; |
|
|
|
float stripLeft = i * stripWidth; |
|
float stripRight = (i + 1.0) * stripWidth; |
|
|
|
if (sourceX >= stripLeft && sourceX < stripRight) { |
|
if (sourceY >= 0.0 && sourceY < size.y && sourceX >= 0.0 && sourceX < size.x) { |
|
half4 color = layer.sample(float2(sourceX, sourceY)); |
|
|
|
float withinStrip = (sourceX - stripLeft) / stripWidth; |
|
float edgeFade = smoothstep(0.0, 0.1, withinStrip) * smoothstep(1.0, 0.9, withinStrip); |
|
color.rgb *= (0.9 + 0.1 * edgeFade); |
|
|
|
float curlShading = cos(normalizedY * M_PI_F * curlFrequency) * curlIntensity * 0.15; |
|
color.rgb *= (1.0 - abs(curlShading)); |
|
|
|
return color; |
|
} |
|
} |
|
} |
|
|
|
return half4(0.0); |
|
} |