466 lines
11 KiB
GLSL
466 lines
11 KiB
GLSL
// https://www.shadertoy.com/view/WtXyW4
|
|
|
|
// License CC0: Alien Waterworld
|
|
// Been working on space themed shaders
|
|
// Code "borrowed" from the usual suspects
|
|
|
|
#define PI 3.141592654
|
|
#define TAU (2.0*PI)
|
|
|
|
#define TOLERANCE 0.00001
|
|
#define MAX_ITER 55
|
|
#define MAX_DISTANCE 31.0
|
|
#define PERIOD 45.0
|
|
#define TIME mod(iTime, PERIOD)
|
|
|
|
const vec3 skyCol1 = vec3(0.35, 0.45, 0.6);
|
|
const vec3 skyCol2 = skyCol1*skyCol1*skyCol1*3.0;
|
|
const vec3 sunCol1 = vec3(1.0,0.9,0.8);
|
|
const vec3 sunCol2 = vec3(1.0,0.9,0.8);
|
|
const vec3 smallSunCol1 = vec3(1.0,0.5,0.25)*0.5;
|
|
const vec3 smallSunCol2 = vec3(1.0,0.5,0.25)*0.5;
|
|
const vec3 ringColor = sqrt(vec3(0.95, 0.65, 0.45));
|
|
const vec4 planet = vec4(80.0, -20.0, 100.0, 50.0)*1000.0;
|
|
const vec3 planetCol = sqrt(vec3(0.9, 0.8, 0.7));
|
|
const vec3 ringsNormal = normalize(vec3(1.0, 1.25, 0.0));
|
|
const vec4 rings = vec4(ringsNormal, -dot(ringsNormal, planet.xyz));
|
|
|
|
void rot(inout vec2 p, float a) {
|
|
float c = cos(a);
|
|
float s = sin(a);
|
|
p = vec2(p.x*c + p.y*s, -p.x*s + p.y*c);
|
|
}
|
|
|
|
float psin(float f) {
|
|
return 0.5 + 0.5*sin(f);
|
|
}
|
|
|
|
vec2 toRect(vec2 p) {
|
|
return p.x*vec2(cos(p.y), sin(p.y));
|
|
}
|
|
|
|
vec2 toPolar(vec2 p) {
|
|
return vec2(length(p), atan(p.y, p.x));
|
|
}
|
|
|
|
float mod1(inout float p, float size) {
|
|
float halfsize = size*0.5;
|
|
float c = floor((p + halfsize)/size);
|
|
p = mod(p + halfsize, size) - halfsize;
|
|
return c;
|
|
}
|
|
|
|
float circle(vec2 p, float r) {
|
|
return length(p) - r;
|
|
}
|
|
|
|
float rayPlane(vec3 ro, vec3 rd, vec4 p) {
|
|
return -(dot(ro,p.xyz)+p.w)/dot(rd,p.xyz);
|
|
}
|
|
|
|
vec2 raySphere(vec3 ro, vec3 rd, vec4 sphere)
|
|
{
|
|
vec3 ce = sphere.xyz;
|
|
float ra = sphere.w;
|
|
vec3 oc = ro - ce;
|
|
float b = dot( oc, rd );
|
|
float c = dot( oc, oc ) - ra*ra;
|
|
float h = b*b - c;
|
|
if( h<0.0 ) return vec2(-1.0); // no intersection
|
|
h = sqrt( h );
|
|
return vec2( -b-h, -b+h );
|
|
}
|
|
|
|
float hash(in vec2 co) {
|
|
return fract(sin(dot(co.xy ,vec2(12.9898,58.233))) * 13758.5453);
|
|
}
|
|
|
|
|
|
float noise2(vec2 x) {
|
|
vec2 i = floor(x);
|
|
vec2 w = fract(x);
|
|
|
|
#if 1
|
|
// quintic interpolation
|
|
vec2 u = w*w*w*(w*(w*6.0-15.0)+10.0);
|
|
#else
|
|
// cubic interpolation
|
|
vec2 u = w*w*(3.0-2.0*w);
|
|
#endif
|
|
|
|
float a = hash(i+vec2(0.0,0.0));
|
|
float b = hash(i+vec2(1.0,0.0));
|
|
float c = hash(i+vec2(0.0,1.0));
|
|
float d = hash(i+vec2(1.0,1.0));
|
|
|
|
float k0 = a;
|
|
float k1 = b - a;
|
|
float k2 = c - a;
|
|
float k3 = d - c + a - b;
|
|
|
|
return k0 + k1*u.x + k2*u.y + k3*u.x*u.y;
|
|
}
|
|
|
|
float smoother(float d, float s) {
|
|
return s*tanh(d/s);
|
|
}
|
|
|
|
float heightMod(vec2 p) {
|
|
vec2 pp = toPolar(p);
|
|
pp.y += -pp.x*0.2;
|
|
p = toRect(pp);
|
|
return pow((psin(1.0*p.x)*psin(1.0*p.y)), max(0.25, pp.x*0.20))*0.8;
|
|
}
|
|
|
|
float loheight(vec2 p, float d) {
|
|
const float aa = 0.5;
|
|
const float ff = 2.03;
|
|
const float tt = 1.3;
|
|
const float oo = 0.93;
|
|
|
|
float hm = heightMod(p);
|
|
|
|
vec2 s = vec2(0.0);
|
|
float a = 1.0;
|
|
float o = 0.2;
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
float nn = a*(noise2(2.0*p));
|
|
s.x += nn;
|
|
s.y += abs(a);
|
|
p += o;
|
|
a *= aa;
|
|
p *= ff;
|
|
o *= oo;
|
|
rot(p, tt);
|
|
}
|
|
|
|
s.x /= s.y;
|
|
s.x -= 1.0;
|
|
s.x += 0.7*hm;
|
|
s.x = smoother(s.x, 0.125);
|
|
|
|
return max(s.x+0.125, 0.0)*0.5;
|
|
}
|
|
|
|
float height(vec2 p, float d) {
|
|
const float aa = 0.5;
|
|
const float ff = 2.03;
|
|
const float tt = 1.3;
|
|
const float oo = 0.93;
|
|
|
|
float hm = heightMod(p);
|
|
|
|
vec2 s = vec2(0.0);
|
|
float a = 1.0;
|
|
float o = 0.2;
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
float nn = a*(noise2(2.0*p));
|
|
s.x += nn;
|
|
s.y += abs(a);
|
|
p += o;
|
|
a *= aa;
|
|
p *= ff;
|
|
o *= oo;
|
|
rot(p, tt);
|
|
}
|
|
|
|
s.x /= s.y;
|
|
s.x -= 1.0;
|
|
s.x += 0.7*hm;
|
|
s.x = smoother(s.x, 0.125);
|
|
|
|
return max(s.x+0.125, 0.0)*0.5;
|
|
}
|
|
|
|
float hiheight(vec2 p, float d) {
|
|
const float aa = 0.5;
|
|
const float ff = 2.03;
|
|
const float tt = 1.3;
|
|
const float oo = 0.93;
|
|
|
|
float hm = heightMod(p);
|
|
|
|
vec2 s = vec2(0.0);
|
|
float a = 1.0;
|
|
float o = 0.2;
|
|
|
|
for (int i = 0; i < 6; ++i) {
|
|
float nn = a*(noise2(2.0*p));
|
|
s.x += nn;
|
|
s.y += abs(a);
|
|
p += o;
|
|
a *= aa;
|
|
p *= ff;
|
|
o *= oo;
|
|
rot(p, tt);
|
|
}
|
|
|
|
s.x /= s.y;
|
|
s.x -= 1.0;
|
|
s.x += 0.7*hm;
|
|
s.x = smoother(s.x, 0.125);
|
|
|
|
return max(s.x+0.125, 0.0)*0.5;
|
|
}
|
|
|
|
vec3 normal(vec2 p, float d) {
|
|
vec2 eps = vec2(0.000125, 0.0);
|
|
|
|
vec3 n;
|
|
|
|
n.x = (hiheight(p - eps.xy, d) - hiheight(p + eps.xy, d));
|
|
n.y = 2.0*eps.x;
|
|
n.z = (hiheight(p - eps.yx, d) - hiheight(p + eps.yx, d));
|
|
|
|
return normalize(n);
|
|
}
|
|
|
|
float march(vec3 ro, vec3 rd, float id, out int max_iter) {
|
|
float dt = 0.1;
|
|
float d = id;
|
|
int currentStep = 0;
|
|
float lastd = d;
|
|
for (int i = 0; i < MAX_ITER; ++i) {
|
|
vec3 p = ro + d*rd;
|
|
float h = height(p.xz, d);
|
|
|
|
if (d > MAX_DISTANCE) {
|
|
max_iter = i;
|
|
return MAX_DISTANCE;
|
|
}
|
|
|
|
float hd = p.y - h;
|
|
|
|
if (hd < TOLERANCE) {
|
|
return d;
|
|
}
|
|
|
|
float sl = 0.9;
|
|
|
|
dt = max(hd*sl, TOLERANCE+0.0005*d);
|
|
lastd = d;
|
|
d += dt;
|
|
}
|
|
|
|
max_iter = MAX_ITER;
|
|
return MAX_DISTANCE;
|
|
}
|
|
|
|
vec3 sunDirection() {
|
|
return normalize(vec3(-0.5, 0.2, 1.0));
|
|
}
|
|
|
|
vec3 smallSunDirection() {
|
|
return normalize(vec3(-0.2, -0.05, 1.0));
|
|
}
|
|
|
|
vec3 skyColor(vec3 ro, vec3 rd) {
|
|
vec3 sunDir = sunDirection();
|
|
vec3 smallSunDir = smallSunDirection();
|
|
|
|
float sunDot = max(dot(rd, sunDir), 0.0);
|
|
float smallSunDot = max(dot(rd, smallSunDir), 0.0);
|
|
|
|
float angle = atan(rd.y, length(rd.xz))*2.0/PI;
|
|
|
|
vec3 sunCol = 0.5*sunCol1*pow(sunDot, 20.0) + 8.0*sunCol2*pow(sunDot, 2000.0);
|
|
vec3 smallSunCol = 0.5*smallSunCol1*pow(smallSunDot, 200.0) + 8.0*smallSunCol2*pow(smallSunDot, 20000.0);
|
|
|
|
|
|
vec2 si = raySphere(ro, rd, planet);
|
|
float pi = rayPlane(ro, rd, rings);
|
|
|
|
float dustTransparency = smoothstep(-0.15, 0.075, rd.y);
|
|
|
|
vec3 skyCol = mix(skyCol1, skyCol2, sqrt(dustTransparency));
|
|
skyCol *= (1.0-dustTransparency);
|
|
|
|
|
|
vec3 planetSurface = ro + si.x*rd;
|
|
vec3 planetNormal = normalize(planetSurface - planet.xyz);
|
|
float planetDiff = max(dot(planetNormal, sunDir), 0.0);
|
|
float planetBorder = max(dot(planetNormal, -rd), 0.0);
|
|
float planetLat = (planetSurface.x+planetSurface.y)*0.0005;
|
|
vec3 planetCol = mix(1.3*planetCol, 0.3*planetCol, pow(psin(planetLat+1.0)*psin(sqrt(2.0)*planetLat+2.0)*psin(sqrt(3.5)*planetLat+3.0), 0.5));
|
|
|
|
vec3 ringsSurface = ro + pi*rd;
|
|
|
|
float borderTransparency = smoothstep(0.0, 0.1, planetBorder);
|
|
|
|
float ringsDist = length(ringsSurface - planet.xyz)*1.0;
|
|
float ringsPeriod = ringsDist*0.001;
|
|
const float ringsMax = 150000.0*0.655;
|
|
const float ringsMin = 100000.0*0.666;
|
|
float ringsMul = pow(psin(ringsPeriod+1.0)*psin(sqrt(0.5)*ringsPeriod+2.0)*psin(sqrt(0.45)*ringsPeriod+4.0)*psin(sqrt(0.35)*ringsPeriod+5.0), 0.25);
|
|
float ringsMix = psin(ringsPeriod*10.0)*psin(ringsPeriod*10.0*sqrt(2.0))*(1.0 - smoothstep(50000.0, 200000.0, pi));
|
|
|
|
vec3 ringsCol = mix(vec3(0.125), 0.75*ringColor, ringsMix)*step(-pi, 0.0)*step(ringsDist, ringsMax)*step(-ringsDist, -ringsMin)*ringsMul;
|
|
|
|
vec3 final = vec3(0.0);
|
|
|
|
final += ringsCol*(step(pi, si.x) + step(si.x, 0.0));
|
|
|
|
final += step(0.0, si.x)*pow(planetDiff, 0.75)*mix(planetCol, ringsCol, 0.0)*dustTransparency*borderTransparency + ringsCol*(1.0 - borderTransparency);
|
|
|
|
final += skyCol + sunCol + smallSunCol;
|
|
|
|
return final;
|
|
}
|
|
|
|
vec3 shipColor(vec2 p) {
|
|
vec2 pp = toPolar(p);
|
|
pp.y += pp.x*0.05;
|
|
p = toRect(pp);
|
|
|
|
float n = mod1(p.x, 0.15);
|
|
p.y += 3.0-TIME*0.5+0.05*abs(n*n);
|
|
|
|
float td = abs(p.x) - (0.005-p.y*0.002);
|
|
td = abs(td) - (0.02*pow(-p.y, 0.25));
|
|
float sd = circle(p, 0.05);
|
|
|
|
vec3 trailCol = vec3(0.5)*smoothstep(-5.0, 0.0, p.y)*step(p.y, 0.0)*smoothstep(0.0, 0.025, -td);
|
|
vec3 shipCol = vec3(0.5+smoothstep(-1.0, 1.0, sin(TIME*15.0*TAU+n)))*smoothstep(0.0, 0.075, -sd);
|
|
|
|
vec3 col = trailCol;
|
|
col += shipCol;
|
|
|
|
float sm = step(abs(n), 2.0);
|
|
|
|
return col*sm;
|
|
}
|
|
|
|
vec3 getColor(vec3 ro, vec3 rd) {
|
|
int max_iter = 0;
|
|
vec3 skyCol = skyColor(ro, rd);
|
|
vec3 col = vec3(0);
|
|
|
|
const float shipHeight = 1.0;
|
|
const float seaHeight = 0.0;
|
|
const float cloudHeight = 0.2;
|
|
const float upperCloudHeight = 0.5;
|
|
|
|
float id = (cloudHeight - ro.y)/rd.y;
|
|
|
|
if (id > 0.0) {
|
|
float d = march(ro, rd, id, max_iter);
|
|
vec3 sunDir = sunDirection();
|
|
vec3 osunDir = sunDir*vec3(-1.0, 1.0, -1.0);
|
|
vec3 p = ro + d*rd;
|
|
|
|
float loh = loheight(p.xz, d);
|
|
float loh2 = loheight(p.xz+sunDir.xz*0.05, d);
|
|
float hih = hiheight(p.xz, d);
|
|
vec3 normal = normal(p.xz, d);
|
|
|
|
float ud = (upperCloudHeight - 4.0*loh - ro.y)/rd.y;
|
|
|
|
float sd = (seaHeight - ro.y)/rd.y;
|
|
vec3 sp = ro + sd*rd;
|
|
float scd = (cloudHeight - sp.y)/sunDir.y;
|
|
vec3 scp = sp + sunDir*scd;
|
|
|
|
float sloh = loheight(scp.xz, d);
|
|
float cshd = exp(-15.0*sloh);
|
|
|
|
float amb = 0.3;
|
|
|
|
vec3 seaNormal = normalize(vec3(0.0, 1.0, 0.0));
|
|
vec3 seaRef = reflect(rd, seaNormal);
|
|
vec3 seaCol = .25*skyColor(p, seaRef);
|
|
seaCol += pow(max(dot(seaNormal, sunDir), 0.0), 2.0);
|
|
seaCol *= cshd;
|
|
seaCol += 0.075*pow(vec3(0.1, 1.3, 4.0), vec3(max(dot(seaNormal, seaRef), 0.0)));
|
|
|
|
float spe = pow(max(dot(sunDir, reflect(rd, normal)), 0.0), 3.0);
|
|
float fre = pow(1.0-dot(normal, -rd), 2.0);
|
|
|
|
col = seaCol;
|
|
|
|
|
|
const float level = 0.00;
|
|
const float level2 = 0.3;
|
|
// REALLY fake shadows and lighting
|
|
vec3 scol = sunCol1*(smoothstep(level, level2, hih) - smoothstep(level, level2, loh2));
|
|
col = mix(vec3(1.0), col, exp(-17.0*(hih-0.25*loh)));
|
|
col = mix(vec3(.75), col, exp(-10.0*loh*(max(d-ud, 0.0))));
|
|
col += scol;
|
|
|
|
col += vec3(0.5)*spe*fre;
|
|
|
|
float ssd = (shipHeight - ro.y)/rd.y;
|
|
|
|
col += shipColor((ro + rd*ssd).xz);
|
|
|
|
col = mix(col, skyCol, smoothstep(0.5*MAX_DISTANCE, 1.*MAX_DISTANCE, d));
|
|
|
|
} else {
|
|
col = skyCol;
|
|
}
|
|
|
|
// col += vec3(1.1, 0.0, 0.0)* smoothstep(0.25, 1.0,(float(max_iter)/float(MAX_ITER)));
|
|
return col;
|
|
}
|
|
|
|
vec3 postProcess(in vec3 col, in vec2 q)
|
|
{
|
|
//col = saturate(col);
|
|
col=pow(clamp(col,0.0,1.0),vec3(0.75));
|
|
col=col*0.6+0.4*col*col*(3.0-2.0*col); // contrast
|
|
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4); // satuation
|
|
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7); // vigneting
|
|
return col;
|
|
}
|
|
|
|
vec3 getSample1(vec2 p, float time) {
|
|
vec3 ro = vec3(0.5, 5.5, -2.0);
|
|
vec3 la = ro + vec3(0.0, -1.+0.9*TIME/PERIOD, 1.0);
|
|
|
|
vec3 ww = normalize(la - ro);
|
|
vec3 uu = normalize(cross(vec3(0.0,1.0,0.0), ww));
|
|
vec3 vv = normalize(cross(ww, uu));
|
|
vec3 rd = normalize(p.x*uu + p.y*vv + 2.0*ww);
|
|
|
|
vec3 col = getColor(ro, rd) ;
|
|
|
|
return col;
|
|
|
|
}
|
|
|
|
vec3 getSample2(vec2 p, float time) {
|
|
p.y-=time*0.25;
|
|
float h = height(p, 0.0);
|
|
vec3 n = normal(p, 0.0);
|
|
|
|
vec3 lp = vec3(10.0, -1.2, 0.0);
|
|
|
|
vec3 ld = normalize(vec3(p.x, h, p.y)- lp);
|
|
|
|
float d = max(dot(ld, n), 0.0);
|
|
|
|
vec3 col = vec3(0.0);
|
|
|
|
col = vec3(1.0)*(h+0.1);
|
|
col += vec3(1.5)*pow(d, 0.75);
|
|
|
|
return col;
|
|
|
|
}
|
|
|
|
void mainImage(out vec4 fragColor, vec2 fragCoord) {
|
|
vec2 q = fragCoord.xy/iResolution.xy;
|
|
vec2 p = -1.0 + 2.0*q;
|
|
p.x *= iResolution.x/iResolution.y;
|
|
|
|
vec3 col = getSample1(p, TIME);
|
|
|
|
col = postProcess(col, q);
|
|
|
|
col *= smoothstep(0.0, 2.0, TIME);
|
|
col *= 1.0-smoothstep(PERIOD-2.0, PERIOD, TIME);
|
|
|
|
fragColor = vec4(col, 1.0);
|
|
}
|