Let’s self reflect
https://www.shadertoy.com/view/XfyXRV
Shader code
shader_type canvas_item;
const float rotation_speed= 0.25;
const float poly_U = 1.; // [0, inf]
const float poly_V = 0.5; // [0, inf]
const float poly_W = 1.0; // [0, inf]
const int poly_type = 3; // [2, 5]
const float poly_zoom = 2.0;
const float inner_sphere = 1.;
const float refr_index = 0.9;
#define MAX_BOUNCES2 6
// -------------------------------------------------------
#define TAU (2.0*PI)
// License: WTFPL, author: sam hocevar, found: https://stackoverflow.com/a/17897228/418488
const vec4 hsv2rgb_K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 hsv2rgb(vec3 c) {
vec3 p = abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www);
return c.z * mix(hsv2rgb_K.xxx, clamp(p - hsv2rgb_K.xxx, 0.0, 1.0), c.y);
}
// License: WTFPL, author: sam hocevar, found: https://stackoverflow.com/a/17897228/418488
// Macro version of above to enable compile-time constants
#define HSV2RGB(c) (c.z * mix(hsv2rgb_K.xxx, clamp(abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www) - hsv2rgb_K.xxx, 0.0, 1.0), c.y))
#define TOLERANCE2 0.0005
//#define MAX_RAY_LENGTH2 10.0
#define MAX_RAY_MARCHES2 50
#define NORM_OFF2 0.005
#define BACKSTEP2
#define TOLERANCE3 0.0005
#define MAX_RAY_LENGTH3 10.0
#define MAX_RAY_MARCHES3 90
#define NORM_OFF3 0.005
const vec3 rayOrigin = vec3(0.0, 1., -5.);
const vec3 sunDir = normalize(-rayOrigin);
const vec3 sunCol = HSV2RGB(vec3(0.06 , 0.90, 1E-2))*1.;
const vec3 bottomBoxCol = HSV2RGB(vec3(0.66, 0.80, 0.5))*1.;
const vec3 topBoxCol = HSV2RGB(vec3(0.60, 0.90, 1.))*1.;
const vec3 glowCol0 = HSV2RGB(vec3(0.05 , 0.7, 1E-3))*1.;
const vec3 glowCol1 = HSV2RGB(vec3(0.95, 0.7, 1E-3))*1.;
const vec3 beerCol = -HSV2RGB(vec3(0.15+0.5, 0.7, 2.));
const float rrefr_index = 1./refr_index;
// License: Unknown, author: knighty, found: https://www.shadertoy.com/view/MsKGzw
const float poly_cospin = cos(PI/3.0);
const float poly_scospin = sqrt(0.75-poly_cospin*poly_cospin);
const vec3 poly_nc = vec3(-0.5, -poly_cospin, poly_scospin);
const vec3 poly_pab = vec3(0., 0., 1.);
const vec3 poly_pbc_ = vec3(poly_scospin, 0., 0.5);
const vec3 poly_pca_ = vec3(0., poly_scospin, poly_cospin);
const vec3 poly_p = normalize((poly_U*poly_pab+poly_V*poly_pbc_+poly_W*poly_pca_));
const vec3 poly_pbc = normalize(poly_pbc_);
const vec3 poly_pca = normalize(poly_pca_);
// License: MIT, author: Inigo Quilez, found: https://iquilezles.org/articles/noacos/
mat3 rot(vec3 d, vec3 z) {
vec3 v = cross( z, d );
float c = dot( z, d );
float k = 1.0/(1.0+c);
return mat3( vec3( v.x*v.x*k + c, v.y*v.x*k - v.z, v.z*v.x*k + v.y),
vec3( v.x*v.y*k + v.z, v.y*v.y*k + c, v.z*v.y*k - v.x),
vec3( v.x*v.z*k - v.y, v.y*v.z*k + v.x, v.z*v.z*k + c));
}
// License: Unknown, author: Matt Taylor (https://github.com/64), found: https://64.github.io/tonemapping/
vec3 aces_approx(vec3 v) {
v = max(v, 0.0);
v *= 0.6;
float a = 2.51;
float b = 0.03;
float c = 2.43;
float d = 0.59;
float e = 0.14;
return clamp((v*(a*v+b))/(v*(c*v+d)+e), 0.0, 1.0);
}
float sphere(vec3 p, float r) {
return length(p) - r;
}
// License: MIT, author: Inigo Quilez, found: https://iquilezles.org/articles/distfunctions/
float box(vec2 p, vec2 b) {
vec2 d = abs(p)-b;
return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}
// License: Unknown, author: knighty, found: https://www.shadertoy.com/view/MsKGzw
void poly_fold(inout vec3 pos) {
vec3 p = pos;
for(int i = 0; i < poly_type; ++i){
p.xy = abs(p.xy);
p -= 2.*min(0., dot(p,poly_nc)) * poly_nc;
}
pos = p;
}
float poly_plane(vec3 pos) {
float d0 = dot(pos, poly_pab);
float d1 = dot(pos, poly_pbc);
float d2 = dot(pos, poly_pca);
float d = d0;
d = max(d, d1);
d = max(d, d2);
return d;
}
float poly_corner(vec3 pos) {
float d = length(pos) - .0125;
return d;
}
float dot2(vec3 p) {
return dot(p, p);
}
float poly_edge(vec3 pos) {
float dla = dot2(pos-min(0., pos.x)*vec3(1., 0., 0.));
float dlb = dot2(pos-min(0., pos.y)*vec3(0., 1., 0.));
float dlc = dot2(pos-min(0., dot(pos, poly_nc))*poly_nc);
return sqrt(min(min(dla, dlb), dlc))-2E-3;
}
vec3 shape(vec3 pos, mat3 g_rot) {
pos *= g_rot;
pos /= poly_zoom;
poly_fold(pos);
pos -= poly_p;
return vec3(poly_plane(pos), poly_edge(pos), poly_corner(pos))*poly_zoom;
}
vec3 render0(vec3 ro, vec3 rd) {
vec3 col = vec3(0.0);
float srd = sign(rd.y);
float tp = -(ro.y-6.)/abs(rd.y);
if (srd < 0.) {
col += bottomBoxCol*exp(-0.5*(length((ro + tp*rd).xz)));
}
if (srd > 0.0) {
vec3 pos = ro + tp*rd;
vec2 pp = pos.xz;
float db = box(pp, vec2(5.0, 9.0))-3.0;
col += topBoxCol*rd.y*rd.y*smoothstep(0.25, 0.0, db);
col += 0.2*topBoxCol*exp(-0.5*max(db, 0.0));
col += 0.05*sqrt(topBoxCol)*max(-db, 0.0);
}
col += sunCol/(1.001-dot(sunDir, rd));
return col;
}
float df2(vec3 p, mat3 g_rot, vec2 g_gd) {
vec3 ds = shape(p, g_rot);
float d2 = ds.y-5E-3;
float d0 = min(-ds.x, d2);
float d1 = sphere(p, inner_sphere);
g_gd = min(g_gd, vec2(d2, d1));
float d = (min(d0, d1));
return d;
}
float rayMarch2(vec3 ro, vec3 rd, float tinit, mat3 g_rot, vec2 g_gd) {
float t = tinit;
#if defined(BACKSTEP2)
vec2 dti = vec2(1e10,0.0);
#endif
int i;
for (int i = 0; i < MAX_RAY_MARCHES2; ++i) {
float d = df2(ro + rd*t, g_rot, g_gd);
#if defined(BACKSTEP2)
if (d<dti.x) { dti=vec2(d,t); }
#endif
// Bouncing in a closed shell, will never miss
if (d < TOLERANCE2/* || t > MAX_RAY_LENGTH3 */) {
break;
}
t += d;
}
#if defined(BACKSTEP2)
if(i==MAX_RAY_MARCHES2) { t=dti.y; };
#endif
return t;
}
vec3 normal2(vec3 pos, mat3 g_rot, vec2 g_gd) {
vec2 eps = vec2(NORM_OFF2,0.0);
vec3 nor;
nor.x = df2(pos+eps.xyy, g_rot, g_gd) - df2(pos-eps.xyy, g_rot, g_gd);
nor.y = df2(pos+eps.yxy, g_rot, g_gd) - df2(pos-eps.yxy, g_rot, g_gd);
nor.z = df2(pos+eps.yyx, g_rot, g_gd) - df2(pos-eps.yyx, g_rot, g_gd);
return normalize(nor);
}
vec3 render2(vec3 ro, vec3 rd, float db, mat3 g_rot, vec2 g_gd) {
vec3 agg = vec3(0.0);
float ragg = 1.;
float tagg = 0.;
for (int bounce = 0; bounce < MAX_BOUNCES2; ++bounce) {
if (ragg < 0.1) break;
g_gd = vec2(1E3);
float t2 = rayMarch2(ro, rd, min(db+0.05, 0.3), g_rot, g_gd);
vec2 gd2 = g_gd;
tagg += t2;
vec3 p2 = ro+rd*t2;
vec3 n2 = normal2(p2, g_rot, g_gd);
vec3 r2 = reflect(rd, n2);
vec3 rr2 = refract(rd, n2, rrefr_index);
float fre2= 1.+dot(n2,rd);
vec3 beer = ragg*exp(0.2*beerCol*tagg);
agg += glowCol1*beer*((1.+tagg*tagg*4E-2)*6./max(gd2.x, 5E-4+tagg*tagg*2E-4/ragg));
vec3 ocol = 0.2*beer*render0(p2, rr2);
if (gd2.y <= TOLERANCE2) {
ragg *= 1.-0.9*fre2;
} else {
agg += ocol;
ragg *= 0.8;
}
ro = p2;
rd = r2;
db = gd2.x;
}
return agg;
}
float df3(vec3 p, mat3 g_rot, vec2 g_gd) {
vec3 ds = shape(p, g_rot);
g_gd = min(g_gd, ds.yz);
const float sw = 0.02;
float d1 = min(ds.y, ds.z)-sw;
float d0 = ds.x;
d0 = min(d0, ds.y);
d0 = min(d0, ds.z);
return d0;
}
float rayMarch3(vec3 ro, vec3 rd, float tinit, out int iter, mat3 g_rot, vec2 g_gd) {
float t = tinit;
int i;
for (int i = 0; i < MAX_RAY_MARCHES3; ++i) {
float d = df3(ro + rd*t, g_rot, g_gd);
if (d < TOLERANCE3 || t > MAX_RAY_LENGTH3) {
break;
}
t += d;
}
iter = i;
return t;
}
vec3 normal3(vec3 pos, mat3 g_rot, vec2 g_gd) {
vec2 eps = vec2(NORM_OFF3,0.0);
vec3 nor;
nor.x = df3(pos+eps.xyy, g_rot, g_gd) - df3(pos-eps.xyy, g_rot, g_gd);
nor.y = df3(pos+eps.yxy, g_rot, g_gd) - df3(pos-eps.yxy, g_rot, g_gd);
nor.z = df3(pos+eps.yyx, g_rot, g_gd) - df3(pos-eps.yyx, g_rot, g_gd);
return normalize(nor);
}
vec3 render3(vec3 ro, vec3 rd, mat3 g_rot, vec2 g_gd) {
int iter;
vec3 skyCol = render0(ro, rd);
vec3 col = skyCol;
g_gd = vec2(1E3);
float t1 = rayMarch3(ro, rd, 0.1, iter, g_rot, g_gd);
vec2 gd1 = g_gd;
vec3 p1 = ro+t1*rd;
vec3 n1 = normal3(p1, g_rot, g_gd);
vec3 r1 = reflect(rd, n1);
vec3 rr1 = refract(rd, n1, refr_index);
float fre1= 1.+dot(rd, n1);
fre1 *= fre1;
float ifo = mix(0.5, 1., smoothstep(1.0, 0.9, float(iter)/float(MAX_RAY_MARCHES3)));
if (t1 < MAX_RAY_LENGTH3) {
col = render0(p1, r1)*(0.5+0.5*fre1)*ifo;
vec3 icol = render2(p1, rr1, gd1.x, g_rot, g_gd);
if (gd1.x > TOLERANCE3 && gd1.y > TOLERANCE3 && rr1 != vec3(0.)) {
col += icol*(1.-0.75*fre1)*ifo;
}
}
col += (glowCol0+1.*fre1*(glowCol0))/max(gd1.x, 3E-4);
return col;
}
vec3 effect(vec2 p, vec2 pp, mat3 g_rot, vec2 g_gd) {
const float fov = 2.0;
const vec3 up = vec3(0., 1., 0.);
const vec3 la = vec3(0.0);
const vec3 ww = normalize(normalize(la-rayOrigin));
const vec3 uu = normalize(cross(up, ww));
const vec3 vv = cross(ww, uu);
vec3 rd = normalize(-p.x*uu + p.y*vv + fov*ww);
vec3 col = vec3(0.0);
col = render3(rayOrigin, rd, g_rot, g_gd);
col -= 2E-2*vec3(2.,3.,1.)*(length(p)+0.25);
col = aces_approx(col);
col = sqrt(col);
return col;
}
void fragment() {
vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;
vec2 q = FRAGCOORD.xy/iResolution.xy;
vec2 p = -1. + 2. * q;
vec2 pp = p;
mat3 g_rot;
vec2 g_gd;
p.x *= iResolution.x/iResolution.y;
float a = rotation_speed * TIME;
vec3 r0 = vec3(1.0, sin(vec2(sqrt(0.5), 1.0)*a));
vec3 r1 = vec3(cos(vec2(sqrt(0.5), 1.0)*0.913*a), 1.0);
mat3 rot = rot(normalize(r0), normalize(r1));
g_rot = rot;
vec3 col = effect(p, pp, g_rot, g_gd);
COLOR = vec4(col, 1.0);
}