62 lines
2.0 KiB
JavaScript
62 lines
2.0 KiB
JavaScript
const GLSL = `
|
|
const float IMPLICIT_MOBIUS_TAU = 6.283185307179586;
|
|
|
|
float sdf(vec3 p) {
|
|
float u = atan(p.y, p.x);
|
|
vec2 section = vec2(length(p.xy) - radius, p.z);
|
|
vec2 twistAxis = vec2(cos(0.5 * u), sin(0.5 * u));
|
|
vec2 closest = twistAxis * clamp(dot(section, twistAxis), -(width * 0.5), (width * 0.5));
|
|
return length(section - closest) - thickness;
|
|
}
|
|
|
|
|
|
vec3 implicit_palette(float t) {
|
|
return 0.58 + 0.42 * cos(6.283185307179586 * (vec3(0.02, 0.38, 0.72) + t));
|
|
}
|
|
|
|
vec3 color(vec3 p, vec3 normal) {
|
|
vec2 ring = vec2(p.x, p.y);
|
|
float angle = atan(ring.y, ring.x) / 6.283185307179586;
|
|
vec3 bandColor = implicit_palette(angle + p.z * 0.035);
|
|
return mix(bandColor, vec3(1.0, 0.84, 0.48), smoothstep(0.25, 0.95, abs(normal.z)) * 0.28);
|
|
}
|
|
`;
|
|
|
|
export default {
|
|
schema: "implicit.js/0.1.0",
|
|
name: "mobius strip",
|
|
units: "mm",
|
|
params: {
|
|
radius: { type: "number", label: "Radius", min: 14, max: 34, step: 0.25, default: 24, unit: "mm" },
|
|
width: { type: "number", label: "Band width", min: 4, max: 22, step: 0.25, default: 13.6, unit: "mm" },
|
|
thickness: { type: "number", label: "Thickness", min: 0.25, max: 2.5, step: 0.05, default: 0.82, unit: "mm" }
|
|
},
|
|
animations: {
|
|
bandBreath: {
|
|
label: "Band breath",
|
|
duration: 4.8,
|
|
loop: true,
|
|
update({ progress, set }) {
|
|
const wave = Math.sin(progress * Math.PI * 2);
|
|
set("width", 13.6 + wave * 5.5);
|
|
set("thickness", 0.82 + wave * 0.35);
|
|
set("radius", 24 + wave * 4);
|
|
}
|
|
}
|
|
},
|
|
bounds: ({ params }) => {
|
|
const halfWidth = params.width * 0.5;
|
|
const radialExtent = params.radius + halfWidth + params.thickness + 6;
|
|
const heightExtent = halfWidth + params.thickness + 6;
|
|
return [[-radialExtent, -radialExtent, -heightExtent], [radialExtent, radialExtent, heightExtent]];
|
|
},
|
|
render: ({ params }) => ({
|
|
steps: 192,
|
|
stepScale: 0.72,
|
|
maxStep: Math.max(params.thickness * 3.8, 1.4),
|
|
epsilon: Math.max(params.thickness * 0.012, 0.006),
|
|
normalEpsilon: Math.max(params.thickness * 0.075, 0.04)
|
|
}),
|
|
glsl: GLSL
|
|
};
|