Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
3D SDF Primitives in WGSL

3D SDF Primitives in WGSL

How to use this gist:

  1. Build a sphere tracer with WebGPU (paper, paper2, youtube)
  2. Create model with sdf functions from here
  3. Add light and shadows
  4. ???
  5. PROFIT

This code tested in Chrome and Firefox, should work on PC too.

Function select can work differently in browsers.

Primitives

Sphere - exact

fn sdSphere(p: vec3<f32>, r: f32) -> f32 {
  return length(p) - r;
}

Ellipsoid - bound (not exact)

fn sdEllipsoid(p: vec3<f32>, r: vec3<f32>) -> f32 {
  let k0 = length(p / r);
  let k1 = length(p / (r * r));
  return k0 * (k0 - 1.) / k1;
}

Box - exact

fn sdBox(p: vec3<f32>, b: vec3<f32>) -> f32 {
  let q = abs(p) - b;
  return length(max(q, vec3<f32>(0.))) + min(max(q.x, max(q.y, q.z)), 0.);
}

Round Box - exact

fn sdRoundBox(p: vec3<f32>, b: vec3<f32>, r: f32) -> f32 {
  let q = abs(p) - b;
  return length(max(q, vec3<f32>(0.))) + min(max(q.x,max(q.y, q.z)), 0.) - r;
}

Box Frame - exact

fn sdBoxFrame(p: vec3<f32>, b: vec3<f32>, e: f32) -> f32 {
  let q = abs(p) - b;
  let w = abs(q + e) - e;
  return min(min(
      length(max(vec3<f32>(q.x, w.y, w.z), vec3<f32>(0.))) + min(max(q.x, max(w.y, w.z)), 0.),
      length(max(vec3<f32>(w.x, q.y, w.z), vec3<f32>(0.))) + min(max(w.x, max(q.y, w.z)), 0.)),
      length(max(vec3<f32>(w.x, w.y, q.z), vec3<f32>(0.))) + min(max(w.x, max(w.y, q.z)), 0.));
}

Gyroid - bound

fn sdGyroid(p: vec3<f32>, h: f32) -> f32 {
  return abs(dot(sin(p), cos(p.zxy))) - h;
}

Torus - exact

fn sdTorus(p: vec3<f32>, R: f32, r: f32) -> f32 {
  let q = vec2<f32>(length(p.xz) - R, p.y);
  return length(q) - r;
}

Capped Torus - exact

fn sdCappedTorus(p: vec3<f32>, R: f32, r: f32, sincos: vec2<f32>) -> f32 {
  let q = vec3<f32>(abs(p.x), p.y, p.z);
  let k = select(length(q.xy), dot(q.xy, sincos), sincos.y * q.x > sincos.x * q.y);
  return sqrt(dot(q, q) + R * R - 2. * R * k) - r;
}

Link - exact

fn sdLink(p: vec3<f32>, R: f32, r: f32, le: f32) -> f32 {
  let q = vec3<f32>(p.x, max(abs(p.y) - le, 0.), p.z);
  return length(vec2<f32>(length(q.xy) - R, q.z)) - r;
}

Capsule / Line - exact

fn sdCapsule(p: vec3<f32>, a: vec3<f32>, b: vec3<f32>, r: f32) -> f32 {
  let pa = p - a;
  let ba = b - a;
  let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);
  return length(pa - ba * h) - r;
}

Vertical Capsule / Line - exact

fn sdVerticalCapsule(p: vec3<f32>, h: f32, r: f32) -> f32 {
  let q = vec3<f32>(p.x, p.y - clamp(p.y, 0., h), p.z);
  return length(q) - r;
}

Cylinder - exact

fn sdCylinder(p: vec3<f32>, a: vec3<f32>, b: vec3<f32>, r: f32) -> f32 {
  let ba = b - a;
  let pa = p - a;
  let baba = dot(ba, ba);
  let paba = dot(pa, ba);
  let x = length(pa * baba - ba * paba) - r * baba;
  let y = abs(paba - baba * 0.5) - baba * 0.5;
  let x2 = x * x;
  let y2 = y * y * baba;
  let d = x2 * step(0., x) + y2 * step(0., y);
  let d2 = select(d, -min(x2, y2), max(x, y) < 0.);
  return sign(d2) * sqrt(abs(d2)) / baba;
}

Vertical Cylinder - exact

