Skip to content

Instantly share code, notes, and snippets.

@opless
Created April 24, 2016 19:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save opless/5dfc31bc2876fc1a7f24e8bf8a8630c6 to your computer and use it in GitHub Desktop.
Save opless/5dfc31bc2876fc1a7f24e8bf8a8630c6 to your computer and use it in GitHub Desktop.
// Planet Shadertoy. Created by Reinder Nijhoff 2015
// @reindernijhoff
//
// https://www.shadertoy.com/view/4tjGRh
//
//#define HIGH_QUALITY
//#define MED_QUALITY
//#define LOW_QUALITY
#define VERY_LOW_QUALITY
const float PI = 3.14159265359;
const float DEG_TO_RAD = (PI / 180.0);
const float MAX = 10000.0;
const float EARTH_RADIUS = 1000.;
const float EARTH_ATMOSPHERE = 5.;
const float EARTH_CLOUDS = 1.;
const float RING_INNER_RADIUS = 1500.;
const float RING_OUTER_RADIUS = 2300.;
const float RING_HEIGHT = 2.;
#ifdef HIGH_QUALITY
const int SEA_NUM_STEPS = 7;
const int TERRAIN_NUM_STEPS = 140;
const int ASTEROID_NUM_STEPS = 11;
const int ASTEROID_NUM_BOOL_SUB = 7;
const int RING_VOXEL_STEPS = 25;
const float ASTEROID_MAX_DISTANCE = 1.1;
const int FBM_STEPS = 4;
const int ATMOSPHERE_NUM_OUT_SCATTER = 5;
const int ATMOSPHERE_NUM_IN_SCATTER = 7;
#define DISPLAY_LLAMEL
#define DISPLAY_CLOUDS
#define DISPLAY_CLOUDS_DETAIL
#define DISPLAY_TERRAIN_DETAIL
#endif
#ifdef MED_QUALITY
const int SEA_NUM_STEPS = 6;
const int TERRAIN_NUM_STEPS = 100;
const int ASTEROID_NUM_STEPS = 10;
const int ASTEROID_NUM_BOOL_SUB = 6;
const int RING_VOXEL_STEPS = 24;
const float ASTEROID_MAX_DISTANCE = 1.;
const int FBM_STEPS = 4;
const int ATMOSPHERE_NUM_OUT_SCATTER = 4;
const int ATMOSPHERE_NUM_IN_SCATTER = 6;
#define DISPLAY_CLOUDS
#define DISPLAY_TERRAIN_DETAIL
#define DISPLAY_CLOUDS_DETAIL
#endif
#ifdef LOW_QUALITY
const int SEA_NUM_STEPS = 5;
const int TERRAIN_NUM_STEPS = 75;
const int ASTEROID_NUM_STEPS = 9;
const int ASTEROID_NUM_BOOL_SUB = 5;
const int RING_VOXEL_STEPS = 20;
const float ASTEROID_MAX_DISTANCE = .85;
const int FBM_STEPS = 3;
const int ATMOSPHERE_NUM_OUT_SCATTER = 3;
const int ATMOSPHERE_NUM_IN_SCATTER = 5;
#endif
#ifdef VERY_LOW_QUALITY
const int SEA_NUM_STEPS = 4;
const int TERRAIN_NUM_STEPS = 60;
const int ASTEROID_NUM_STEPS = 7;
const int ASTEROID_NUM_BOOL_SUB = 4;
const int RING_VOXEL_STEPS = 16;
const float ASTEROID_MAX_DISTANCE = .67;
const int FBM_STEPS = 3;
const int ATMOSPHERE_NUM_OUT_SCATTER = 2;
const int ATMOSPHERE_NUM_IN_SCATTER = 4;
#define HIDE_TERRAIN
#endif
const vec3 SUN_DIRECTION = vec3( .940721, .28221626, .18814417 );
const vec3 SUN_COLOR = vec3(.3, .21, .165);
float time;
//-----------------------------------------------------
// Noise functions
//-----------------------------------------------------
float hash( const in float n ) {
return fract(sin(n)*43758.5453123);
}
float hash( const in vec2 p ) {
float h = dot(p,vec2(127.1,311.7));
return fract(sin(h)*43758.5453123);
}
float hash( const in vec3 p ) {
float h = dot(p,vec3(127.1,311.7,758.5453123));
return fract(sin(h)*43758.5453123);
}
vec3 hash31( const in float p) {
vec3 h = vec3(1275.231,4461.7,7182.423) * p;
return fract(sin(h)*43758.543123);
}
vec3 hash33( const in vec3 p) {
return vec3( hash(p), hash(p.zyx), hash(p.yxz) );
}
float noise( const in float p ) {
float i = floor( p );
float f = fract( p );
float u = f*f*(3.0-2.0*f);
return -1.0+2.0* mix( hash( i + 0. ), hash( i + 1. ), u);
}
float noise( const in vec2 p ) {
vec2 i = floor( p );
vec2 f = fract( p );
vec2 u = f*f*(3.0-2.0*f);
return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ),
hash( i + vec2(1.0,0.0) ), u.x),
mix( hash( i + vec2(0.0,1.0) ),
hash( i + vec2(1.0,1.0) ), u.x), u.y);
}
float noise( const in vec3 x ) {
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
float n = p.x + p.y*157.0 + 113.0*p.z;
return mix(mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x),
mix( hash(n+157.0), hash(n+158.0),f.x),f.y),
mix(mix( hash(n+113.0), hash(n+114.0),f.x),
mix( hash(n+270.0), hash(n+271.0),f.x),f.y),f.z);
}
float tri( const in vec2 p ) {
return 0.5*(cos(6.2831*p.x) + cos(6.2831*p.y));
}
const mat2 m2 = mat2( 0.80, -0.60, 0.60, 0.80 );
float fbm( in vec2 p ) {
float f = 0.0;
f += 0.5000*noise( p ); p = m2*p*2.02;
f += 0.2500*noise( p ); p = m2*p*2.03;
f += 0.1250*noise( p );
#ifndef LOW_QUALITY
#ifndef VERY_LOW_QUALITY
p = m2*p*2.01;
f += 0.0625*noise( p );
#endif
#endif
return f/0.9375;
}
float fbm( const in vec3 p, const in float a, const in float f) {
float ret = 0.0;
float amp = 1.0;
float frq = 1.0;
for(int i = 0; i < FBM_STEPS; i++) {
float n = pow(noise(p * frq),2.0);
ret += n * amp;
frq *= f;
amp *= a * (pow(n,0.2));
}
return ret;
}
//-----------------------------------------------------
// Lightning functions
//-----------------------------------------------------
float diffuse( const in vec3 n, const in vec3 l) {
return clamp(dot(n,l),0.,1.);
}
float specular( const in vec3 n, const in vec3 l, const in vec3 e, const in float s) {
float nrm = (s + 8.0) / (3.1415 * 8.0);
return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}
float fresnel( const in vec3 n, const in vec3 e, float s ) {
return pow(clamp(1.-dot(n,e), 0., 1.),s);
}
//-----------------------------------------------------
// Math functions
//-----------------------------------------------------
vec2 rotate(float angle, vec2 v) {
return vec2(cos(angle) * v.x + sin(angle) * v.y, cos(angle) * v.y - sin(angle) * v.x);
}
float boolSub(float a,float b) {
return max(a,-b);
}
float sphere(vec3 p,float r) {
return length(p)-r;
}
//-----------------------------------------------------
// Intersection functions (by iq)
//-----------------------------------------------------
vec3 nSphere( in vec3 pos, in vec4 sph ) {
return (pos-sph.xyz)/sph.w;
}
float iSphere( in vec3 ro, in vec3 rd, in vec4 sph ) {
vec3 oc = ro - sph.xyz;
float b = dot( oc, rd );
float c = dot( oc, oc ) - sph.w*sph.w;
float h = b*b - c;
if( h<0.0 ) return -1.0;
return -b - sqrt( h );
}
float iCSphereF( vec3 p, vec3 dir, float r ) {
float b = dot( p, dir );
float c = dot( p, p ) - r * r;
float d = b * b - c;
if ( d < 0.0 ) return -MAX;
return -b + sqrt( d );
}
vec2 iCSphere2( vec3 p, vec3 dir, float r ) {
float b = dot( p, dir );
float c = dot( p, p ) - r * r;
float d = b * b - c;
if ( d < 0.0 ) return vec2( MAX, -MAX );
d = sqrt( d );
return vec2( -b - d, -b + d );
}
vec3 nPlane( in vec3 ro, in vec4 obj ) {
return obj.xyz;
}
float iPlane( in vec3 ro, in vec3 rd, in vec4 pla ) {
return (-pla.w - dot(pla.xyz,ro)) / dot( pla.xyz, rd );
}
//-----------------------------------------------------
// Wet stone by TDM
//
// https://www.shadertoy.com/view/ldSSzV
//-----------------------------------------------------
const float ASTEROID_TRESHOLD = 0.001;
const float ASTEROID_EPSILON = 1e-6;
const float ASTEROID_DISPLACEMENT = 0.1;
const float ASTEROID_RADIUS = 0.13;
const vec3 RING_COLOR_1 = vec3(0.42,0.3,0.2);
const vec3 RING_COLOR_2 = vec3(0.51,0.41,0.32) * 0.2;
float asteroidRock( const in vec3 p, const in vec3 id ) {
float d = sphere(p,ASTEROID_RADIUS);
for(int i = 0; i < ASTEROID_NUM_BOOL_SUB; i++) {
float ii = float(i)+id.x;
float r = (ASTEROID_RADIUS*2.5) + ASTEROID_RADIUS*hash(ii);
vec3 v = normalize(hash31(ii) * 2.0 - 1.0);
d = boolSub(d,sphere(p+v*r,r * 0.8));
}
return d;
}
float asteroidMap( const in vec3 p, const in vec3 id) {
float d = asteroidRock(p, id) + noise(p*4.0) * ASTEROID_DISPLACEMENT;
return d;
}
float asteroidMapDetailed( const in vec3 p, const in vec3 id) {
float d = asteroidRock(p, id) + fbm(p*4.0,0.4,2.96) * ASTEROID_DISPLACEMENT;
return d;
}
void asteroidTransForm(inout vec3 ro, const in vec3 id ) {
float xyangle = (id.x-.5)*time*2.;
ro.xy = rotate( xyangle, ro.xy );
float yzangle = (id.y-.5)*time*2.;
ro.yz = rotate( yzangle, ro.yz );
}
void asteroidUnTransForm(inout vec3 ro, const in vec3 id ) {
float yzangle = (id.y-.5)*time*2.;
ro.yz = rotate( -yzangle, ro.yz );
float xyangle = (id.x-.5)*time*2.;
ro.xy = rotate( -xyangle, ro.xy );
}
vec3 asteroidGetNormal(vec3 p, vec3 id) {
asteroidTransForm( p, id );
vec3 n;
n.x = asteroidMapDetailed(vec3(p.x+ASTEROID_EPSILON,p.y,p.z), id);
n.y = asteroidMapDetailed(vec3(p.x,p.y+ASTEROID_EPSILON,p.z), id);
n.z = asteroidMapDetailed(vec3(p.x,p.y,p.z+ASTEROID_EPSILON), id);
n = normalize(n-asteroidMapDetailed(p, id));
asteroidUnTransForm( n, id );
return n;
}
vec2 asteroidSpheretracing(vec3 ori, vec3 dir, vec3 id) {
asteroidTransForm( ori, id );
asteroidTransForm( dir, id );
vec2 td = vec2(0.0);
for(int i = 0; i < ASTEROID_NUM_STEPS; i++) {
vec3 p = ori + dir * td.x;
td.y = asteroidMap(p, id);
if(td.y < ASTEROID_TRESHOLD) break;
td.x += (td.y-ASTEROID_TRESHOLD) * 0.9;
}
return td;
}
vec3 asteroidGetStoneColor(vec3 p, float c, vec3 l, vec3 n, vec3 e) {
return mix( diffuse(n,l)*RING_COLOR_1*SUN_COLOR, SUN_COLOR*specular(n,l,e,3.0), .5*fresnel(n,e,5.));
}
//-----------------------------------------------------
// Ring (by me ;))
//-----------------------------------------------------
const float RING_DETAIL_DISTANCE = 40.;
const float RING_VOXEL_STEP_SIZE = .03;
vec3 ringShadowColor( const in vec3 ro ) {
if( iSphere( ro, SUN_DIRECTION, vec4( 0., 0., 0., EARTH_RADIUS ) ) > 0. ) {
return vec3(0.);
}
return vec3(1.);
}
bool ringMap( const in vec3 ro ) {
return ro.z < RING_HEIGHT/RING_VOXEL_STEP_SIZE && hash(ro)<.5;
}
vec4 renderRingNear( const in vec3 ro, const in vec3 rd ) {
// find startpoint
float d1 = iPlane( ro, rd, vec4( 0., 0., 1., RING_HEIGHT ) );
float d2 = iPlane( ro, rd, vec4( 0., 0., 1., -RING_HEIGHT ) );
if( d1 < 0. && d2 < 0. ) return vec4( 0. );
float d = min( max(d1,0.), max(d2,0.) );
if( d > ASTEROID_MAX_DISTANCE ) return vec4( 0. );
vec3 ros = ro + rd*d;
// avoid precision problems..
vec2 mroxy = mod(ros.xy, vec2(10.));
vec2 roxy = ros.xy - mroxy;
ros.xy -= roxy;
ros /= RING_VOXEL_STEP_SIZE;
ros.xy -= vec2(.013,.112)*time*.5;
vec3 pos = floor(ros);
vec3 ri = 1.0/rd;
vec3 rs = sign(rd);
vec3 dis = (pos-ros + 0.5 + rs*0.5) * ri;
float alpha = 0., dint;
vec3 offset = vec3(0.), id, asteroidro;
vec2 asteroid;
for( int i=0; i<RING_VOXEL_STEPS; i++ ) {
if( ringMap(pos) ) {
id = hash33(pos);
offset = id*(1.-2.*ASTEROID_RADIUS)+ASTEROID_RADIUS;
dint = iSphere( ros, rd, vec4(pos+offset, ASTEROID_RADIUS) );
if( dint > 0. ) {
asteroidro = ros+rd*dint-(pos+offset);
asteroid = asteroidSpheretracing( asteroidro, rd, id );
if( asteroid.y < .1 ) {
alpha = 1.;
break;
}
}
}
vec3 mm = step(dis.xyz, dis.yxy) * step(dis.xyz, dis.zzx);
dis += mm * rs * ri;
pos += mm * rs;
}
if( alpha > 0. ) {
vec3 intersection = ros + rd*(asteroid.x+dint);
vec3 n = asteroidGetNormal( asteroidro + rd*asteroid.x, id );
vec3 col = asteroidGetStoneColor(intersection, .1, SUN_DIRECTION, n, rd);
intersection *= RING_VOXEL_STEP_SIZE;
intersection.xy += roxy;
col *= ringShadowColor( intersection );
return vec4( col, 1.-smoothstep(0.4*ASTEROID_MAX_DISTANCE, 0.5* ASTEROID_MAX_DISTANCE, distance( intersection, ro ) ) );
}
return vec4(0.);
}
//-----------------------------------------------------
// Ring (by me ;))
//-----------------------------------------------------
float renderRingFarShadow( const in vec3 ro, const in vec3 rd ) {
// intersect plane
float d = iPlane( ro, rd, vec4( 0., 0., 1., 0.) );
if( d > 0. ) {
vec3 intersection = ro + rd*d;
float l = length(intersection.xy);
if( l > RING_INNER_RADIUS && l < RING_OUTER_RADIUS ) {
return .5 + .5 * (.2+.8*noise( l*.07 )) * (.5+.5*noise(intersection.xy));
}
}
return 0.;
}
vec4 renderRingFar( const in vec3 ro, const in vec3 rd, inout float maxd ) {
// intersect plane
float d = iPlane( ro, rd, vec4( 0., 0., 1., 0.) );
if( d > 0. && d < maxd ) {
maxd = d;
vec3 intersection = ro + rd*d;
float l = length(intersection.xy);
if( l > RING_INNER_RADIUS && l < RING_OUTER_RADIUS ) {
float dens = .5 + .5 * (.2+.8*noise( l*.07 )) * (.5+.5*noise(intersection.xy));
vec3 col = mix( RING_COLOR_1, RING_COLOR_2, abs( noise(l*0.2) ) ) * abs(dens) * 1.5;
col *= ringShadowColor( intersection );
col *= .8+.3*diffuse( vec3(0,0,1), SUN_DIRECTION );
col *= SUN_COLOR;
return vec4( col, dens );
}
}
return vec4(0.);
}
vec4 renderRing( const in vec3 ro, const in vec3 rd, inout float maxd ) {
vec4 far = renderRingFar( ro, rd, maxd );
float l = length( ro.xy );
if( abs(ro.z) < RING_HEIGHT+RING_DETAIL_DISTANCE
&& l < RING_OUTER_RADIUS+RING_DETAIL_DISTANCE
&& l > RING_INNER_RADIUS-RING_DETAIL_DISTANCE ) {
float d = iPlane( ro, rd, vec4( 0., 0., 1., 0.) );
float detail = mix( .5 * noise( fract(ro.xy+rd.xy*d) * 92.1)+.25, 1., smoothstep( 0.,RING_DETAIL_DISTANCE, d) );
far.xyz *= detail;
}
// are asteroids neaded ?
if( abs(ro.z) < RING_HEIGHT+ASTEROID_MAX_DISTANCE
&& l < RING_OUTER_RADIUS+ASTEROID_MAX_DISTANCE
&& l > RING_INNER_RADIUS-ASTEROID_MAX_DISTANCE ) {
vec4 near = renderRingNear( ro, rd );
far = mix( far, near, near.w );
maxd=0.;
}
return far;
}
//-----------------------------------------------------
// Stars (by me ;))
//-----------------------------------------------------
vec4 renderStars( const in vec3 rd ) {
vec3 rds = rd;
vec3 col = vec3(0);
float v = 1.0/( 2. * ( 1. + rds.z ) );
vec2 xy = vec2(rds.y * v, rds.x * v);
float s = noise(rds*134.);
s += noise(rds*470.);
s = pow(s,19.0) * 0.00001;
if (s > 0.5) {
vec3 backStars = vec3(s)*.5 * vec3(0.95,0.8,0.9);
col += backStars;
}
return vec4( col, 1 );
}
//-----------------------------------------------------
// Atmospheric Scattering by GLtracy
//
// https://www.shadertoy.com/view/lslXDr
//-----------------------------------------------------
const float ATMOSPHERE_K_R = 0.166;
const float ATMOSPHERE_K_M = 0.0025;
const float ATMOSPHERE_E = 12.3;
const vec3 ATMOSPHERE_C_R = vec3( 0.3, 0.7, 1.0 );
const float ATMOSPHERE_G_M = -0.85;
const float ATMOSPHERE_SCALE_H = 4.0 / ( EARTH_ATMOSPHERE );
const float ATMOSPHERE_SCALE_L = 1.0 / ( EARTH_ATMOSPHERE );
const float ATMOSPHERE_FNUM_OUT_SCATTER = float(ATMOSPHERE_NUM_OUT_SCATTER);
const float ATMOSPHERE_FNUM_IN_SCATTER = float(ATMOSPHERE_NUM_IN_SCATTER);
const int ATMOSPHERE_NUM_OUT_SCATTER_LOW = 2;
const int ATMOSPHERE_NUM_IN_SCATTER_LOW = 4;
const float ATMOSPHERE_FNUM_OUT_SCATTER_LOW = float(ATMOSPHERE_NUM_OUT_SCATTER_LOW);
const float ATMOSPHERE_FNUM_IN_SCATTER_LOW = float(ATMOSPHERE_NUM_IN_SCATTER_LOW);
float atmosphericPhaseMie( float g, float c, float cc ) {
float gg = g * g;
float a = ( 1.0 - gg ) * ( 1.0 + cc );
float b = 1.0 + gg - 2.0 * g * c;
b *= sqrt( b );
b *= 2.0 + gg;
return 1.5 * a / b;
}
float atmosphericPhaseReyleigh( float cc ) {
return 0.75 * ( 1.0 + cc );
}
float atmosphericDensity( vec3 p ){
return exp( -( length( p ) - EARTH_RADIUS ) * ATMOSPHERE_SCALE_H );
}
float atmosphericOptic( vec3 p, vec3 q ) {
vec3 step = ( q - p ) / ATMOSPHERE_FNUM_OUT_SCATTER;
vec3 v = p + step * 0.5;
float sum = 0.0;
for ( int i = 0; i < ATMOSPHERE_NUM_OUT_SCATTER; i++ ) {
sum += atmosphericDensity( v );
v += step;
}
sum *= length( step ) * ATMOSPHERE_SCALE_L;
return sum;
}
vec4 atmosphericInScatter( vec3 o, vec3 dir, vec2 e, vec3 l ) {
float len = ( e.y - e.x ) / ATMOSPHERE_FNUM_IN_SCATTER;
vec3 step = dir * len;
vec3 p = o + dir * e.x;
vec3 v = p + dir * ( len * 0.5 );
float sumdensity = 0.;
vec3 sum = vec3( 0.0 );
for ( int i = 0; i < ATMOSPHERE_NUM_IN_SCATTER; i++ ) {
vec3 u = v + l * iCSphereF( v, l, EARTH_RADIUS + EARTH_ATMOSPHERE );
float n = ( atmosphericOptic( p, v ) + atmosphericOptic( v, u ) ) * ( PI * 4.0 );
float dens = atmosphericDensity( v );
float m = MAX;
sum += dens * exp( -n * ( ATMOSPHERE_K_R * ATMOSPHERE_C_R + ATMOSPHERE_K_M ) )
* (1. - renderRingFarShadow( u, SUN_DIRECTION ) );
sumdensity += dens;
v += step;
}
sum *= len * ATMOSPHERE_SCALE_L;
float c = dot( dir, -l );
float cc = c * c;
return vec4( sum * ( ATMOSPHERE_K_R * ATMOSPHERE_C_R * atmosphericPhaseReyleigh( cc ) +
ATMOSPHERE_K_M * atmosphericPhaseMie( ATMOSPHERE_G_M, c, cc ) ) * ATMOSPHERE_E,
clamp(sumdensity * len * ATMOSPHERE_SCALE_L,0.,1.));
}
float atmosphericOpticLow( vec3 p, vec3 q ) {
vec3 step = ( q - p ) / ATMOSPHERE_FNUM_OUT_SCATTER_LOW;
vec3 v = p + step * 0.5;
float sum = 0.0;
for ( int i = 0; i < ATMOSPHERE_NUM_OUT_SCATTER_LOW; i++ ) {
sum += atmosphericDensity( v );
v += step;
}
sum *= length( step ) * ATMOSPHERE_SCALE_L;
return sum;
}
vec3 atmosphericInScatterLow( vec3 o, vec3 dir, vec2 e, vec3 l ) {
float len = ( e.y - e.x ) / ATMOSPHERE_FNUM_IN_SCATTER_LOW;
vec3 step = dir * len;
vec3 p = o + dir * e.x;
vec3 v = p + dir * ( len * 0.5 );
vec3 sum = vec3( 0.0 );
for ( int i = 0; i < ATMOSPHERE_NUM_IN_SCATTER_LOW; i++ ) {
vec3 u = v + l * iCSphereF( v, l, EARTH_RADIUS + EARTH_ATMOSPHERE );
float n = ( atmosphericOpticLow( p, v ) + atmosphericOpticLow( v, u ) ) * ( PI * 4.0 );
float m = MAX;
sum += atmosphericDensity( v ) * exp( -n * ( ATMOSPHERE_K_R * ATMOSPHERE_C_R + ATMOSPHERE_K_M ) );
v += step;
}
sum *= len * ATMOSPHERE_SCALE_L;
float c = dot( dir, -l );
float cc = c * c;
return sum * ( ATMOSPHERE_K_R * ATMOSPHERE_C_R * atmosphericPhaseReyleigh( cc ) +
ATMOSPHERE_K_M * atmosphericPhaseMie( ATMOSPHERE_G_M, c, cc ) ) * ATMOSPHERE_E;
}
vec4 renderAtmospheric( const in vec3 ro, const in vec3 rd, inout float d ) {
// inside or outside atmosphere?
vec2 e = iCSphere2( ro, rd, EARTH_RADIUS + EARTH_ATMOSPHERE );
vec2 f = iCSphere2( ro, rd, EARTH_RADIUS );
if( length(ro) <= EARTH_RADIUS + EARTH_ATMOSPHERE ) {
if( d < e.y ) {
e.y = d;
}
d = e.y;
e.x = 0.;
if ( iSphere( ro, rd, vec4(0,0,0,EARTH_RADIUS)) > 0. ) {
d = iSphere( ro, rd, vec4(0,0,0,EARTH_RADIUS));
}
} else {
if( iSphere( ro, rd, vec4(0,0,0,EARTH_RADIUS + EARTH_ATMOSPHERE )) < 0. ) return vec4(0.);
if ( e.x > e.y ) {
d = MAX;
return vec4(0.);
}
d = e.y = min( e.y, f.x );
}
return atmosphericInScatter( ro, rd, e, SUN_DIRECTION );
}
vec3 renderAtmosphericLow( const in vec3 ro, const in vec3 rd ) {
vec2 e = iCSphere2( ro, rd, EARTH_RADIUS + EARTH_ATMOSPHERE );
e.x = 0.;
return atmosphericInScatterLow( ro, rd, e, SUN_DIRECTION );
}
//-----------------------------------------------------
// Seascape by TDM
//
// https://www.shadertoy.com/view/Ms2SD1
//-----------------------------------------------------
const int SEA_ITER_GEOMETRY = 3;
const int SEA_ITER_FRAGMENT = 5;
const float SEA_EPSILON = 1e-3;
float SEA_EPSILON_NRM = 0.1 / iResolution.x;
const float SEA_HEIGHT = 0.6;
const float SEA_CHOPPY = 4.0;
const float SEA_SPEED = 0.8;
const float SEA_FREQ = 0.16;
const vec3 SEA_BASE = vec3(0.1,0.19,0.22);
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);
float SEA_TIME;
const mat2 sea_octave_m = mat2(1.6,1.2,-1.2,1.6);
float seaOctave( in vec2 uv, const in float choppy) {
uv += noise(uv);
vec2 wv = 1.0-abs(sin(uv));
vec2 swv = abs(cos(uv));
wv = mix(wv,swv,wv);
return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
}
float seaMap(const in vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz; uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < SEA_ITER_GEOMETRY; i++) {
d = seaOctave((uv+SEA_TIME)*freq,choppy);
d += seaOctave((uv-SEA_TIME)*freq,choppy);
h += d * amp;
uv *= sea_octave_m; freq *= 1.9; amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
float seaMapHigh(const in vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz; uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < SEA_ITER_FRAGMENT; i++) {
d = seaOctave((uv+SEA_TIME)*freq,choppy);
d += seaOctave((uv-SEA_TIME)*freq,choppy);
h += d * amp;
uv *= sea_octave_m; freq *= 1.9; amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
vec3 seaGetColor( const in vec3 n, vec3 eye, const in vec3 l, const in float att,
const in vec3 sunc, const in vec3 upc, const in vec3 reflected) {
vec3 refracted = SEA_BASE * upc + diffuse(n,l) * SEA_WATER_COLOR * 0.12 * sunc;
vec3 color = mix(refracted,reflected,fresnel(n, -eye, 3.)*.65 );
color += upc*SEA_WATER_COLOR * (att * 0.18);
color += sunc * vec3(specular(n,l,eye,60.0));
return color;
}
vec3 seaGetNormal(const in vec3 p, const in float eps) {
vec3 n;
n.y = seaMapHigh(p);
n.x = seaMapHigh(vec3(p.x+eps,p.y,p.z)) - n.y;
n.z = seaMapHigh(vec3(p.x,p.y,p.z+eps)) - n.y;
n.y = eps;
return normalize(n);
}
float seaHeightMapTracing(const in vec3 ori, const in vec3 dir, out vec3 p) {
float tm = 0.0;
float tx = 1000.0;
float hx = seaMap(ori + dir * tx);
if(hx > 0.0) return tx;
float hm = seaMap(ori + dir * tm);
float tmid = 0.0;
for(int i = 0; i < SEA_NUM_STEPS; i++) {
tmid = mix(tm,tx, hm/(hm-hx));
p = ori + dir * tmid;
float hmid = seaMap(p);
if(hmid < 0.0) {
tx = tmid;
hx = hmid;
} else {
tm = tmid;
hm = hmid;
}
}
return tmid;
}
vec3 seaTransform( in vec3 x ) {
x.yz = rotate( 0.8, x.yz );
return x;
}
vec3 seaUntransform( in vec3 x ) {
x.yz = rotate( -0.8, x.yz );
return x;
}
void renderSea( const in vec3 ro, const in vec3 rd, inout vec3 n, inout float att ) {
vec3 p,
rom = seaTransform(ro),
rdm = seaTransform(rd);
rom.y -= EARTH_RADIUS;
rom *= 1000.;
rom.xz += vec2(3.1,.2)*time;
SEA_TIME = time * SEA_SPEED;
seaHeightMapTracing(rom,rdm,p);
float squareddist = dot(p - rom, p-rom );
n = seaGetNormal(p, squareddist * SEA_EPSILON_NRM );
n = seaUntransform(n);
att = clamp(SEA_HEIGHT+p.y, 0.,1.);
}
//-----------------------------------------------------
// Terrain based on Elevated and Terrain Tubes by IQ
//
// https://www.shadertoy.com/view/MdX3Rr
// https://www.shadertoy.com/view/4sjXzG
//-----------------------------------------------------
#ifndef HIDE_TERRAIN
const mat2 terrainM2 = mat2(1.6,-1.2,1.2,1.6);
float terrainLow( vec2 p ) {
p *= 0.0013;
float s = 1.0;
float t = 0.0;
for( int i=0; i<2; i++ ) {
t += s*tri( p );
s *= 0.5 + 0.1*t;
p = 0.97*terrainM2*p + (t-0.5)*0.12;
}
return t*33.0;
}
float terrainMed( vec2 p ) {
p *= 0.0013;
float s = 1.0;
float t = 0.0;
for( int i=0; i<6; i++ ) {
t += s*tri( p );
s *= 0.5 + 0.1*t;
p = 0.97*terrainM2*p + (t-0.5)*0.12;
}
return t*33.0;
}
float terrainHigh( vec2 p ) {
vec2 q = p;
p *= 0.0013;
float s = 1.0;
float t = 0.0;
for( int i=0; i<7; i++ ) {
t += s*tri( p );
s *= 0.5 + 0.1*t;
p = 0.97*terrainM2*p + (t-0.5)*0.12;
}
t += t*0.015*fbm( q );
return t*33.0;
}
float terrainMap( const in vec3 pos ) {
return pos.y - terrainMed(pos.xz);
}
float terrainMapH( const in vec3 pos ) {
float y = terrainHigh(pos.xz);
float h = pos.y - y;
return h;
}
float terrainIntersect( in vec3 ro, in vec3 rd, in float tmin, in float tmax ) {
float t = tmin;
for( int i=0; i<TERRAIN_NUM_STEPS; i++ ) {
vec3 pos = ro + t*rd;
float res = terrainMap( pos );
if( res<(0.001*t) || t>tmax ) break;
t += res*.9;
}
return t;
}
float terrainCalcShadow(in vec3 ro, in vec3 rd ) {
vec2 eps = vec2(150.0,0.0);
float h1 = terrainMed( ro.xz );
float h2 = terrainLow( ro.xz );
float d1 = 10.0;
float d2 = 80.0;
float d3 = 200.0;
float s1 = clamp( 1.0*(h1 + rd.y*d1 - terrainMed(ro.xz + d1*rd.xz)), 0.0, 1.0 );
float s2 = clamp( 0.5*(h1 + rd.y*d2 - terrainMed(ro.xz + d2*rd.xz)), 0.0, 1.0 );
float s3 = clamp( 0.2*(h2 + rd.y*d3 - terrainLow(ro.xz + d3*rd.xz)), 0.0, 1.0 );
return min(min(s1,s2),s3);
}
vec3 terrainCalcNormalHigh( in vec3 pos, float t ) {
vec2 e = vec2(1.0,-1.0)*0.001*t;
return normalize( e.xyy*terrainMapH( pos + e.xyy ) +
e.yyx*terrainMapH( pos + e.yyx ) +
e.yxy*terrainMapH( pos + e.yxy ) +
e.xxx*terrainMapH( pos + e.xxx ) );
}
vec3 terrainCalcNormalMed( in vec3 pos, float t ) {
float e = 0.005*t;
vec2 eps = vec2(e,0.0);
float h = terrainMed( pos.xz );
return normalize(vec3( terrainMed(pos.xz-eps.xy)-h, e, terrainMed(pos.xz-eps.yx)-h ));
}
vec3 terrainTransform( in vec3 x ) {
x.zy = rotate( -.83, x.zy );
return x;
}
vec3 terrainUntransform( in vec3 x ) {
x.zy = rotate( .83, x.zy );
return x;
}
float llamelTime;
const float llamelScale = 5.;
vec3 llamelPosition() {
llamelTime = time*2.5;
vec2 pos = vec2( -400., 135.-llamelTime*0.075* llamelScale);
return vec3( pos.x, terrainMed( pos ), pos.y );
}
vec3 terrainShade( const in vec3 col, const in vec3 pos, const in vec3 rd, const in vec3 n, const in float spec,
const in vec3 sunc, const in vec3 upc, const in vec3 reflc ) {
vec3 sunDirection = terrainTransform(SUN_DIRECTION);
float dif = diffuse( n, sunDirection );
float bac = diffuse( n, vec3(-sunDirection.x, sunDirection.y, -sunDirection.z) );
float sha = terrainCalcShadow( pos, sunDirection );
float amb = clamp( n.y,0.0,1.0);
vec3 lin = vec3(0.0);
lin += 2.*dif*sunc*vec3( sha, sha*sha*0.1+0.9*sha, sha*sha*0.2+0.8*sha );
lin += 0.2*amb*upc;
lin += 0.08*bac*clamp(vec3(1.)-sunc, vec3(0.), vec3(1.));
return mix( col*lin*3., reflc, spec*fresnel(n,-terrainTransform(rd),5.0) );
}
vec3 terrainGetColor( const in vec3 pos, const in vec3 rd, const in float t, const in vec3 sunc, const in vec3 upc, const in vec3 reflc ) {
vec3 nor = terrainCalcNormalHigh( pos, t );
vec3 sor = terrainCalcNormalMed( pos, t );
float spec = 0.005;
#ifdef DISPLAY_TERRAIN_DETAIL
float no = noise(5.*fbm(1.11*pos.xz));
#else
const float no = 0.;
#endif
float r = .5+.5*fbm(.95*pos.xz);
vec3 col = (r*0.25+0.75)*0.9*mix( vec3(0.08,0.07,0.07), vec3(0.10,0.09,0.08), noise(0.4267*vec2(pos.x*2.,pos.y*9.8))+.01*no );
col = mix( col, 0.20*vec3(0.45,.30,0.15)*(0.50+0.50*r),smoothstep(0.825,0.925,nor.y+.025*no) );
col = mix( col, 0.15*vec3(0.30,.30,0.10)*(0.25+0.75*r),smoothstep(0.95,1.0,nor.y+.025*no) );
col *= .88+.12*no;
float s = nor.y + 0.03*pos.y + 0.35*fbm(0.05*pos.xz) - .35;
float sf = fwidth(s) * 1.5;
s = smoothstep(0.84-sf, 0.84+sf, s );
col = mix( col, 0.29*vec3(0.62,0.65,0.7), s);
nor = mix( nor, sor, 0.7*smoothstep(0.9, 0.95, s ) );
spec = mix( spec, 0.45, smoothstep(0.9, 0.95, s ) );
col = terrainShade( col, pos, rd, nor, spec, sunc, upc, reflc );
#ifdef DISPLAY_LLAMEL
col *= clamp( distance(pos.xz, llamelPosition().xz )*0.4, 0.4, 1.);
#endif
return col;
}
vec3 terrainTransformRo( const in vec3 ro ) {
vec3 rom = terrainTransform(ro);
rom.y -= EARTH_RADIUS - 100.;
rom.xz *= 5.;
rom.xz += vec2(-170.,50.)+vec2(-4.,.4)*time;
rom.y += (terrainLow( rom.xz ) - 86.)*clamp( 1.-1.*(length(ro)-EARTH_RADIUS), 0., 1.);
return rom;
}
vec4 renderTerrain( const in vec3 ro, const in vec3 rd, inout vec3 intersection, inout vec3 n ) {
vec3 p,
rom = terrainTransformRo(ro),
rdm = terrainTransform(rd);
float tmin = 10.0;
float tmax = 3200.0;
float res = terrainIntersect( rom, rdm, tmin, tmax );
if( res > tmax ) {
res = -1.;
} else {
vec3 pos = rom+rdm*res;
n = terrainCalcNormalMed( pos, res );
n = terrainUntransform( n );
intersection = ro+rd*res/100.;
}
return vec4(res, rom+rdm*res);
}
#endif
//-----------------------------------------------------
// LLamels by Eiffie
//
// https://www.shadertoy.com/view/ltsGz4
//-----------------------------------------------------
#ifdef DISPLAY_LLAMEL
float llamelMapSMin(const in float a,const in float b,const in float k){
float h=clamp(0.5+0.5*(b-a)/k,0.0,1.0);return b+h*(a-b-k+k*h);
}
float llamelMapLeg(vec3 p, vec3 j0, vec3 j3, vec3 l, vec4 r, vec3 rt){//z joint with tapered legs
float lx2z=l.x/(l.x+l.z),h=l.y*lx2z;
vec3 u=(j3-j0)*lx2z,q=u*(0.5+0.5*(l.x*l.x-h*h)/dot(u,u));
q+=sqrt(max(0.0,l.x*l.x-dot(q,q)))*normalize(cross(u,rt));
vec3 j1=j0+q,j2=j3-q*(1.0-lx2z)/lx2z;
u=p-j0;q=j1-j0;
h=clamp(dot(u,q)/dot(q,q),0.0,1.0);
float d=length(u-q*h)-r.x-(r.y-r.x)*h;
u=p-j1;q=j2-j1;
h=clamp(dot(u,q)/dot(q,q),0.0,1.0);
d=min(d,length(u-q*h)-r.y-(r.z-r.y)*h);
u=p-j2;q=j3-j2;
h=clamp(dot(u,q)/dot(q,q),0.0,1.0);
return min(d,length(u-q*h)-r.z-(r.w-r.z)*h);
}
float llamelMap(in vec3 p) {
const vec3 rt=vec3(0.0,0.0,1.0);
p.y += 0.25*llamelScale;
p.xz -= 0.5*llamelScale;
p.xz = vec2(-p.z, p.x);
vec3 pori = p;
p /= llamelScale;
vec2 c=floor(p.xz);
p.xz=fract(p.xz)-vec2(0.5);
p.y -= p.x*.04*llamelScale;
float sa=sin(c.x*2.0+c.y*4.5+llamelTime*0.05)*0.15;
float b=0.83-abs(p.z);
float a=c.x+117.0*c.y+sign(p.x)*1.57+sign(p.z)*1.57+llamelTime,ca=cos(a);
vec3 j0=vec3(sign(p.x)*0.125,ca*0.01,sign(p.z)*0.05),j3=vec3(j0.x+sin(a)*0.1,max(-0.25+ca*0.1,-0.25),j0.z);
float dL=llamelMapLeg(p,j0,j3,vec3(0.08,0.075,0.12),vec4(0.03,0.02,0.015,0.01),rt*sign(p.x));
p.y-=0.03;
float dB=(length(p.xyz*vec3(1.0,1.75,1.75))-0.14)*0.75;
a=c.x+117.0*c.y+llamelTime;ca=cos(a);sa*=0.4;
j0=vec3(0.125,0.03+abs(ca)*0.03,ca*0.01),j3=vec3(0.3,0.07+ca*sa,sa);
float dH=llamelMapLeg(p,j0,j3,vec3(0.075,0.075,0.06),vec4(0.03,0.035,0.03,0.01),rt);
dB=llamelMapSMin(min(dL,dH),dB,clamp(0.04+p.y,0.0,1.0));
a=max(abs(p.z),p.y)+0.05;
return max(min(dB,min(a,b)),length(pori.xz-vec2(0.5)*llamelScale)-.5*llamelScale);
}
vec3 llamelGetNormal( in vec3 ro ) {
vec2 e = vec2(1.0,-1.0)*0.001;
return normalize( e.xyy*llamelMap( ro + e.xyy ) +
e.yyx*llamelMap( ro + e.yyx ) +
e.yxy*llamelMap( ro + e.yxy ) +
e.xxx*llamelMap( ro + e.xxx ) );
}
vec4 renderLlamel( in vec3 ro, const in vec3 rd, const in vec3 sunc, const in vec3 upc, const in vec3 reflc ) {
ro -= llamelPosition();
float t=.1*hash(rd.xy),d,dm=10.0,tm;
for(int i=0;i<36;i++){
t+=d=llamelMap(ro+rd*t);
if(d<dm){dm=d;tm=t;}
if(t>1000.0 || d<0.00001)break;
}
dm=max(0.0,dm);
if( dm < .02 ) {
vec3 col = vec3(0.45,.30,0.15)*.2;
vec3 pos = ro + rd*tm;
vec3 nor = llamelGetNormal( pos );
col = terrainShade( col, pos, rd, nor, .01, sunc, upc, reflc );
return vec4(col, clamp( 1.-(dm-0.01)/0.01,0., 1.) );
}
return vec4(0.);
}
#endif
//-----------------------------------------------------
// Clouds (by me ;))
//-----------------------------------------------------
vec4 renderClouds( const in vec3 ro, const in vec3 rd, const in float d, const in vec3 n, const in float land,
const in vec3 sunColor, const in vec3 upColor, inout float shadow ) {
vec3 intersection = ro+rd*d;
vec3 cint = intersection*0.009;
float rot = -.2*length(cint.xy) + .6*fbm( cint*.4,0.5,2.96 ) + .05*land;
cint.xy = rotate( rot, cint.xy );
vec3 cdetail = mod(intersection*3.23,vec3(50.));
cdetail.xy = rotate( .25*rot, cdetail.xy );
float clouds = 1.3*(fbm( cint*(1.+.02*noise(intersection)),0.5,2.96)+.4*land-.3);
#ifdef DISPLAY_CLOUDS_DETAIL
if( d < 200. ) {
clouds += .3*(fbm(cdetail,0.5,2.96)-.5)*(1.-smoothstep(0.,200.,d));
}
#endif
shadow = clamp(1.-clouds, 0., 1.);
clouds = clamp(clouds, 0., 1.);
clouds *= clouds;
clouds *= smoothstep(0.,0.4,d);
vec3 clbasecolor = vec3(1.);
vec3 clcol = .1*clbasecolor*sunColor * vec3(specular(n,SUN_DIRECTION,rd,36.0));
clcol += .3*clbasecolor*sunColor;
clcol += clbasecolor*(diffuse(n,SUN_DIRECTION)*sunColor+upColor);
return vec4( clcol, clouds );
}
//-----------------------------------------------------
// Planet (by me ;))
//-----------------------------------------------------
vec4 renderPlanet( const in vec3 ro, const in vec3 rd, const in vec3 up, inout float maxd ) {
float d = iSphere( ro, rd, vec4( 0., 0., 0., EARTH_RADIUS ) );
vec3 intersection = ro + rd*d;
vec3 n = nSphere( intersection, vec4( 0., 0., 0., EARTH_RADIUS ) );
vec4 res;
#ifndef HIDE_TERRAIN
bool renderTerrainDetail = length(ro) < EARTH_RADIUS+EARTH_ATMOSPHERE &&
dot( terrainUntransform( vec3(0.,1.,0.) ), normalize(ro) ) > .9996;
#endif
bool renderSeaDetail = d < 1. && dot( seaUntransform( vec3(0.,1.,0.) ), normalize(ro) ) > .9999;
float mixDetailColor = 0.;
if( d < 0. || d > maxd) {
#ifndef HIDE_TERRAIN
if( renderTerrainDetail ) {
intersection = ro;
n = normalize( ro );
} else {
return vec4(0);
}
#else
return vec4(0.);
#endif
}
if( d > 0. ) {
maxd = d;
}
float att = 0.;
if( dot(n,SUN_DIRECTION) < -0.1 ) return vec4( 0., 0., 0., 1. );
float dm = MAX, e = 0.;
vec3 col, detailCol, nDetail;
// normal and intersection
#ifndef HIDE_TERRAIN
if( renderTerrainDetail ) {
res = renderTerrain( ro, rd, intersection, nDetail );
if( res.x < 0. && d < 0. ) {
return vec4(0);
}
if( res.x >= 0. ) {
maxd = pow(res.x/4000.,4.)*50.;
e = -10.;
}
mixDetailColor = 1.-smoothstep(.75, 1., (length(ro)-EARTH_RADIUS) / EARTH_ATMOSPHERE);
n = normalize( mix( n, nDetail, mixDetailColor ) );
} else
#endif
if( renderSeaDetail ) {
float attsea, mf = smoothstep(.5,1.,d);
renderSea( ro, rd, nDetail, attsea );
n = normalize(mix( nDetail, n, mf ));
att = mix( attsea, att, mf );
} else {
e = fbm( .003*intersection+vec3(1.),0.4,2.96) + smoothstep(.85,.95, abs(intersection.z/EARTH_RADIUS));
#ifndef HIDE_TERRAIN
if( d < 1500. ) {
e += (-.03+.06* fbm( intersection*0.1,0.4,2.96))*(1.-d/1500.);
}
#endif
}
vec3 sunColor = .25*renderAtmosphericLow( intersection, SUN_DIRECTION).xyz;
vec3 upColor = 2.*renderAtmosphericLow( intersection, n).xyz;
vec3 reflColor = renderAtmosphericLow( intersection, reflect(rd,n)).xyz;
// color
#ifndef HIDE_TERRAIN
if(renderTerrainDetail ) {
detailCol = col = terrainGetColor(res.yzw, rd, res.x, sunColor, upColor, reflColor);
d = 0.;
}
#endif
if( mixDetailColor < 1. ) {
if( e < .45 ) {
// sea
col = seaGetColor(n,rd,SUN_DIRECTION, att, sunColor, upColor, reflColor);
} else {
// planet (land) far
float land1 = max(0.1, fbm( intersection*0.0013,0.4,2.96) );
float land2 = max(0.1, fbm( intersection*0.0063,0.4,2.96) );
float iceFactor = abs(pow(intersection.z/EARTH_RADIUS,13.0))*e;
vec3 landColor1 = vec3(0.43,0.65,0.1) * land1;
vec3 landColor2 = RING_COLOR_1 * land2;
vec3 mixedLand = (landColor1 + landColor2)* 0.5;
vec3 finalLand = mix(mixedLand, vec3(7.0, 7.0, 7.0) * land1 * 1.5, max(iceFactor+.02*land2-.02, 0.));
col = (diffuse(n,SUN_DIRECTION)*sunColor+upColor)*finalLand*.75;
#ifdef HIGH_QUALITY
col *= (.5+.5*fbm( intersection*0.23,0.4,2.96) );
#endif
}
}
if( mixDetailColor > 0. ) {
col = mix( col, detailCol, mixDetailColor );
}
#ifdef DISPLAY_LLAMEL
if(renderTerrainDetail ) {
vec3 rom = terrainTransformRo(ro),
rdm = terrainTransform(rd);
d = iSphere( rom, rdm, vec4( llamelPosition(), llamelScale*3. ) );
if( d > 0. ) {
vec4 llamel = renderLlamel( rom+rdm*d, rdm, sunColor, upColor, reflColor );
col = mix(col, llamel.rgb, llamel.a);
}
}
#endif
d = iSphere( ro, rd, vec4( 0., 0., 0., EARTH_RADIUS+EARTH_CLOUDS ) );
if( d > 0. ) {
float shadow;
vec4 clouds = renderClouds( ro, rd, d, n, e, sunColor, upColor, shadow);
col *= shadow;
col = mix( col, clouds.rgb, clouds.w );
}
float m = MAX;
col *= (1. - renderRingFarShadow( ro+rd*d, SUN_DIRECTION ) );
return vec4( col, 1. );
}
//-----------------------------------------------------
// Lens flare by musk
//
// https://www.shadertoy.com/view/4sX3Rs
//-----------------------------------------------------
vec3 lensFlare( const in vec2 uv, const in vec2 pos) {
vec2 main = uv-pos;
vec2 uvd = uv*(length(uv));
float f0 = 1.5/(length(uv-pos)*16.0+1.0);
float f1 = max(0.01-pow(length(uv+1.2*pos),1.9),.0)*7.0;
float f2 = max(1.0/(1.0+32.0*pow(length(uvd+0.8*pos),2.0)),.0)*00.25;
float f22 = max(1.0/(1.0+32.0*pow(length(uvd+0.85*pos),2.0)),.0)*00.23;
float f23 = max(1.0/(1.0+32.0*pow(length(uvd+0.9*pos),2.0)),.0)*00.21;
vec2 uvx = mix(uv,uvd,-0.5);
float f4 = max(0.01-pow(length(uvx+0.4*pos),2.4),.0)*6.0;
float f42 = max(0.01-pow(length(uvx+0.45*pos),2.4),.0)*5.0;
float f43 = max(0.01-pow(length(uvx+0.5*pos),2.4),.0)*3.0;
vec3 c = vec3(.0);
c.r+=f2+f4; c.g+=f22+f42; c.b+=f23+f43;
c = c*.5 - vec3(length(uvd)*.05);
c+=vec3(f0);
return c;
}
//-----------------------------------------------------
// cameraPath
//-----------------------------------------------------
vec3 pro, pta, pup;
float dro, dta, dup;
void camint( inout vec3 ret, const in float t, const in float duration, const in vec3 dest, inout vec3 prev, inout float prevt ) {
if( t >= prevt && t <= prevt+duration ) {
ret = mix( prev, dest, smoothstep(prevt, prevt+duration, t) );
}
prev = dest;
prevt += duration;
}
void cameraPath( in float t, out vec3 ro, out vec3 ta, out vec3 up ) {
#ifndef HIDE_TERRAIN
time = t = mod( t, 92. );
#else
time = t = mod( t, 66. );
#endif
dro = dta = dup = 0.;
pro = ro = vec3(900. ,7000. ,1500. );
pta = ta = vec3( 0. , 0. , 0. );
pup = up = vec3( 0. , 0.4, 1. );
camint( ro, t, 5., vec3(-4300. ,-1000. , 500. ), pro, dro );
camint( ta, t, 5., vec3( 0. , 0. , 0. ), pta, dta );
camint( up, t, 7., vec3( 0. , 0.1, 1. ), pup, dup );
camint( ro, t, 3., vec3(-1355. , 1795. , 1.2 ), pro, dro );
camint( ta, t, 1., vec3( 0. , 300. ,-600. ), pta, dta );
camint( up, t, 6., vec3( 0. , 0.1, 1. ), pup, dup );
camint( ro, t, 10., vec3(-1355. , 1795. , 1.2 ), pro, dro );
camint( ta, t, 14., vec3( 0. , 100. , 600. ), pta, dta );
camint( up, t, 13., vec3( 0. , 0.3, 1. ), pup, dup );
vec3 roe = seaUntransform( vec3( 0., EARTH_RADIUS+0.004, 0. ) );
vec3 upe = seaUntransform( vec3( 0., 1., 0. ) );
camint( ro, t, 7.,roe, pro, dro );
camint( ta, t, 7., vec3( EARTH_RADIUS + 0., EARTH_RADIUS - 500., 500. ), pta, dta );
camint( up, t, 6., upe, pup, dup );
camint( ro, t, 17.,roe, pro, dro );
camint( ta, t, 17., vec3( EARTH_RADIUS + 500., EARTH_RADIUS + 1300., -100. ), pta, dta );
camint( up, t, 18., vec3(.0,1.,1.), pup, dup );
camint( ro, t, 11., vec3( 3102. , 0. , 1450. ), pro, dro );
camint( ta, t, 4., vec3( 0. , -100. , 0. ), pta, dta );
camint( up, t, 8., vec3( 0. , 0.15, 1. ), pup, dup );
#ifndef HIDE_TERRAIN
roe = terrainUntransform( vec3( 0., EARTH_RADIUS+0.004, 0. ) );
upe = terrainUntransform( vec3( 0., 1., 0. ) );
camint( ro, t, 7., roe, pro, dro );
camint( ta, t, 12., vec3( -EARTH_RADIUS, EARTH_RADIUS+200., 100.), pta, dta );
camint( up, t, 2., upe, pup, dup );
roe = terrainUntransform( vec3( 0., EARTH_RADIUS+0.001, 0. ) );
camint( ro, t, 17.,roe, pro, dro );
camint( ta, t, 18., roe + vec3( 5000., EARTH_RADIUS-100., -2000.), pta, dta );
camint( up, t, 18., vec3(.0,1.,1.), pup, dup );
roe = terrainUntransform( vec3( 0., EARTH_RADIUS+1.8, 0. ) );
camint( ro, t, 4.,roe, pro, dro );
camint( ta, t, 4.5, roe + vec3( EARTH_RADIUS, EARTH_RADIUS+2000., -30.), pta, dta );
camint( up, t, 4., vec3(.0,1.,1.), pup, dup );
#endif
camint( ro, t, 10., vec3(900. ,7000. , 1500. ), pro, dro );
camint( ta, t, 2., vec3( 0. , 0. , 0. ), pta, dta );
camint( up, t, 10., vec3( 0. , 0.4, 1. ), pup, dup );
up = normalize( up );
}
//-----------------------------------------------------
// mainImage
//-----------------------------------------------------
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 p = -1.0 + 2.0 * (fragCoord.xy) / iResolution.xy;
p.x *= iResolution.x/iResolution.y;
vec3 col;
// black bands
vec2 bandy = vec2(.1,.9);
if( uv.y < bandy.x || uv.y > bandy.y ) {
col = vec3(0.);
} else {
// camera
vec3 ro, ta, up;
cameraPath( iGlobalTime*.7, ro, ta, up );
vec3 ww = normalize( ta - ro );
vec3 uu = normalize( cross(ww,up) );
vec3 vv = normalize( cross(uu,ww));
vec3 rd = normalize( -p.x*uu + p.y*vv + 2.2*ww );
float maxd = MAX;
col = renderStars( rd ).xyz;
vec4 planet = renderPlanet( ro, rd, up, maxd );
if( planet.w > 0. ) col.xyz = planet.xyz;
float atmosphered = maxd;
vec4 atmosphere = .85*renderAtmospheric( ro, rd, atmosphered );
col = col * (1.-atmosphere.w ) + atmosphere.xyz;
vec4 ring = renderRing( ro, rd, maxd );
if( ring.w > 0. && atmosphered < maxd ) {
ring.xyz = ring.xyz * (1.-atmosphere.w ) + atmosphere.xyz;
}
col = col * (1.-ring.w ) + ring.xyz;
#ifdef DISPLAY_CLOUDS
float lro = length(ro);
if( lro < EARTH_RADIUS+EARTH_CLOUDS*1.25 ) {
vec3 sunColor = 2.*renderAtmosphericLow( ro, SUN_DIRECTION);
vec3 upColor = 4.*renderAtmosphericLow( ro, vec3(-SUN_DIRECTION.x, SUN_DIRECTION.y, -SUN_DIRECTION.z));
if( lro < EARTH_RADIUS+EARTH_CLOUDS ) {
// clouds
float d = iCSphereF( ro, rd, EARTH_RADIUS + EARTH_CLOUDS );
if( d < maxd ) {
float shadow;
vec4 clouds = renderClouds( ro, rd, d, normalize(ro), 0., sunColor, upColor, shadow );
clouds.w *= 1.-smoothstep(0.8*EARTH_CLOUDS,EARTH_CLOUDS,lro-EARTH_RADIUS);
col = mix(col, clouds.rgb, clouds.w * (1.-smoothstep( 10., 30., d)) );
}
}
float offset = lro-EARTH_RADIUS-EARTH_CLOUDS;
col = mix( col, .5*sunColor, .15*abs(noise(offset*100.))*clamp(1.-4.*abs(offset)/EARTH_CLOUDS, 0., 1.) );
}
#endif
// post processing
col = pow( clamp(col,0.0,1.0), vec3(0.4545) );
col *= vec3(1.,0.99,0.95);
col = clamp(1.06*col-0.03, 0., 1.);
vec2 sunuv = 2.7*vec2( dot( SUN_DIRECTION, -uu ), dot( SUN_DIRECTION, vv ) );
float flare = dot( SUN_DIRECTION, normalize(ta-ro) );
col += vec3(1.4,1.2,1.0)*lensFlare(p, sunuv)*clamp( flare+.3, 0., 1.);
uv.y = (uv.y-bandy.x)*(1./(bandy.y-bandy.x));
col *= 0.5 + 0.5*pow( 16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y), 0.1 );
}
fragColor = vec4( col ,1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment