Travelling through a vast drifting 'Mandelbox.'
Log in to post a comment.
#version 300 es
// Remnant X
// by Dave Hoskins. 2014
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// Thanks to boxplorer and the folks at 'Fractalforums.com'
// HD Video:- https://www.youtube.com/watch?v=BjkK9fLXXo0
precision highp float;
uniform float iTime;
uniform vec2 iResolution;
out vec4 fragColor;
uniform float Time_Slider; // value=0, min=0, max=500, step=0.001
vec3 sunDir = normalize( vec3( 0.35, 0.1, 0.3 ) );
const vec3 sunColour = vec3(1.0, .95, .8);
#define SCALE 2.8
#define MINRAD2 .25
float minRad2 = clamp(MINRAD2, 1.0e-9, 1.0);
#define scale (vec4(SCALE, SCALE, SCALE, abs(SCALE)) / minRad2)
float absScalem1 = abs(SCALE - 1.0);
float AbsScaleRaisedTo1mIters = pow(abs(SCALE), float(1-10));
vec3 surfaceColour1 = vec3(.8, .0, 0.);
vec3 surfaceColour2 = vec3(.4, .4, 0.5);
vec3 surfaceColour3 = vec3(.5, 0.3, 0.00);
vec3 fogCol = vec3(0.4, 0.4, 0.4);
float gTime;
float hash13(vec3 p3)
{
p3 = fract(p3 * .1031);
p3 += dot(p3, p3.zyx + 31.32);
return fract((p3.x + p3.y) * p3.z);
}
//----------------------------------------------------------------------------------------
float Noise(in vec3 p)
{
vec3 i = floor(p);
vec3 f = fract(p);
f *= f * (3.0-2.0*f);
vec2 add = vec2(1,0);
return mix(
mix(mix(hash13(i ), hash13(i + add.xyy),f.x),
mix(hash13(i + add.yxy), hash13(i + add.xxy),f.x),
f.y),
mix(mix(hash13(i + add.yyx), hash13(i + add.xyx),f.x),
mix(hash13(i + add.yxx), hash13(i + add.xxx),f.x),
f.y),
f.z);
}
//----------------------------------------------------------------------------------------
float Map(vec3 pos)
{
vec4 p = vec4(pos,1);
vec4 p0 = p; // p.w is the distance estimate
for (int i = 0; i < 9; i++)
{
p.xyz = clamp(p.xyz, -1.0, 1.0) * 2.0 - p.xyz;
float r2 = dot(p.xyz, p.xyz);
p *= clamp(max(minRad2/r2, minRad2), 0.0, 1.0);
// scale, translate
p = p*scale + p0;
}
return ((length(p.xyz) - absScalem1) / p.w - AbsScaleRaisedTo1mIters);
}
//----------------------------------------------------------------------------------------
vec3 Colour(vec3 pos, float sphereR)
{
vec3 p = pos;
vec3 p0 = p;
float trap = 1.0;
for (int i = 0; i < 6; i++)
{
p.xyz = clamp(p.xyz, -1.0, 1.0) * 2.0 - p.xyz;
float r2 = dot(p.xyz, p.xyz);
p *= clamp(max(minRad2/r2, minRad2), 0.0, 1.0);
p = p*scale.xyz + p0.xyz;
trap = min(trap, r2);
}
// |c.x|: log final distance (fractional iteration count)
// |c.y|: spherical orbit trap at (0,0,0)
vec2 c = clamp(vec2( 0.3333*log(dot(p,p))-1.0, sqrt(trap) ), 0.0, 1.0);
float t = mod(length(pos) - gTime*150., 16.0);
surfaceColour1 = mix( surfaceColour1, vec3(.4, 3.0, 5.), pow(smoothstep(0.0, .3, t) * smoothstep(0.6, .3, t), 10.0));
return mix(mix(surfaceColour1, surfaceColour2, c.y), surfaceColour3, c.x);
}
//----------------------------------------------------------------------------------------
vec3 GetNormal(vec3 pos, float distance)
{
distance *= 0.001+.0001;
vec2 eps = vec2(distance, 0.0);
vec3 nor = vec3(
Map(pos+eps.xyy) - Map(pos-eps.xyy),
Map(pos+eps.yxy) - Map(pos-eps.yxy),
Map(pos+eps.yyx) - Map(pos-eps.yyx));
return normalize(nor);
}
//----------------------------------------------------------------------------------------
float GetSky(vec3 pos)
{
pos *= 2.3;
float t = Noise(pos);
t += Noise(pos * 2.1) * .5;
t += Noise(pos * 4.3) * .25;
t += Noise(pos * 7.9) * .125;
return t;
}
//----------------------------------------------------------------------------------------
float BinarySubdivision(in vec3 rO, in vec3 rD, vec2 t)
{
float halfwayT;
for (int i = 0; i < 6; i++)
{
halfwayT = dot(t, vec2(.5));
float d = Map(rO + halfwayT*rD);
//if (abs(d) < 0.001) break;
t = mix(vec2(t.x, halfwayT), vec2(halfwayT, t.y), step(0.0005, d));
}
return halfwayT;
}
//----------------------------------------------------------------------------------------
vec2 Scene(in vec3 rO, in vec3 rD, in vec2 fragCoord)
{
float t = .05 + 0.05 * hash13(fragCoord.xyx);
vec3 p = vec3(0.0);
float oldT = 0.0;
bool hit = false;
float glow = 0.0;
vec2 dist;
for( int j=0; j < 100; j++ )
{
if (t > 12.0) break;
p = rO + t*rD;
float h = Map(p);
if(h <0.0005)
{
dist = vec2(oldT, t);
hit = true;
break;
}
glow += clamp(.05-h, 0.0, .4);
oldT = t;
t += h + t*0.001;
}
if (!hit)
t = 1000.0;
else t = BinarySubdivision(rO, rD, dist);
return vec2(t, clamp(glow*.25, 0.0, 1.0));
}
//----------------------------------------------------------------------------------------
float Hash(vec2 p)
{
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 33758.5453)-.5;
}
//----------------------------------------------------------------------------------------
vec3 PostEffects(vec3 rgb, vec2 xy)
{
// Gamma first...
// Then...
#define CONTRAST 1.08
#define SATURATION 1.5
#define BRIGHTNESS 1.5
rgb = mix(vec3(.5), mix(vec3(dot(vec3(.2125, .7154, .0721), rgb*BRIGHTNESS)), rgb*BRIGHTNESS, SATURATION), CONTRAST);
// Noise...
//rgb = clamp(rgb+Hash(xy*iTime)*.1, 0.0, 1.0);
// Vignette...
rgb *= .5 + 0.5*pow(20.0*xy.x*xy.y*(1.0-xy.x)*(1.0-xy.y), 0.2);
rgb = pow(rgb, vec3(0.47 ));
return rgb;
}
//----------------------------------------------------------------------------------------
float Shadow( in vec3 ro, in vec3 rd)
{
float res = 1.0;
float t = 0.05;
float h;
for (int i = 0; i < 8; i++)
{
h = Map( ro + rd*t );
res = min(6.0*h / t, res);
t += h;
}
return max(res, 0.0);
}
//----------------------------------------------------------------------------------------
mat3 RotationMatrix(vec3 axis, float angle)
{
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;
return mat3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c);
}
//----------------------------------------------------------------------------------------
vec3 LightSource(vec3 spotLight, vec3 dir, float dis)
{
float g = 0.0;
if (length(spotLight) < dis)
{
g = pow(max(dot(normalize(spotLight), dir), 0.0), 500.0);
}
return vec3(.6) * g;
}
//----------------------------------------------------------------------------------------
vec3 CameraPath( float t )
{
vec3 p = vec3(-.78 + 3. * sin(2.14*t),.05+2.5 * sin(.942*t+1.3),.05 + 3.5 * cos(3.594*t) );
return p;
}
//----------------------------------------------------------------------------------------
void main()
{
float m = (Time_Slider/iResolution.x)* 200.;
gTime = (iTime+m)*.01 + 15.1;
vec2 xy = gl_FragCoord.xy / iResolution.xy;
vec2 uv = (-1.0 + 2.0 * xy) * vec2(iResolution.x/iResolution.y, 1.0);
vec3 cameraPos = CameraPath(gTime);
vec3 camTar = CameraPath(gTime + .01);
float roll = 13.0*sin(gTime*.5+.4);
vec3 cw = normalize(camTar-cameraPos);
vec3 cp = vec3(sin(roll), cos(roll),0.0);
vec3 cu = normalize(cross(cw,cp));
vec3 cv = normalize(cross(cu,cw));
cw = RotationMatrix(cv, sin(-gTime*20.0)*.7) * cw;
vec3 dir = normalize(uv.x*cu + uv.y*cv + 1.3*cw);
vec3 spotLight = CameraPath(gTime + .03) + vec3(sin(gTime*18.4), cos(gTime*17.98), sin(gTime * 22.53))*.2;
vec3 col = vec3(0.0);
vec3 sky = vec3(0.03, .04, .05) * GetSky(dir);
vec2 ret = Scene(cameraPos, dir,gl_FragCoord.xy);
if (ret.x < 900.0)
{
vec3 p = cameraPos + ret.x*dir;
vec3 nor = GetNormal(p, ret.x);
vec3 spot = spotLight - p;
float atten = length(spot);
spot /= atten;
float shaSpot = Shadow(p, spot);
float shaSun = Shadow(p, sunDir);
float bri = max(dot(spot, nor), 0.0) / pow(atten, 1.5) * .15;
float briSun = max(dot(sunDir, nor), 0.0) * .3;
col = Colour(p, ret.x);
col = (col * bri * shaSpot) + (col * briSun* shaSun);
vec3 ref = reflect(dir, nor);
col += pow(max(dot(spot, ref), 0.0), 10.0) * 2.0 * shaSpot * bri;
col += pow(max(dot(sunDir, ref), 0.0), 10.0) * 2.0 * shaSun * bri;
}
col = mix(sky, col, min(exp(-ret.x+1.5), 1.0));
col += vec3(pow(abs(ret.y), 2.)) * vec3(.02, .04, .1);
col += LightSource(spotLight-cameraPos, dir, ret.x);
col = PostEffects(col, xy);
fragColor=vec4(col,1.0);
}
//--------------------------------------------------------------------------