fn sdVerticalCylinder(p: vec3<f32>, h: f32, r: f32) -> f32 {
  let d = abs(vec2<f32>(length(p.xz), p.y)) - vec2<f32>(r, h);
  return min(max(d.x, d.y), 0.) + length(max(d, vec2<f32>(0.)));
}

Rounded Cylinder - exact

fn sdRoundedCylinder(p: vec3<f32>, h: f32, r: f32, re: f32) -> f32 {
  let d = vec2<f32>(length(p.xz) - 2. * r + re, abs(p.y) - h);
  return min(max(d.x, d.y), 0.) + length(max(d, vec2<f32>(0.))) - re;
}

Infinite Cylinder - exact

fn sdInfiniteCylinder(p: vec3<f32>, c: vec3<f32>) -> f32 {
  return length(p.xz - c.xy) - c.z;
}

Cone - exact

fn sdCone(p: vec3<f32>, h: f32, sincos: vec2<f32>) -> f32 {
  // Alternatively pass q instead of (sin(alpha), cos(alpha))
  let q = h * vec2<f32>(sincos.x / sincos.y, -1.);

  let w = vec2<f32>(length(p.xz), p.y);
  let a = w - q * clamp(dot(w,q) / dot(q,q), 0., 1.);
  let b = w - q * vec2<f32>(clamp(w.x / q.x, 0., 1.), 1.);
  let k = sign(q.y);
  let d = min(dot(a, a), dot(b, b));
  let s = max(k * (w.x * q.y - w.y * q.x), k * (w.y - q.y));
  return sqrt(d) * sign(s);
}

Cone - bound (not exact)

fn sdConeBound(p: vec3<f32>, h: f32, sincos: vec2<f32>) -> f32 {
  return max(dot(sincos.yx, vec2<f32>(length(p.xz), p.y)), -h - p.y);
}

Infinite Cone - exact

fn sdInfiniteCone(p: vec3<f32>, sincos: vec2<f32>) -> f32 {
  let q = vec2<f32>(length(p.xz), -p.y);
  let d = length(q - sincos * max(dot(q, sincos), 0.));
  return d * select(-1., 1., q.x * sincos.y - q.y * sincos.x > 0.0);
}

Capped Vertical Cone - exact

fn sdCappedVerticalCone(p: vec3<f32>, h: f32, r1: f32, r2: f32) -> f32 {
  let q = vec2<f32>(length(p.xz), p.y);
  let k1 = vec2<f32>(r2, h);
  let k2 = vec2<f32>(r2 - r1, 2. * h);
  let ca = vec2<f32>(q.x - min(q.x, select(r2, r1, q.y < 0.)), abs(q.y) - h);
  let cb = q - k1 + k2 * clamp(dot(k1 - q, k2) / dot(k2, k2), 0., 1.);
  let s = select(1., -1., cb.x < 0. && ca.y < 0.);
  return s * sqrt(min(dot(ca, ca), dot(cb, cb)));
}

Capped Cone - exact

fn sdCappedCone(p: vec3<f32>, a: vec3<f32>, b: vec3<f32>, ra: f32, rb: f32) -> f32 {
  let rba = rb - ra;
  let baba = dot(b - a, b - a);
  let papa = dot(p - a, p - a);
  let paba = dot(p - a, b - a) / baba;
  let x = sqrt(papa - paba * paba * baba);
  let cax = max(0.0, x - select(rb, ra, paba < 0.5));
  let cay = abs(paba - 0.5) - 0.5;
  let k = rba * rba + baba;
  let f = clamp((rba * (x - ra) + paba * baba) / k, 0.0, 1.0);
  let cbx = x - ra - f * rba;
  let cby = paba - f;
  let s = select(1., -1., cbx < 0.0 && cay < 0.0);
  return s * sqrt(min(cax * cax + cay * cay * baba, cbx * cbx + cby * cby * baba));
}

Round Vertical cone - exact

fn sdRoundVerticalCone(p: vec3<f32>, h: f32, r1: f32, r2: f32) -> f32 {
  let q = vec2<f32>(length(p.xz), p.y);
  let b = (r1 - r2) / h;
  let a = sqrt(1. - b * b);
  let k = dot(q, vec2<f32>(-b, a));
  if (k < 0.) { return length(q) - r1; }
  if (k > a * h) { return length(q - vec2<f32>(0., h)) - r2; }
  return dot(q, vec2<f32>(a, b)) - r1;
}

