diff --git a/packages/shader-ast-stdlib/README.md b/packages/shader-ast-stdlib/README.md index 74f5c59eb5..46dcc4dbf0 100644 --- a/packages/shader-ast-stdlib/README.md +++ b/packages/shader-ast-stdlib/README.md @@ -104,7 +104,7 @@ node --experimental-repl-await > const shaderAstStdlib = await import("@thi.ng/shader-ast-stdlib"); ``` -Package sizes (gzipped, pre-treeshake): ESM: 11.05 KB +Package sizes (gzipped, pre-treeshake): ESM: 11.81 KB ## Dependencies @@ -443,6 +443,7 @@ for reference. #### Primitives +- `sdfArc2` - `sdfBox2` - `sdfBox3` - `sdfCircle` @@ -451,6 +452,7 @@ for reference. - `sdfLine3` - `sdfPlane2` - `sdfPlane3` +- `sdfQuadratic2` - `sdfSphere` - `sdfTorus` - `sdfTriangle2` diff --git a/packages/shader-ast-stdlib/src/index.ts b/packages/shader-ast-stdlib/src/index.ts index a05b833502..6beafd0a68 100644 --- a/packages/shader-ast-stdlib/src/index.ts +++ b/packages/shader-ast-stdlib/src/index.ts @@ -53,6 +53,8 @@ export * from "./raymarch/scene.js"; export * from "./screen/uv.js"; export * from "./sdf/annular.js"; +export * from "./sdf/arc.js"; +export * from "./sdf/bezier.js"; export * from "./sdf/box.js"; export * from "./sdf/cylinder.js"; export * from "./sdf/isec.js"; diff --git a/packages/shader-ast-stdlib/src/sdf/arc.ts b/packages/shader-ast-stdlib/src/sdf/arc.ts new file mode 100644 index 0000000000..c2ef5986c3 --- /dev/null +++ b/packages/shader-ast-stdlib/src/sdf/arc.ts @@ -0,0 +1,43 @@ +import type { Vec2Sym } from "@thi.ng/shader-ast/api/syms"; +import { ternary } from "@thi.ng/shader-ast/ast/controlflow"; +import { defn, ret } from "@thi.ng/shader-ast/ast/function"; +import { vec2 } from "@thi.ng/shader-ast/ast/lit"; +import { gt, madd, mul, neg, sub } from "@thi.ng/shader-ast/ast/ops"; +import { $x, $y } from "@thi.ng/shader-ast/ast/swizzle"; +import { sym } from "@thi.ng/shader-ast/ast/sym"; +import { abs, cos, length, sin } from "@thi.ng/shader-ast/builtin/math"; + +/** + * Returns signed distance from `p` to 2D circular arc with `aperture` (in + * [0..π] interval), radius `ra` and `thickness`. + * + * @remarks + * Slightly modified version (easier to use aperture control) of original GLSL + * impl by Inigo Quilez: + * + * - https://www.shadertoy.com/view/wl23RK + * - https://iquilezles.org/articles/distfunctions2d/ + */ +export const sdfArc2 = defn( + "float", + "sdfArc", + ["vec2", "float", "float", "float"], + (p, apert, ra, rb) => { + let q: Vec2Sym; + let sc: Vec2Sym; + return [ + (q = sym(vec2(abs($x(p)), $y(p)))), + (sc = sym(vec2(sin(apert), cos(apert)))), + ret( + sub( + ternary( + gt(mul($y(sc), $x(q)), mul($x(sc), $y(q))), + length(madd(sc, neg(ra), q)), + abs(sub(length(q), ra)) + ), + rb + ) + ), + ]; + } +); diff --git a/packages/shader-ast-stdlib/src/sdf/bezier.ts b/packages/shader-ast-stdlib/src/sdf/bezier.ts new file mode 100644 index 0000000000..de79e96d9a --- /dev/null +++ b/packages/shader-ast-stdlib/src/sdf/bezier.ts @@ -0,0 +1,117 @@ +import type { FloatSym, Vec2Sym } from "@thi.ng/shader-ast"; +import { assign } from "@thi.ng/shader-ast/ast/assign"; +import { ifThen } from "@thi.ng/shader-ast/ast/controlflow"; +import { defn, ret } from "@thi.ng/shader-ast/ast/function"; +import { + float, + FLOAT0, + FLOAT1, + FLOAT2, + vec2, +} from "@thi.ng/shader-ast/ast/lit"; +import { + add, + div, + gte, + lt, + madd, + mul, + neg, + sub, +} from "@thi.ng/shader-ast/ast/ops"; +import { $x, $y } from "@thi.ng/shader-ast/ast/swizzle"; +import { sym } from "@thi.ng/shader-ast/ast/sym"; +import { + abs, + acos, + cos, + dot, + powf, + sign, + sin, + sqrt, +} from "@thi.ng/shader-ast/builtin/math"; +import { clamp01 } from "../math/clamp.js"; +import { cross2 } from "../math/cross2.js"; + +/** + * Returns signed distance from `p` to 2D quadratic bezier (given by points A, + * B, C). + * + * @remarks + * Ported from original GLSL impl by Inigo Quilez: + * + * - https://www.shadertoy.com/view/MlKcDD + * - https://iquilezles.org/articles/distfunctions2d/ + */ +export const sdfQuadratic2 = defn( + "float", + "sdfQuadratic2", + ["vec2", "vec2", "vec2", "vec2"], + (pos, A, B, C) => { + let a: Vec2Sym, b: Vec2Sym, c: Vec2Sym, d: Vec2Sym; + let kk: FloatSym, kx: FloatSym, ky: FloatSym, kz: FloatSym; + let p: FloatSym, q: FloatSym, p3: FloatSym, q2: FloatSym, h: FloatSym; + let m: FloatSym, n: FloatSym, t: FloatSym, v: FloatSym, z: FloatSym; + let res: FloatSym, sgn: FloatSym; + let x: Vec2Sym, y: Vec2Sym, uv: Vec2Sym; + return [ + (a = sym(sub(B, A))), + (b = sym(add(madd(B, -2, A), C))), + (c = sym(mul(a, 2))), + (d = sym(sub(A, pos))), + (kk = sym(div(FLOAT1, dot(b, b)))), + (kx = sym(mul(kk, dot(a, b)))), + (ky = sym(mul(kk, div(madd(FLOAT2, dot(a, a), dot(d, b)), 3)))), + (kz = sym(mul(kk, dot(d, a)))), + (res = sym(FLOAT0)), + (sgn = sym(FLOAT0)), + (p = sym(sub(ky, mul(kx, kx)))), + (q = sym(madd(sub(mul(mul(FLOAT2, kx), kx), mul(3, ky)), kx, kz))), + (p3 = sym(mul(mul(p, p), p))), + (q2 = sym(mul(q, q))), + (h = sym(madd(p3, 4, q2))), + ifThen( + gte(h, FLOAT0), + [ + assign(h, sqrt(h)), + (x = sym(div(sub(vec2(h, neg(h)), q), FLOAT2))), + (uv = sym(mul(sign(x), powf(abs(x), float(1 / 3))))), + (t = sym(clamp01(sub(add($x(uv), $y(uv)), kx)))), + assign(x, madd(madd(b, t, c), t, d)), + assign(res, dot(x, x)), + assign(sgn, cross2(madd(b, mul(t, FLOAT2), c), x)), + ], + [ + (z = sym(sqrt(neg(p)))), + (v = sym( + div(acos(div(q, mul(mul(p, z), FLOAT2))), float(3)) + )), + (m = sym(cos(v))), + (n = sym(mul(sin(v), 1.732050808))), + (uv = sym( + clamp01( + sub(mul(vec2(add(m, m), sub(neg(n), m)), z), kx) + ) + )), + (x = sym(madd(madd(b, $x(uv), c), $x(uv), d))), + (y = sym(madd(madd(b, $y(uv), c), $y(uv), d))), + assign(m, dot(x, x)), + assign(n, dot(y, y)), + ifThen( + lt(m, n), + [ + assign(res, m), + assign(sgn, cross2(madd(b, mul($x(uv), 2), c), x)), + ], + [ + assign(res, n), + assign(sgn, cross2(madd(b, mul($y(uv), 2), c), y)), + ] + ), + ] + ), + ret(mul(sign(sgn), sqrt(res))), + ]; + } +); diff --git a/packages/shader-ast-stdlib/tpl.readme.md b/packages/shader-ast-stdlib/tpl.readme.md index af99768d05..5d2400b536 100644 --- a/packages/shader-ast-stdlib/tpl.readme.md +++ b/packages/shader-ast-stdlib/tpl.readme.md @@ -370,6 +370,7 @@ for reference. #### Primitives +- `sdfArc2` - `sdfBox2` - `sdfBox3` - `sdfCircle` @@ -378,6 +379,7 @@ for reference. - `sdfLine3` - `sdfPlane2` - `sdfPlane3` +- `sdfQuadratic2` - `sdfSphere` - `sdfTorus` - `sdfTriangle2`