sh = () => raymarch(`
#define PI ${PI}
#define TAU ${TAU}
${rotateX()}
${rotateY()}
${rotateZ()}
${opUnion()}
${opSubtraction()}
${opIntersection()}
${sdSphere()}
${sdBox()}
${sdCappedCylinder()}
// heartbeat function adapted from https://observablehq.com/@mattdesl/heartbeat-function
float beat (float value, float intensity, float frequency) {
float v = atan(sin(value * PI * frequency) * intensity);
return (v + PI / 4.) / PI;
}
vec2 sceneSDF(vec3 p) {
// Slowly spin the whole scene
p = rotateX(u_time * TAU) * p;
float s = beat(u_time * 2., 5., 2.);
p = rotateY(s * TAU) * p;
float cylinderRadius = .5 + .5 * s;
float cylinder1 = sdCappedCylinder(p, 1.0, cylinderRadius);
float cylinder2 = sdCappedCylinder(rotateX(PI/2.) * p, 1., cylinderRadius);
float cylinder3 = sdCappedCylinder(rotateZ(PI/2.) * p, 1., cylinderRadius);
float cube = sdBox(p, vec3(1.8, 1.8, 1.8)/2.);
float sphere = sdSphere(p, 1.2);
float ballOffset = .6 + 2. * s;
float ballRadius = .3 + s / 2.;
float balls = sdSphere(p - vec3(ballOffset, 0., 0.), ballRadius);
balls = opUnion(balls, sdSphere(p + vec3(ballOffset, 0., 0.), ballRadius));
balls = opUnion(balls, sdSphere(p - vec3(0., ballOffset, 0.), ballRadius));
balls = opUnion(balls, sdSphere(p + vec3(0., ballOffset, 0.), ballRadius));
balls = opUnion(balls, sdSphere(p - vec3(0., 0., ballOffset), ballRadius));
balls = opUnion(balls, sdSphere(p + vec3(0., 0., ballOffset), ballRadius));
float csgNut = opSubtraction(opUnion(cylinder1, opUnion(cylinder2, cylinder3)),
opIntersection(cube, sphere));
return vec2(opUnion(balls, csgNut), (balls < csgNut) ? 2. : 1.);
}
`, {
computeColor:`
${phong()}
vec3 computeColor(vec3 p, vec3 eye, float materialID) {
// Use the surface normal as the ambient color of the material
float t = clamp(beat(u_time * 2., 5., 2.) * 1.3, 0., 1.);
vec3 K_a = mix(vec3(0), vec3(1, 1, 0), (materialID == 1.) ? 1. - t : t);
vec3 K_d = K_a;
vec3 K_s = vec3(1);
float shininess = 40.;
return phongIllumination(K_a, K_d, K_s, shininess, p, eye);
}`,
eye: `vec3(8, 5, 7)`,
multiMaterials: true,
logShader: true,
antiAliasing: 3,
})