Round cone - exact

fn sdRoundCone(p: vec3<f32>, a: vec3<f32>, b: vec3<f32>, r1: f32, r2: f32) -> f32 {
  let ba = b - a;
  let l2 = dot(ba, ba);
  let rr = r1 - r2;
  let a2 = l2 - rr * rr;
  let il2 = 1. / l2;

  let pa = p - a;
  let y = dot(pa, ba);
  let z = y - l2;
  let w = pa * l2 - ba * y;
  let x2 = dot(w, w);
  let y2 = y * y * l2;
  let z2 = z * z * l2;

  let k = sign(rr) * rr * rr * x2;
  if (sign(z) * a2 * z2 > k) { return sqrt(x2 + z2) * il2 - r2; }
  if (sign(y) * a2 * y2 < k) { return sqrt(x2 + y2) * il2 - r1; }
  return (sqrt(x2 * a2 * il2) + y * rr) * il2 - r1;
}

Solid Angle - exact

fn sdSolidAngle(p: vec3<f32>, sincos: vec2<f32>, r: f32) -> f32 {
  let q = vec2<f32>(length(p.xz), p.y);
  let l = length(q) - r;
  let m = length(q - sincos * clamp(dot(q, sincos), 0., r));
  return max(l, m * sign(sincos.y * q.x - sincos.x * q.y));
}

Plane - exact

fn sdPlane(p: vec3<f32>, n: vec3<f32>, h: f32) -> f32 {
  // n must be normalized
  return dot(p, n) + h;
}

Octahedron - exact

fn sdOctahedron(p: vec3<f32>, s: f32) -> f32 {
  var q: vec3<f32> = abs(p);
  let m = q.x + q.y + q.z - s;
  if (3. * q.x < m) {q = q.xyz;}
  else {if (3. * q.y < m) {q = q.yzx;}
        else {if (3. * q.z < m) {q = q.zxy;}
              else {return m * 0.57735027;}}}
  let k = clamp(0.5 * (q.z - q.y + s), 0., s);
  return length(vec3<f32>(q.x, q.y - s + k, q.z - k));
}

Octahedron - bound (not exact)

fn sdOctahedronBound(p: vec3<f32>, s: f32) -> f32 {
  let q = abs(p);
  return (q.x + q.y + q.z - s) * 0.57735027;
}

Pyramid - exact

fn sdPyramid(p: vec3<f32>, h: f32) -> f32 {
  let m2 = h * h + 0.25;
  var xz: vec2<f32> = abs(p.xz);
  xz = select(xz, xz.yx, xz[1] > xz[0]);
  xz = xz - vec2<f32>(0.5);

  let q = vec3<f32>(xz[1], h * p.y - 0.5 * xz[0], h * xz[0] + 0.5 * p.y);
  let s = max(-q.x, 0.);
  let t = clamp((q.y - 0.5 * xz[1]) / (m2 + 0.25), 0., 1.);

  let a = m2 * (q.x + s) * (q.x + s) + q.y * q.y;
  let b = m2 * (q.x + 0.5 * t) * (q.x + 0.5 * t) + (q.y - m2 * t) * (q.y - m2 * t);

  let d2 = min(a, b) * step(min(q.y, -q.x * m2 - q.y * 0.5), 0.);
  return sqrt((d2 + q.z * q.z) / m2) * sign(max(q.z, -p.y));
}

Hexagonal Prism - exact

fn sdHexPrism(p: vec3<f32>, h: vec2<f32>) -> f32 {
  let k = vec3<f32>(-0.8660254, 0.5, 0.57735);
  let a = abs(p);
  let v = a.xy - 2. * min(dot(k.xy, a.xy), 0.) * k.xy;
  let d1 = length(v - vec2<f32>(clamp(v.x, -k.z * h.x, k.z * h.x), h.x)) * sign(v.y - h.x);
  let d2 = a.z - h.y;
  return min(max(d1, d2), 0.) + length(max(vec2<f32>(d1, d2), vec2<f32>(0.)));
}

Triangular Prism - bound

fn sdTriPrism(p: vec3<f32>, h: vec2<f32>) -> f32 {
  let q = abs(p);
  return max(q.z - h.y, max(q.x * 0.866025 + p.y * 0.5, -p.y) - h.x * 0.5);
}

