76 lines
2.5 KiB
JavaScript
76 lines
2.5 KiB
JavaScript
const GLSL = `
|
|
float sdBox(vec3 p, vec3 b) {
|
|
vec3 q = abs(p) - b;
|
|
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
|
|
}
|
|
|
|
float snowflakeRadius(float a) {
|
|
float r = radius * (0.72 + 0.12 * cos(3.0 * a));
|
|
if (depth > 1.5) {
|
|
r += radius * 0.105 * cos(12.0 * a);
|
|
}
|
|
if (depth > 2.5) {
|
|
r += radius * 0.055 * cos(48.0 * a);
|
|
}
|
|
if (depth > 3.5) {
|
|
r += radius * 0.026 * cos(96.0 * a);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
float sdf(vec3 p) {
|
|
float a = atan(p.y, p.x);
|
|
float radial = length(p.xy) - snowflakeRadius(a);
|
|
float sideBevel = radial - edgeRound;
|
|
float slab = abs(p.z) - thickness * 0.5 + edgeRound;
|
|
return min(max(sideBevel, slab), 0.0) + length(max(vec2(sideBevel, slab), 0.0)) - edgeRound;
|
|
}
|
|
|
|
vec3 color(vec3 p, vec3 normal) {
|
|
float a = atan(p.y, p.x);
|
|
float ice = 0.5 + 0.5 * cos(a * 12.0 + length(p.xy) * 0.11);
|
|
vec3 c = mix(baseColor, accentColor, ice);
|
|
return c * (0.62 + 0.38 * smoothstep(-0.3, 0.95, normal.z));
|
|
}
|
|
`;
|
|
|
|
export default {
|
|
schema: "implicit.js/0.1.0",
|
|
name: "Koch snowflake extrusion",
|
|
description: "A rounded extruded Koch-snowflake approximation with controllable recursive edge detail.",
|
|
units: "mm",
|
|
params: {
|
|
radius: { type: "number", label: "Radius", min: 14, max: 42, step: 0.5, default: 28, unit: "mm" },
|
|
depth: { type: "number", label: "Recursion depth", min: 1, max: 4, step: 1, default: 4 },
|
|
thickness: { type: "number", label: "Thickness", min: 1.5, max: 9, step: 0.1, default: 4.2, unit: "mm" },
|
|
edgeRound: { type: "number", label: "Edge round", min: 0.05, max: 1.6, step: 0.05, default: 0.55, unit: "mm" },
|
|
baseColor: { type: "color", label: "Ice color", default: "#e0fbff" },
|
|
accentColor: { type: "color", label: "Edge color", default: "#00a6ff" }
|
|
},
|
|
animations: {
|
|
frostBloom: {
|
|
label: "Frost bloom",
|
|
duration: 5.0,
|
|
loop: true,
|
|
update({ progress, set }) {
|
|
const wave = Math.sin(progress * Math.PI * 2);
|
|
set("edgeRound", 0.55 + (wave * 0.5 + 0.5) * 0.75);
|
|
set("thickness", 4.2 + wave * 1.2);
|
|
}
|
|
}
|
|
},
|
|
bounds: ({ params }) => {
|
|
const extent = params.radius + params.edgeRound + 7;
|
|
const z = params.thickness + params.edgeRound + 4;
|
|
return [[-extent, -extent, -z], [extent, extent, z]];
|
|
},
|
|
render: ({ params }) => ({
|
|
steps: 180,
|
|
stepScale: 0.72,
|
|
maxStep: Math.max(params.edgeRound * 4.5, 1.0),
|
|
epsilon: Math.max(params.edgeRound * 0.012, 0.004),
|
|
normalEpsilon: Math.max(params.edgeRound * 0.09, 0.035)
|
|
}),
|
|
glsl: GLSL
|
|
};
|