// soft min of a and b with smoothing factor k float smin(float a, float b, float k) { float h = max(k - abs(a-b), 0) / k; return min(a, b) - h * h * h * k * (1 / 6.0); } // soft max of a and b with smoothing factor k float smax(float a, float b, float k) { float h = max(k - abs(a - b), 0) / k; return max(a, b) + h * h * h * k * (1 / 6.0); } Material mixMat(Material a, Material b, float fac) { Material m; m.col = lerp(a.col, b.col, fac); m.gloss = lerp(a.gloss, b.gloss, fac); return m; } Material mixMat(SurfacePoint a, SurfacePoint b) { float fac = clamp(a.dist/(a.dist + b.dist), 0, 1); return mixMat(a.mat, b.mat, fac); } // -------------------------------- // base sdf operations // -------------------------------- float qUnion(float a, float b) { return min(a, b); } float qUnion(float a, float b, float smooth) { return smin(a, b, smooth); } SurfacePoint qUnion(SurfacePoint a, SurfacePoint b) { SurfacePoint o; o.dist = min(a.dist, b.dist); o.mat = mixMat(a, b); return o; } SurfacePoint qUnion(SurfacePoint a, SurfacePoint b, float smooth) { SurfacePoint o; o.dist = smin(a.dist, b.dist, smooth); o.mat = mixMat(a, b); return o; } float qSub(float a, float b) { return max(a, -b); } float qSub(float a, float b, float smooth) { return smax(a, -b, smooth); } SurfacePoint qSub(SurfacePoint a, SurfacePoint b) { SurfacePoint o; o.dist = max(a.dist, -b.dist); o.mat = a.mat; return o; } SurfacePoint qSub(SurfacePoint a, SurfacePoint b, float smooth) { SurfacePoint o; o.dist = smax(a.dist, -b.dist, smooth); o.mat = a.mat; return o; } float qIntersect(float a, float b) { return max(a, b); } float qIntersect(float a, float b, float smooth) { return smax(a, b, smooth); } SurfacePoint qIntersect(SurfacePoint a, SurfacePoint b) { SurfacePoint o; o.dist = max(a.dist, b.dist); o.mat = mixMat(a, b); return o; } SurfacePoint qIntersect(SurfacePoint a, SurfacePoint b, float smooth) { SurfacePoint o; o.dist = smax(a.dist, b.dist, smooth); o.mat = mixMat(a, b); return o; } float qRound(float a, float radius) { return a - radius; } SurfacePoint qRound(SurfacePoint a, float radius) { a.dist -= radius; return a; } // -------------------------------- // spatial warping // -------------------------------- float3 rotX(float3 p, float a) { return mul(float3x3(1, 0, 0, 0, cos(a), -sin(a), 0, sin(a), cos(a)), p); } float3 rotY(float3 p, float a) { return mul(float3x3(cos(a), 0, sin(a), 0, 1, 0, -sin(a), 0, cos(a)), p); } float3 rotZ(float3 p, float a) { return mul(float3x3(cos(a), -sin(a), 0, sin(a), cos(a), 0, 0, 0, 1), p); } // repeats space every r units, centered on the origin float3 repXYZ(float3 p, float3 r) { float3 o = p; o = fmod(abs(p + r/2.0), r) - r/2.0; o *= sign(o); return o; } // repeats space every r units, centered on the origin, no sign float3 repXYZUnsigned(float3 p, float3 r) { return fmod(abs(p + r / 2.0), r) - r / 2.0; } // repeats space inline float3 repXZ(float3 p, float x, float z) { float3 o = p; o.x = fmod(abs(p.x) + x / 2.0, x) - x / 2.0; o.x *= sign(p.x); o.z = fmod(abs(p.z) + z / 2.0, z) - z / 2.0; o.z *= sign(p.z); return o; }