Quadratic Bezier - exact

fn sdBezier(p: vec3<f32>, A: vec3<f32>, B: vec3<f32>, C: vec3<f32>) -> vec2<f32> {
  let a = B - A;
  let b = A - 2. * B + C;
  let c = a * 2.;
  let d = A - p;
  let kk = 1. / dot(b, b);
  let kx = kk * dot(a, b);
  let ky = kk * (2. * dot(a, a) + dot(d, b)) / 3.;
  let kz = kk * dot(d, a);

  let p1 = ky - kx * kx;
  let p3 = p1 * p1 * p1;
  let q = kx * (2.0 * kx * kx - 3.0 * ky) + kz;
  var h: f32 = q * q + 4. * p3;

  var res: vec2<f32>;
  if (h >= 0.) {
    h = sqrt(h);
    let x = (vec2<f32>(h, -h) - q) / 2.;
    let uv = sign(x) * pow(abs(x), vec2<f32>(1. / 3.));
    let t = clamp(uv.x + uv.y - kx, 0., 1.);
    let f = d + (c + b * t) * t;
    res = vec2<f32>(dot(f, f), t);
  } else {
    let z = sqrt(-p1);
    let v = acos(q / (p1 * z * 2.)) / 3.;
    let m = cos(v);
    let n = sin(v) * 1.732050808;
    let t = clamp(vec2<f32>(m + m, -n - m) * z - kx, vec2<f32>(0.0), vec2<f32>(1.0));
    let f = d + (c + b * t.x) * t.x;
    var dis: f32 = dot(f, f);
    res = vec2<f32>(dis, t.x);

    let g = d + (c + b * t.y) * t.y;
    dis = dot(g, g);
    res = select(res, vec2<f32>(dis, t.y), dis < res.x);
  }
  res.x = sqrt(res.x);
  return res;
}

Triangle - exact

fn udTriangle(p: vec3<f32>, a: vec3<f32>, b: vec3<f32>, c: vec3<f32>) -> f32 {
  let ba = b - a; let pa = p - a;
  let cb = c - b; let pb = p - b;
  let ac = a - c; let pc = p - c;
  let nor = cross(ba, ac);
   let d1 = ba * clamp(dot(ba, pa) / dot(ba, ba), 0., 1.) - pa;
  let d2 = cb * clamp(dot(cb, pb) / dot(cb, cb), 0., 1.) - pb;
  let d3 = ac * clamp(dot(ac, pc) / dot(ac, ac), 0., 1.) - pc;
   let k0 = min(min(dot(d1, d1), dot(d2, d2)), dot(d3, d3));
  let k1 = dot(nor, pa) * dot(nor, pa) / dot(nor, nor);
  let t = sign(dot(cross(ba, nor), pa)) + sign(dot(cross(cb, nor), pb)) +
      sign(dot(cross(ac, nor), pc));
  return sqrt(select(k0, k1, t < 2.));
}

Quad - exact

fn udQuad(p: vec3<f32>, a: vec3<f32>, b: vec3<f32>, c: vec3<f32>, d: vec3<f32>) -> f32 {
  let ba = b - a; let pa = p - a;
  let cb = c - b; let pb = p - b;
  let dc = d - c; let pc = p - c;
  let ad = a - d; let pd = p - d;
  let nor = cross(ba, ad);
   let d1 = ba * clamp(dot(ba, pa) / dot(ba, ba), 0., 1.) - pa;
  let d2 = cb * clamp(dot(cb, pb) / dot(cb, cb), 0., 1.) - pb;
  let d3 = dc * clamp(dot(dc, pc) / dot(dc, dc), 0., 1.) - pc;
  let d4 = ad * clamp(dot(ad, pd) / dot(ad, ad), 0., 1.) - pd;
   let k0 = min(min(dot(d1, d1), dot(d2, d2)), min(dot(d3, d3), dot(d4, d4)));
  let k1 = dot(nor, pa) * dot(nor, pa) / dot(nor, nor);
  let t = sign(dot(cross(ba, nor), pa)) + sign(dot(cross(cb, nor), pb)) +
      sign(dot(cross(dc, nor), pc)) + sign(dot(cross(ad, nor), pd));
  return sqrt(select(k0, k1, t < 3.));
}

Boolean operations with primitives

Union, Subtraction, Intersection - exact (outside), bound, bound

