uniform sampler2D tDiffuse;
uniform float iTime;
uniform vec2 iResolution;
varying vec2 sv;
float dot2(vec2 a, vec2 b)
{
return a.x * b.x + a.y * b.y;
}
float cross2(vec2 a, vec2 b){
return a.x * b.y - a.y * b.x;
}
vec2 rotate(vec2 v, float a) {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, -s, s, c);
return m * v;
}
// SDF for a line, found in a comment by valentingalea on https://www.shadertoy.com/view/XllGDs
float sdf_line(vec2 st, vec2 vert_a, vec2 vert_b){
vec2 dvec_ap = st - vert_a; // Displacement vector from vert_a to our current pixel!
vec2 dvec_ab = vert_b - vert_a; // Displacement vector from vert_a to vert_b
vec2 direction = normalize(dvec_ab); // We find a direction vector, which has unit norm by definition!
return cross2(dvec_ap, direction); // Ah, the mighty cross-norm product!
}
float hash00(float p)
{
p = fract(p * .1031);
p *= p + 33.33;
p *= p + p;
return fract(p);
}
float hash2d(vec2 uv)
{
float xhash = cos( uv.x * 37.0 );
float yhash = cos( uv.y * 57.0 );
return fract( 415.92653 * ( xhash + yhash ) );
}
float noise(float x)
{
float i = floor(x);
float f = fract(x);
float u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
return mix(hash00(i), hash00(i + 1.0), u);
}
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
float fbmMountains(float pos)
{
float f = 1.2;
float a = 0.30;
float t = 0.05;
for(float i = 0.0; i < 8.0; i++)
{
t += a * noise(f * pos);
f *= 2.0;
a *= 0.4;
}
return t;
}
float fbmSea(vec2 pos)
{
vec2 firstDir = vec2(0.8, 0.2);
float angle = 0.5;
float f = 1.2;
float s = 3.2;
float a = 1.0;
float t = 0.05;
for(float i = 0.0; i < 4.0; i++)
{
vec2 dir = rotate(firstDir, i * angle);
float sDist = sdf_line(pos, vec2(0.0), dir);
t += a * noise(f * (sDist - s * iTime));
s *= 0.8;
f *= 0.7;
a *= 0.3;
}
return t;
}
float sdSea(vec3 pos)
{
// ground
float fh = -2.0 + noise(0.5 * (pos.z + 1.8 * iTime));//-2.0;
float oneDpos = sdf_line(pos.xz, vec2(0.0), vec2(1.0));
fh = -2.0 + noise(0.5 * (oneDpos - 1.8 * iTime));
fh = -6.0 + fbmSea(pos.xz);
return pos.y - fh;
}
float map( in vec3 pos)
{
return sdSea(pos);
}
#define MAX_STEPS 200; //Dosnt work, rewrite manualy
#define SURFACE_DIST 0.001;
#define MAX_DIST 100.0;
#define MIN_DIST 0.2;
float castRay( in vec3 ro, in vec3 rd)
{
float tmin = MIN_DIST;
float tmax = MAX_DIST;
float surfDistMin = SURFACE_DIST;
float t = tmin;
for( int i=0; i<150; i++ )
{
float h = map( ro+rd*t);
//abs increases stability non euklidian mapping after the reymarch steps into
//the sdf. the "* t" increases the mistake for farther objects.
if( abs(h)tmax ) t=-1.0;
return t;
}
vec3 calcNormal( in vec3 pos)
{
vec2 e = vec2(0.0005, 0.0);
return normalize( vec3(
map( pos + e.xyy) - map( pos - e.xyy),
map( pos + e.yxy) - map( pos - e.yxy),
map( pos + e.yyx) - map( pos - e.yyx) ) );
}
float getDiffuse(vec3 normal, vec3 lightDir)
{
float diffuseLight = clamp(dot(normal, lightDir), 0. , 1.0);
return diffuseLight;
}
float getMinnaert(vec3 normal, vec3 lightDir, vec3 viewDir)
{
float diffuseLight = clamp(dot(normal, lightDir), 0. , 1.0);
float NdotL = max(0.0, dot( normal, lightDir));
float NdotV = max(0.0, dot( normal, viewDir));
float roughness = 0.15;
float minnaert = saturate( NdotL * pow(NdotL * NdotV, roughness));
return minnaert;
}
float getSpecular(vec3 pos, vec3 normal, vec3 lightPos, vec3 viewDir)
{
viewDir = normalize(viewDir);
vec3 reflectDir = reflect(normalize(lightPos - pos), normal);
return pow(max(dot(-viewDir, reflectDir), 0.0), 32.0);
}
//Returns the RayDirection for a pixel given the ray origin, the look at vector and a zoom factor.
vec3 cameraRayDirection(vec2 uv, vec3 rayOrigin, vec3 lookAt, float zoom)
{
vec3 forwardDir = normalize(lookAt - rayOrigin);
vec3 rightDir = normalize(cross(vec3(0, 1, 0), forwardDir));
vec3 upDir = cross(forwardDir, rightDir);
vec3 centerOfScreen = rayOrigin + forwardDir * zoom;
vec3 intersectionOfScreen = centerOfScreen + uv.x * rightDir + uv.y * upDir;
return intersectionOfScreen - rayOrigin;
}
vec3 render(vec2 uv)
{
vec3 rayOrigin = vec3(0.0, 0.0, 0.0);
vec3 lookAt = vec3(0, 0, 6.0);
vec3 lightDir = normalize(vec3(20.0, 10.0, 5.0));
vec3 rayDirection = cameraRayDirection(uv, rayOrigin, lookAt, 1.);
float dist = castRay(rayOrigin, rayDirection);
vec3 pos = rayOrigin + rayDirection * dist;
vec3 normal = calcNormal(pos);
float diffuse = getDiffuse(normal, lightDir);
float minnaert = getMinnaert(normal, lightDir, rayDirection);
float spec = getSpecular(pos, normal, vec3(130, 20, -300), rayDirection);
vec3 lightCol = diffuse * vec3(0.02) + minnaert * vec3(0.6) + spec * vec3(0.8);
float maxDist = MAX_DIST;
float stars = pow(hash2d(uv), 800.0);
vec3 background = vec3(stars);
//dist negative for to far fields
float mountainFBM = 0.5 * fbmMountains(8.0 * uv.x - 15.0);
float yDisplacement = 0.08;
vec3 mountainColor = vec3(0.018);
for (float i = 0.0; i < 8.0; i++)
{
float mountainFBM = 0.3 * fbmMountains(8.0 * uv.x - 15.0 - i * 0.04);
float mountainFact = step(mountainFBM, uv.y + yDisplacement + 0.005 * i);
mountainColor *= 0.6;
background = mix(mountainColor, background, mountainFact);
}
//float moonFact = step(length(uv - vec2(-0.6, 0.35)), 0.020);
float moonFact = smoothstep(0.028, 0.020, length(uv - vec2(-0.6, 0.35)));
vec3 moonCol = mix(vec3(0.9), vec3(0.1), step(length(uv - vec2(-0.563, 0.35)), 0.04));
vec3 moon = mix(background, moonCol, moonFact);
background = moon;
vec3 finalCol = mix(lightCol, background, step(maxDist, dist));
return finalCol;
}
void main()
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = (sv - 0.5) * iResolution.xy / iResolution.y;
// Time varying pixel color
vec3 col = render(uv);
//Gama correction
col = pow( col, vec3(0.4545));
// Output to screen
gl_FragColor = vec4(col ,1.0);
}