Files
shadertoy/shaders/just_another_cube/just_another_cube.frag.msl

90 lines
2.1 KiB
Plaintext

#include <metal_stdlib>
using namespace metal;
// Just Another Cube — mrange
// MSL port of just_another_cube.vk.glsl. The Shadertoy original uses
// mutable file-scope globals; in MSL we pass them by reference.
struct ShadertoyUBO {
float iTime;
float2 iResolution;
};
struct PassthroughVOut {
float4 pos [[position]];
float2 uv;
};
constant float M = 1e-3;
static float D(float3 p,
thread float2x2& R,
thread float& d,
thread float& G) {
p.xy = p.xy * R;
p.xz = p.xz * R;
float3 S = sin(123.0 * p);
float shell = abs(length(p) - 0.6);
p *= p * p * p;
d = pow(dot(p, p), 0.125) - 0.5
- pow(1.0 + S.x * S.y * S.z, 8.0) / 1e5;
G = min(G, max(shell, d));
return d;
}
fragment float4 just_another_cube_fs(PassthroughVOut in [[stage_in]],
constant ShadertoyUBO& U [[buffer(0)]]) {
float2 C = in.uv * U.iResolution;
float2x2 R;
float d = 1.0, z = 0.0, G = 9.0;
float3 r = float3(U.iResolution, U.iResolution.y);
float3 I = normalize(float3(C - 0.5 * r.xy, r.y));
float3 B = float3(1, 2, 9) * M;
float3 p = float3(0.0);
float3 O = float3(0.0);
{
float4 cs = cos(0.3 * U.iTime + float4(0, 11, 33, 0));
R = float2x2(cs.x, cs.y, cs.z, cs.w);
}
for (; z < 9.0 && d > M; z += D(p, R, d, G)) {
p = z * I;
p.z -= 2.0;
}
if (z < 9.0) {
for (int i = 0; i < 3; ) {
r = float3(0.0);
r[i] = M;
O[i++] = D(p + r, R, d, G) - D(p - r, R, d, G);
}
O = normalize(O);
z = 1.0 + dot(O, I);
r = reflect(I, O);
C = (p + r * (5.0 - p.y) / abs(r.y)).xz;
float3 colorTerm;
if (r.y > 0.0) {
d = sqrt(length(C * C)) + 1.0;
colorTerm = 5e2 * smoothstep(5.0, 4.0, d) * d * B;
} else {
colorTerm = exp(-2.0 * length(C)) * (B / M - 1.0);
}
O = z * z * colorTerm + pow(1.0 + O.y, 5.0) * B;
}
float4 result = sqrt(float4(O + B / G, O.x + B.x / G));
return result;
}