fn opUnion(d1: f32, d2: f32) -> f32 { return min(d1, d2); }

fn opSubtraction(d1: f32, d2: f32) -> f32 { return max(d1, -d2); }

fn opIntersection(d1: f32, d2: f32) -> f32 { return max(d1, d2); }

Chamfer Union, Chamfer Subtraction, Chamfer Intersection - bound, bound, bound

fn opUnionChamfer(d1: f32, d2: f32, r: f32) -> f32 {
  return min(min(d1, d2), (d1 - r + d2) * 0.5);
}

fn opSubtractionChamfer(d1: f32, d2: f32, r: f32) -> f32{
  return max(max(d1, -d2), (d1 + r - d2) * 0.5);
}

fn opIntersectionChamfer(d1: f32, d2: f32, r: f32) -> f32 {
  return max(max(d1, d2), (d1 + r + d2) * 0.5);
}

Blend Union, Blend Subtraction, Blend Intersection - bound, bound, bound

fn opUnionBlend(d1: f32, d2: f32, k: f32) -> f32 {
  let h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0., 1.);
  return mix(d2, d1, h) - k * h * (1. - h);
}

fn opSubtractionBlend(d1: f32, d2: f32, k: f32) -> f32 {
  let h = clamp(0.5 - 0.5 * (d1 + d2) / k, 0., 1.);
  return mix(d1, -d2, h) + k * h * (1. - h);
}

fn opIntersectionBlend(d1: f32, d2: f32, k: f32) -> f32 {
  let h = clamp(0.5 - 0.5 * (d2 - d1) / k, 0., 1.);
  return mix(d2, d1, h) + k * h * (1. - h);
}

Displacement

Displacement - bound (not exact)

fn opDisplace(d1: f32, d2: f32) -> f32 {
  return d1 + d2;
}
//let d = opDisplace(sdfPrimitive3d(p), displacement3d(p));

Twist - bound

fn opTwist(p: vec3<f32>, k: f32) -> vec3<f32> {
  let s = sin(k * p.y);
  let c = cos(k * p.y);
  let m = mat2x2<f32>(vec2<f32>(c, s), vec2<f32>(-s, c));
  return vec3<f32>(m * p.xz, p.y);
}
//let d = sdfPrimitive3d(opTwist(p, k));

Bend - bound

fn opCheapBend(p: vec3<f32>, k: f32) -> vec3<f32> {
  let s = sin(k * p.x);
  let c = cos(k * p.x);
  let m = mat2x2<f32>(vec2<f32>(c, s), vec2<f32>(-s, c));
  return vec3<f32>(m * p.xy, p.z);
}
//let d = sdfPrimitive3d(opCheapBend(p, k));

Positioning

Translate - exact

fn opTranslate(p: vec3<f32>, t: vec3<f32>) -> vec3<f32> {
  return p - t;
}
//let d = sdfPrimitive3d(opTranslate(p, t));

90 degree rotation - exact

fn op90RotateX(p: vec3<f32>) -> vec3<f32> {
  return vec3<f32>(p.x, p.z, -p.y);
}

fn op90RotateY(p: vec3<f32>) -> vec3<f32> {
  let r = sqrt(0.5);
  return vec3<f32>(-p.z, p.y, p.x);
}

fn op90RotateZ(p: vec3<f32>) -> vec3<f32> {
  return vec3<f32>(p.y, -p.x, p.z);
}
//let d = sdfPrimitive3d(op90RotateZ(p));

Rotation around axis - exact

fn opRotateX(p: vec3<f32>, a: f32) -> vec3<f32> {
  let s = sin(a); let c = cos(a);
  return vec3<f32>(p.x, c * p.y + s * p.z, -s * p.y + c * p.z);
}

fn opRotateY(p: vec3<f32>, a: f32) -> vec3<f32> {
  let s = sin(a); let c = cos(a);
  return vec3<f32>(c * p.x - s * p.z, p.y, s * p.x + c * p.z);
}

fn opRotateZ(p: vec3<f32>, a: f32) -> vec3<f32> {
  let s = sin(a); let c = cos(a);
  return vec3<f32>(c * p.x + s * p.y, -s * p.x + c * p.y, p.z);
}
//let d = sdfPrimitive3d(opRotateY(p, a));

Rotation around free axis - exact

