Files
4kintro/sea.frag

174 lines
4.4 KiB
GLSL

#ifdef GL_ES
precision mediump float;
#endif
#define MAX_STEPS 100
#define MAX_DIST 80.
#define SURF_DIST .001
#define TAU 6.283185
#define PI 3.141592
//#define SUN_DIR vec3(0.5, 0.4, 2.)
#define FOG_DENSITY 0.02
uniform vec2 u_resolution;
uniform float u_time;
struct Obj {
float distance; // distance map
int material; // material Id
};
mat2 Rot(float a) {
float s=sin(a), c=cos(a);
return mat2(c, -s, s, c);
}
float sdBox(vec3 p, vec3 s) {
p = abs(p)-s;
return length(max(p, 0.))+min(max(p.x, max(p.y, p.z)), 0.);
}
vec3 applyFog(in vec3 color, in float distance) {
float fogAmount = 1.0 - exp(-distance*FOG_DENSITY);
vec3 fogColor = vec3(0.1, 0.18, 0.43);
return mix( color, fogColor, fogAmount );
}
vec3 translate(vec3 p) {
p.xy *= Rot(u_time*0.4);
p.yz *= Rot(u_time*0.4);
return p;
}
float opExtrusion( in vec3 p, in float sdf, in float h )
{
vec2 w = vec2( sdf, abs(p.z) - h);
return min(max(w.x,w.y),0.0) + length(max(w,0.0));
}
vec2 opRevolution( in vec3 p, float w )
{
return vec2( length(p.xz) - w, p.y );
}
vec4 opElongate( in vec3 p, in vec3 h )
{
vec3 q = abs(p)-h;
return vec4( max(q,0.0), min(max(q.x,max(q.y,q.z)),0.0) );
}
// Scene
Obj mapScene(vec3 p) {
vec3 p0 = p;
float dGround = p.y - 0.5*(sin(0.4*p.x+u_time*1.)+sin(1.0*p.z+u_time*1.));
dGround *=0.8;
Obj ground = Obj(dGround, 0);
p0.y = dGround + 0.1;
float d1 = length(p0) - 0.3;
Obj ob1 = Obj(d1, 1);
if (ground.distance > ob1.distance) return ob1;
return ground;
}
Obj castRay(vec3 ro, vec3 rd) {
float t = 0.0;
Obj res = Obj(-1., -1);
for(int i=0; i<MAX_STEPS; i++) {
vec3 p = ro + rd * t;
res = mapScene(p);
t += res.distance;
if (t > MAX_DIST || res.distance < abs(SURF_DIST*t) ) break;
}
if (t > MAX_DIST) t = -1.0;
res.distance = t;
return res;
}
float castShadow(vec3 ro, vec3 rd) {
float res = 1.0;
float t = 0.0001;
for(int i=0; i<MAX_STEPS; i++) {
vec3 pos = ro + t* rd;
float h = mapScene(pos).distance;
res = min(res, 10.0*h/t);
if (abs(h) < (0.001*t) ) break;
t += h;
if (t > 20.) break;
}
return clamp(res,0., 1.);
}
vec3 calcNormal(vec3 pos) {
vec2 e = vec2(.0001, 0.);
vec3 n = vec3( mapScene(pos+e.xyy).distance - mapScene(pos-e.xyy).distance,
mapScene(pos+e.yxy).distance - mapScene(pos-e.yxy).distance,
mapScene(pos+e.yyx).distance - mapScene(pos-e.yyx).distance
);
return normalize(n);
}
void main()
{
vec2 p = (2.0 * gl_FragCoord.xy - u_resolution.xy) / u_resolution.y;
float angle = u_time*0.2;
angle = 4.6; // comment to rotate
// camera
vec3 ta = vec3(0.0, .5, 0.0);
vec3 ro = ta + vec3(1.*sin(angle), .7, 2.); // *cos(angle))
vec3 ww = normalize(ta-ro);
vec3 uu = normalize(cross(ww, vec3(0,1,0)));
vec3 vv = normalize(cross(uu,ww));
vec3 rd = normalize(p.x * uu + p.y*vv + 1.3*ww); // camera
// global light
vec3 col = vec3(0.1216, 0.2863, 0.5529) - 0.5*rd.y;
Obj t = castRay(ro, rd);
if (t.distance > 0.) {
vec3 pos = ro + rd * t.distance;
vec3 nor = calcNormal(pos);
// vec3 r = reflect(rd, nor);
vec3 outMaterial = vec3(0.1255, 0.1176, 0.1176);
if (t.material == 0) {
outMaterial = vec3(0.0039, 0.2235, 0.4) + sin(t.distance)*0.1;
} else if (t.material == 1) {
outMaterial = vec3(0.8392, 0.0118, 0.0118);
}
vec3 SUN_DIR = vec3(0.5+sin(u_time*0.1), 0.4, 2.0+sin(u_time*0.2)*0.5);
float sun_dif = clamp(dot(nor, SUN_DIR), 0., 1.);
float sun_sha = castShadow(pos + nor*0.02, SUN_DIR);
float sky_dif = clamp(0.5 + 0.5 * dot(nor, vec3(0.,1.,0.)), 0., 1.);
float bounce_dif = clamp(0.5 + 0.5 * dot(nor, vec3(.7,.5, 0.)), 0., 1.);
// format color + what to apply
col = outMaterial * vec3(2.0,1.5, .2) * sun_dif * sun_dif * sun_sha;
col += outMaterial * vec3(0.0196, 0.2078, 0.4196) * sky_dif;
col += outMaterial * vec3(0.051, 0.0588, 0.5686) * bounce_dif;
// apply fog
col = applyFog(col, t.distance);
}
col = pow(col, vec3(.4545)); // gamma correction
gl_FragColor = vec4(col,1.0);
}