raymarch = (opts = {}) => {
const {
sceneSDF = `vec2 sceneSDF(vec3 p) { return vec2(length(p) - 1., 2.); }`,
computeColor = computeColorIQ(),
eye = `vec3(0.0, 0.0, 4.0)`,
target = `vec3(0.0)`,
background = `vec3(0.6 - length((gl_FragCoord.xy - u_resolution / 2.) / u_resolution.x))`,
distMin = 0.001,
distMax = 20,
raymarchingSteps = 100,
antiAliasing = 1,
gamma = `vec3(1.)`,
init = `void init() {}`,
effect = `vec3 effect(vec3 col) { return col; }`,
...options
} = opts
return fragment(`
precision mediump float;
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// Antialiasing: number of samples in x and y dimensions
#define AA ${antiAliasing | 0}
#define MIN_DIST float(${distMin})
#define MAX_DIST float(${distMax})
${sceneSDF}
${setCamera()}
${castRay(raymarchingSteps)}
${softShadow()}
${calcNormal()}
${calcAO()}
${computeColor}
${render(background)}
${init}
${effect}
void main() {
// Ray Origin)
vec3 ro = ${eye};
vec3 ta = ${target};
// camera-to-world transformation
mat3 ca = setCamera(ro, ta, 0.0);
vec3 color = vec3(0.0);
#if AA>1
for(int m = 0; m < AA; m++)
for(int n = 0; n < AA; n++) {
// pixel coordinates
vec2 o = vec2(float(m), float(n)) / float(AA) - 0.5;
vec2 p = (-u_resolution.xy + 2.0 * (gl_FragCoord.xy + o)) / u_resolution.y;
#else
vec2 p = (-u_resolution.xy + 2.0 * gl_FragCoord.xy) / u_resolution.y;
#endif
// ray direction
vec3 rd = ca * normalize(vec3(p.xy, 2.0));
// render
vec3 col = render(ro, rd);
color += col;
#if AA>1
}
color /= float(AA*AA);
#endif
color = effect(color);
gl_FragColor = vec4(color, 1.0);
}`, options)
}