fn opRotateE(p: vec3<f32>, e: vec3<f32>, a: f32) -> vec3<f32> {
  let c = cos(a);
  return dot(e, p) * (1. - c) * e - cross(e, p) * sin(a) + c * p;
}
//let d = sdfPrimitive3d(opRotateE(p, normalize(vec3<f32>(1.,0.,.5)), a));

Scale - exact

fn opScale(p: vec3<f32>, s: f32) -> vec3<f32> {
  return p / s;
}
//let d = sdfPrimitive3d(opScale(p, s)) * s;

Free transformation - exact

fn opTransform(p: vec3<f32>, transform: mat4x4<f32>) -> vec3<f32> {
  let q = inverse(transform) * vec4<f32>(p, 1.);
}
//let d = sdfPrimitive3d(opTransform(p, transform)) * determinant(transform);

// OR
//let d = sdfPrimitive3d(opScale(opRotateE(opTranslate(p, t), e, a), s)) * s;

Symmetry - exact

fn opSymmetryX(p: vec3<f32>) -> vec3<f32> { return vec3<f32>(abs(p.x), p.y, p.z); }

fn opSymmetryY(p: vec3<f32>) -> vec3<f32> { return vec3<f32>(p.x, abs(p.y), p.z); }

fn opSymmetryZ(p: vec3<f32>) -> vec3<f32> { return vec3<f32>(p.x, p.y, abs(p.z)); }
//let d = sdfPrimitive3d(opSymmetryX(p));

Infinite Repetition - exact

fn opInfArray(p: vec3<f32>, c: vec3<f32>) -> vec3<f32> {
  return p - c * round(p / c);
}
//let d = sdfPrimitive3d(opInfArray(p, c));

Finite Repetition - exact

fn opLimArray(p: vec3<f32>, c: f32, lim: vec3<f32>) -> vec3<f32> {
  return p - c * clamp(round(p / c), -lim, lim);
}
//let d = sdfPrimitive3d(opLimArray(p, c));

Primitive alterations

Elongation - exact

fn opElongate(p: vec3<f32>, h: vec3<f32>) -> vec3<f32> {
  return p - clamp(p, -h, h);
}
//let d = sdfPrimitive3d(opElongateFast(p, h));

fn opElongateCorrect(p: vec3<f32>, h: vec3<f32>) -> vec4<f32> {
  let q = abs(p) - h;
  let sgn = 2. * step(vec3<f32>(0.), p) - vec3<f32>(1.);
  return vec4<f32>(sgn * max(q, vec3<f32>(0.)), min(max(q.x, max(q.y, q.z)), 0.));
}
//let p2 = opElongateCorrect(p, h);
//let d = p2.w + sdfPrimitive3d(p2.xyz);

Rounding - exact

fn opRound(p: vec3<f32>, r: f32) -> f32 {
  return sdfPrimitive3d(p) - r;
}

Onion - exact

fn opOnion(d: f32, thickness: f32) -> f32 {
  return abs(d) - thickness;
}
//let d = opOnion(sdfPrimitive3d(p), thickness);

Extrusion from 2D SDF - exact

fn opExtrusion(d: f32, z: f32, h: f32) -> f32 {
  let w = vec2<f32>(d, abs(z) - h);
  return min(max(w.x, w.y), 0.) + length(max(w, vec2<f32>(0.)));
}
//let d = opExtrusion(sdfPrimitive2d(p.xy), p.z, h));

Revolution from 2D SDF - exact

fn opRevolution(p: vec3<f32>, o: f32) -> vec2<f32> {
  return vec2<f32>(length(p.xz) - o, p.y);
}
//let d = sdfPrimitive2d(opRevolution(p, h));

Change metric - bound

fn length4(p: vec3<f32>) -> f32 {
  var q: vec3<f32> = p * p;
  q = q * q;
  return sqrt(sqrt(q.x + q.y + q.z));
}

fn length6(p: vec3<f32>) -> f32 {
  var q: vec3<f32> = p * p * p;
  q = q * q;
  return pow(q.x + q.y + q.z, 1. / 6.);
}

fn length8(p: vec3<f32>) -> f32 {
  var q: vec3<f32> = p * p;
  q = q * q; q = q * q;
  return pow(q.x + q.y + q.z, 1. / 8.);
}

MIT License. © 2020 Inigo Quilez, Johann Korndörfer, Martijn Steinrucken, Munrocket

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment