#include using namespace metal; // Fractal Pyramid — bradjamesgrant // MSL port of fractal_pyramid.vk.glsl. struct ShadertoyUBO { float iTime; float2 iResolution; }; struct PassthroughVOut { float4 pos [[position]]; float2 uv; }; static float3 palette(float d) { return mix(float3(0.2, 0.7, 0.9), float3(1.0, 0.0, 1.0), d); } static float2 rotate(float2 p, float a) { float c = cos(a); float s = sin(a); return p * float2x2(c, s, -s, c); } static float mapScene(float3 p, float iTime) { for (int i = 0; i < 8; ++i) { float t = iTime * 0.2; p.xz = rotate(p.xz, t); p.xy = rotate(p.xy, t * 1.89); p.xz = abs(p.xz); p.xz -= 0.5; } return dot(sign(p), p) / 5.0; } static float4 rm(float3 ro, float3 rd, float iTime) { float t = 0.0; float3 col = float3(0.0); float d = 1.0; for (int i = 0; i < 64; ++i) { float3 p = ro + rd * t; d = mapScene(p, iTime) * 0.5; if (d < 0.02) break; if (d > 100.0) break; col += palette(length(p) * 0.1) / (400.0 * d); t += d; } return float4(col, 1.0 / (d * 100.0)); } fragment float4 fractal_pyramid_fs(PassthroughVOut in [[stage_in]], constant ShadertoyUBO& U [[buffer(0)]]) { float2 fragCoord = in.uv * U.iResolution; float2 uv = (fragCoord - (U.iResolution * 0.5)) / U.iResolution.x; float3 ro = float3(0.0, 0.0, -50.0); ro.xz = rotate(ro.xz, U.iTime); float3 cf = normalize(-ro); float3 cs = normalize(cross(cf, float3(0.0, 1.0, 0.0))); float3 cu = normalize(cross(cf, cs)); float3 uuv = ro + cf * 3.0 + uv.x * cs + uv.y * cu; float3 rd = normalize(uuv - ro); return rm(ro, rd, U.iTime); }