64 lines
2.3 KiB
JavaScript
64 lines
2.3 KiB
JavaScript
const GLSL = `
|
|
const float IMPLICIT_TREFOIL_TAU = 6.283185307179586;
|
|
|
|
float sdf(vec3 p) {
|
|
p.z /= verticalScale;
|
|
float phi = atan(p.y, p.x);
|
|
vec2 torusSection = vec2(length(p.xy) - majorRadius, p.z);
|
|
float best = 1.0e6;
|
|
for (int branchIndex = 0; branchIndex < 3; branchIndex += 1) {
|
|
float t = (phi + IMPLICIT_TREFOIL_TAU * float(branchIndex)) / 3.0;
|
|
vec2 knotCenter = knotRadius * vec2(cos(2.0 * t), sin(2.0 * t));
|
|
best = min(best, length(torusSection - knotCenter));
|
|
}
|
|
return best - tubeRadius;
|
|
}
|
|
|
|
|
|
vec3 color(vec3 p, vec3 normal) {
|
|
float sweep = atan(p.y, p.x) / IMPLICIT_TREFOIL_TAU + p.z * 0.018;
|
|
return mix(baseColor, accentColor, 0.5 + 0.5 * sin(6.283185307179586 * sweep));
|
|
}
|
|
`;
|
|
|
|
export default {
|
|
schema: "implicit.js/0.1.0",
|
|
name: "trefoil torus-knot tube",
|
|
description: "A constant-radius solid tube following a closed trefoil torus knot path.",
|
|
units: "mm",
|
|
params: {
|
|
majorRadius: { type: "number", label: "Major radius", min: 10, max: 24, step: 0.25, default: 16.5, unit: "mm" },
|
|
knotRadius: { type: "number", label: "Lobe radius", min: 3.5, max: 10, step: 0.1, default: 6.9, unit: "mm" },
|
|
tubeRadius: { type: "number", label: "Tube radius", min: 0.8, max: 4.5, step: 0.05, default: 2.05, unit: "mm" },
|
|
verticalScale: { type: "number", label: "Vertical scale", min: 0.65, max: 1.6, step: 0.05, default: 1 },
|
|
baseColor: { type: "color", label: "Copper color", default: "#ff7a33" },
|
|
accentColor: { type: "color", label: "Cyan color", default: "#2ee8ff" }
|
|
},
|
|
animations: {
|
|
knotBreath: {
|
|
label: "Knot breath",
|
|
duration: 5.2,
|
|
loop: true,
|
|
update({ progress, set }) {
|
|
const wave = Math.sin(progress * Math.PI * 2);
|
|
set("tubeRadius", 2.05 + wave * 0.95);
|
|
set("knotRadius", 6.9 + wave * 1.7);
|
|
set("verticalScale", 1 + wave * 0.3);
|
|
}
|
|
}
|
|
},
|
|
bounds: ({ params }) => {
|
|
const xy = params.majorRadius + params.knotRadius + params.tubeRadius + 5;
|
|
const z = params.knotRadius * params.verticalScale + params.tubeRadius + 5;
|
|
return [[-xy, -xy, -z], [xy, xy, z]];
|
|
},
|
|
render: ({ params }) => ({
|
|
steps: 220,
|
|
epsilon: Math.max(0.006, params.tubeRadius * 0.004),
|
|
normalEpsilon: Math.max(0.04, params.tubeRadius * 0.028),
|
|
stepScale: 0.72,
|
|
maxStep: Math.max(params.tubeRadius * 0.68, 0.7)
|
|
}),
|
|
glsl: GLSL
|
|
};
|