Files
cadSet/text-to-cad/models/implicits/genus-2-double-torus.implicit.js
T
2026-07-22 19:38:36 +08:00

58 lines
2.5 KiB
JavaScript

const GLSL = `
float sdf(vec3 p) {
float left = implicit_torus(p - vec3(-(separation * 0.5), 0.0, 0.0), majorRadius, tubeRadius);
float right = implicit_torus(p - vec3((separation * 0.5), 0.0, 0.0), majorRadius, tubeRadius);
float bridge = implicit_capsule(p, vec3(-max((separation * 0.5) - tubeRadius * 0.6, tubeRadius), 0.0, 0.0), vec3(max((separation * 0.5) - tubeRadius * 0.6, tubeRadius), 0.0, 0.0), bridgeRadius);
float handles = implicit_union_round(left, right, blend);
return implicit_union_round(handles, bridge, max(blend * 0.78, 0.4));
}
vec3 color(vec3 p, vec3 normal) {
float side = smoothstep(-18.0, 18.0, p.x);
return mix(mix(leftColor, rightColor, side), highlightColor, smoothstep(0.65, 0.98, abs(normal.z)) * 0.28);
}
`;
export default {
schema: "implicit.js/0.1.0",
name: "genus-2 double torus",
description: "Two toroidal handles smoothly fused into one symmetric watertight genus-2 solid.",
units: "mm",
params: {
separation: { type: "number", label: "Handle spacing", min: 16, max: 34, step: 0.25, default: 26, unit: "mm" },
majorRadius: { type: "number", label: "Major radius", min: 7, max: 15, step: 0.25, default: 10.5, unit: "mm" },
tubeRadius: { type: "number", label: "Tube radius", min: 2.2, max: 6.5, step: 0.1, default: 4.2, unit: "mm" },
bridgeRadius: { type: "number", label: "Bridge radius", min: 2.6, max: 7, step: 0.1, default: 5.2, unit: "mm" },
blend: { type: "number", label: "Blend", min: 0.5, max: 6, step: 0.1, default: 3.8, unit: "mm" },
leftColor: { type: "color", label: "Left handle", default: "#ff6fb1" },
rightColor: { type: "color", label: "Right handle", default: "#7c83ff" },
highlightColor: { type: "color", label: "Bridge light", default: "#fff06a" }
},
animations: {
handleBreath: {
label: "Handle breath",
duration: 5.0,
loop: true,
update({ progress, set }) {
const wave = Math.sin(progress * Math.PI * 2);
set("separation", 26 + wave * 5);
set("tubeRadius", 4.2 + wave * 1.1);
set("blend", 3.8 + wave * 2.0);
}
}
},
bounds: ({ params }) => {
const halfSpacing = params.separation / 2;
const x = halfSpacing + params.majorRadius + params.tubeRadius + params.blend + 8;
const yz = params.majorRadius + params.tubeRadius + params.blend + 8;
return [[-x, -yz, -yz], [x, yz, yz]];
},
render: ({ params }) => ({
steps: 240,
epsilon: Math.max(0.004, params.tubeRadius * 0.0014),
normalEpsilon: Math.max(0.035, params.tubeRadius * 0.011)
}),
glsl: GLSL
};