Fractal Marble
Log in to post a comment.
precision highp float;
uniform float iTime;
uniform vec2 iResolution;
uniform float offset; // value=0, min=0, max=1, step=0.001
uniform float scale; // value=0.1, min=0.05, max=0.2, step=0.001
uniform float angle; // value=-0.85, min=-1, max=1, step=0.001
uniform float fracParam; // value=0.85, min=0.45, max=0.88, step=0.001
// Hash without Sine by David Hoskins
// https://www.shadertoy.com/view/4djSRW
float hash13(vec3 p3) {
p3 = fract(p3 * .1031);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
mat2 rot(float a) {
return mat2(cos(a),sin(a),-sin(a),cos(a));
}
float map(in vec3 p) {
float a = 0.;
p.zy *= rot(p.x * angle);
vec3 c = p;
for (int i = 0; i < 9; ++i) {
// p = fracParam * abs(p)/dot(p,p) - fracParam;
p = fracParam * abs(normalize(p)) - fracParam;
p.xy = vec2(p.x*p.x - p.y*p.y, 2.*p.y*p.x);
p = p.yzx;
// smooth blending, see: http://www.fractalforums.com/3d-fractal-generation/kaliset-3d-fractal-used-as-coloring-and-bump-mapping-for-de-systems/
a += exp2(-20. * abs(dot(p, c)));
// a += exp2(-20. * abs(dot(p, vec3(.5))));
// a += exp2(-20. * abs(length(p) -.5));
}
return a;
}
vec3 iSphere( in vec3 ro, in vec3 rd ) {
vec3 oc = ro;
float b = dot( oc, rd );
float c = dot( oc, oc ) - 1.;
float h = b*b - c;
float d = sqrt( max(0.0,1.-h)) - 1.;
h = sqrt(max(0., h));
return vec3(d, -b-h, -b+h );
}
vec3 getCol( float t ) {
return .5 + .5 * cos(6.28318 * t + vec3(0.0, 0.6, 1.2));
}
vec4 march( in vec3 ro, vec3 rd, float maxDist ) {
float d = 0., c = 0.;
float dt = 0.05;
// scale
ro *= 2.;
maxDist *= 2.;
// rotate
ro.xz*=rot(0.1*iTime);
ro.yz*=rot(0.2);
rd.xz*=rot(0.1*iTime);
rd.yz*=rot(0.2);
vec3 col= vec3(0.);
vec4 sum = vec4(0.0);
for( int i=0; i<64; i++ ) {
d += dt * exp2(-2. * c);
if( d > maxDist) {
return sum;
}
vec3 pos = ro+d*rd;
c = map(pos);
vec3 col = getCol(c*scale + offset) * sqrt(length(pos) * .5 + 0.01);
// blend front to back
// float a = min(0.2*dt*(c),1.) *(1.0-sum.a); // clear glass
float a = min(0.2*dt*sqrt(c),1.) *(1.0-sum.a); // milky glass
sum += vec4(col * a, a);
}
return sum;
}
void main() {
const float N = 1./1.45;
const vec3 L = normalize(vec3(.5, -1., .2));
vec2 p = (2. * gl_FragCoord.xy - iResolution) / iResolution.y;
vec3 ro = vec3(0., 0., 2.5);
vec3 rd = normalize( vec3(p.x, p.y, -1.8) );
vec3 isp = iSphere( ro, rd );
vec3 bgCol = vec3(0);
vec3 col = bgCol;
float s = max( 0.0, isp.x/isp.y );
float px = 3.6/iResolution.y;
if (s < px) {
vec3 pos0 = ro+isp.y*rd;
vec3 nor0 = pos0;
vec3 rfr0 = refract(rd, nor0, N);
vec3 isp0 = iSphere(pos0, rfr0);
vec4 data = march(pos0, rfr0, isp0.z - isp0.y);
col = data.rgb * data.rgb * 20.;
float diff = .5 - .5 *dot(L, nor0);
col *= diff ;
col = mix(bgCol, col, data.a);
vec3 rfl0 = reflect(rd, nor0);
float fre0 = .15 + (1. - .15) * pow(clamp(1. + dot(nor0, rd), 0., 1.), 5.);
float spec0 = pow(max(dot(reflect(-L, nor0), rd), 0.0), 64.);
col *= 1.-fre0;
col += (.05 * smoothstep(-.1, .2, rfl0.y ) + spec0 * 5. ) * fre0;
// refraction out
vec3 pos1 = pos0 + isp0.z * rfr0;
vec3 nor1 = -pos1;
vec3 rfr1 = refract(rfr0, nor1, 1./N);
float fre1 = .15 + (1. - .15) * pow(clamp(1. + dot(nor1,-rfr0), 0., 1.), 5.);
float spec1 = pow(max(dot(reflect(-L, nor1), rfr1), 0.0), 64.);
col += ((.1 * smoothstep(-.1, .2, rfr1.y ) + (spec1 * .6)) * (1.-fre0) * fre1 * (1. - data.a) * (1. - data.a)) * getCol(.75*scale + offset);
col = mix(col, bgCol, clamp(s/px, 0., 1.));
}
col = max( vec3(0), col - 0.004);
col = (col*(6.2*col + .5)) / (col*(6.2*col+1.7) + 0.06);
col += 4./255. * (hash13(vec3(gl_FragCoord.xy, iTime)) - .5);
gl_FragColor = vec4(max(vec3(0), col), 1.0 );
}