sh = () => raymarch({
eye: `vec3(3, 3, 3) * 2.5`,
background: `vec3(${hexToRgb(palette[0]).join(',')})/255.`,
distMax: 30,
sceneSDF: `
#define PI ${Math.PI}
#define TAU ${Math.PI * 2}
#define NUM_COLORS ${palette.length}.
uniform sampler2D u_texture;
${iqSDF.sdTorus()}
${iqSDF.opUnion()}
${iqSDF.sdRoundedCylinder()}
${iqSDF.sdSphere()}
${glslSnippets.rotate3D()}
vec2 mapRef(vec3 p) {
vec2 d = vec2(sdTorus(p * rotate3D(u_time * TAU, vec3(0, 0, 1)), vec2(3., 1.8)), 0.5);
return d;
}
vec2 mapShadow(vec3 p) {
vec2 d = vec2(10e5, 0.);
const float n = 12.;
for(float i = 0.; i < n; i ++) {
d = opUnion(d, vec2(sdRoundedCylinder(p * rotate3D(i/n * PI, vec3(1, 0, 1)) + vec3(0, sin(-u_time * TAU + i/n * PI) * 12., 0), 1., .8, 2.1 + cos(-(u_time + .25) * 2. * TAU + i/n * TAU) * 2.), mod(i, NUM_COLORS - 1.) + 1.));
}
return d;
}
vec2 sceneSDF(vec3 p) {
return opUnion(mapRef(p), mapShadow(p));
}`,
computeColor: `
vec3 getNormalRef(vec3 p){
vec2 e = vec2(.0002,0.);
vec3 n = vec3(
mapRef(p + e.xyy).x - mapRef(p - e.xyy).x,
mapRef(p + e.yxy).x - mapRef(p - e.yxy).x,
mapRef(p + e.yyx).x - mapRef(p - e.yyx).x
);
return normalize(n);
}
vec2 marcherRef(vec3 ro, vec3 rd) {
float t = 0.001;
float m = -1.;
for(int i=0; i<200; i++) {
vec2 d = mapRef(ro + t * rd);
if(abs(d.x)<.0001) break;
t+=d.x;
m = d.y;
}
return vec2(t,m);
}
float getShadow(vec3 ro, vec3 rd) {
float depth = 1e-3;
float res = 1.0;
for (int i = 0; i < 22; i++) {
vec2 info = mapShadow(ro + rd * depth);
res = min(res, 10.0 * info.x / depth);
if (res < 1e-3) { break; }
depth += info.x;
}
return res;
}
vec3 getNormalShadow(vec3 p){
vec2 e = vec2(.0002,0.);
vec3 n = vec3(
mapShadow(p + e.xyy).x - mapShadow(p - e.xyy).x,
mapShadow(p + e.yxy).x - mapShadow(p - e.yxy).x,
mapShadow(p + e.yyx).x - mapShadow(p - e.yyx).x
);
return normalize(n);
}
vec2 marcherShadow(vec3 ro, vec3 rd) {
float t = 0.001;
float m = -1.;
for(int i=0; i<100; i++) {
vec2 d = mapShadow(ro + t * rd);
m =d.y;
if(abs(d.x)<.001) break;
t+=d.x;
}
return vec2(t,m);
}
vec3 getLight(vec3 p, vec3 nor, vec3 lops) {
vec3 light = vec3(0.0);
float ambient = 1.0;
float diffuse = max(dot(nor, lops), 0.0);
float shadow = getShadow(p + nor * 1e-3, normalize(vec3(0.,1.,0.5)));
light += ambient * vec3(0.12, 0.23, 0.19) * shadow;
light += diffuse * vec3(0.97, 0.99, 0.99) * shadow;
return light;
}
vec3 getColor(float id, vec3 pos, vec3 rd) {
if (id < 1.0) return vec3(${hexToRgb(palette[0]).join(',')})/255.;
return texture2D(u_texture, vec2((id+.5) / NUM_COLORS, .5)).rgb;
}
vec3 computeColor(vec3 ro, vec3 rd, vec3 pos, float d, float m) {
if(m < 1.) {
vec3 nor = calcNormal(pos);
float fresnel = clamp(1.0 + dot(rd, nor), 0.0, 1.0);
vec3 reflected = reflect(rd, nor);
vec3 p = pos;
vec2 d = castRay(ro, rd);
vec3 reflectedPos = p + reflected * d.x;
vec3 reflectedN = calcNormal(reflectedPos);
vec3 lpos = normalize(vec3(0.,1.,0.5));
vec3 light = vec3(0);
if (d.y >= 1.0) {
light = getLight(p, nor, lpos);
}
vec3 refl = getColor(d.y, reflectedPos, reflected) * light;
rd = refract(rd, nor, 1.0 / 1.03); // water
d = marcherRef(p - nor * 1e-3, rd);
p = p + rd * d.x;
nor = getNormalRef(p);
p = p - nor * 1e-5;
rd = refract(rd, nor, 1.0 / 1.33);
d = marcherShadow(p, rd);
p = p + rd * d.x;
nor = getNormalShadow(p);
light = vec3(1.0);
if (d.y >= 1.0) {
light = getLight(p, nor, lpos);
}
vec3 refr = getColor(d.y, p, rd) * light;
vec3 col = mix(refr, refl, pow(fresnel, 5.0) * 0.8 + 0.2);
return pow(col, vec3(0.4545));
}
else {
vec3 nor = calcNormal(pos);
vec3 ref = reflect(rd, nor); // reflected ray
// material
vec3 col = texture2D(u_texture, vec2((m+.5) / NUM_COLORS, .5)).rgb;
// lighting
float occ = calcAO(pos, nor); // ambient occlusion
vec3 lig = normalize(vec3(-0.4, 0.7, -0.6)); // sunlight
float amb = clamp(0.5 + 0.5 * nor.y, 0.0, 1.0); // ambient light
float dif = clamp(dot(nor, lig), 0.0, 1.0); // diffuse reflection from sunlight
// backlight
float bac = clamp(dot(nor, normalize(vec3(-lig.x, 0.0, -lig.z))), 0.0, 1.0) * clamp(1.0 - pos.y, 0.0, 1.0);
float dom = smoothstep(-0.1, 0.1, ref.y); // dome light
float fre = pow(clamp(1.0 + dot(nor, rd), 0.0, 1.0), 2.0); // fresnel
float spe = pow(clamp(dot(ref, lig), 0.0, 1.0), 16.0); // specular reflection
dif *= softshadow(pos, lig, 0.02, 2.5);
dom *= softshadow(pos, ref, 0.02, 2.5);
vec3 lin = vec3(0.0);
lin += 1.30 * dif * vec3(1.00, 0.80, 0.55);
lin += 2.00 * spe * vec3(1.00, 0.90, 0.70) * dif;
lin += 0.40 * amb * vec3(0.40, 0.60, 1.00) * occ;
lin += 0.50 * dom * vec3(0.40, 0.60, 1.00) * occ;
lin += 0.50 * bac * vec3(0.25, 0.25, 0.25) * occ;
lin += 0.25 * fre * vec3(1.00, 1.00, 1.00) * occ;
col = col * lin;
// mix in fog?
// col = mix(col, vec3(0.8, 0.9, 1.0), 1.0 - exp(-0.0002 * d * d * d));
col = mix(col, vec3(${hexToRgb(palette[0]).join(',')})/255., 1.0 - exp(-0.00003 * d * d * d));
// gamma
//col = pow(col, vec3(0.4545));
return col;
}
}`,
logShader: true
})