uniform float time; uniform vec2 resolution; uniform sampler2D texture_sampler; uniform sampler2D texts; 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); } vec3 applyFog(in vec3 color, in float distance) { float fogAmount = 1.0 - exp(-distance *0.01); vec3 fogColor = vec3(0.17, 0.16, 0.24); return mix( color, fogColor, fogAmount ); } 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)); } float sdCog2d(vec2 pos) { float r = length(pos)*2.; float a = atan(pos.y,pos.x); float f = 1. - smoothstep(-0.2, .8, sin(a * 12.))*0.14; f = smoothstep(f,f + 2.,r); return f; } float opSmoothSubtraction( float d1, float d2, float k ) { float h = max(k-abs(-d1-d2),0.0); return max(-d1, d2) + h*h*0.25/k; } float sdCapsule( vec3 p, vec3 a, vec3 b, float r ) { vec3 pa = p - a, ba = b - a; float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); return length( pa - ba*h ) - r; } float sdCog(vec3 pos, float angle) { pos.xy *= Rot(angle); float d1 = opExtrusion(pos, sdCog2d(pos.xy), 0.15); float d2 = sdCapsule(pos - vec3(0.,0., -0.5), vec3(0., 0.0, 0.), vec3(0., 0., 1.), 0.2); return 0.8 * opSmoothSubtraction(d2,d1,0.02)-0.001; } // Scene Obj mapScene(in vec3 p) { float d = 1e10; float dGround = p.y +1.5 + sin(p.z*0.6)*.2 + sin(p.x*1.3)*.1; Obj ground = Obj(dGround, 0); { float d1 = sdCog(p+vec3(1., 0., 0.), time); d = min(d, d1); } { float d1 = sdCog(p+vec3(0.5, -.87, 0.), -time); d = min(d, d1); } { float d1 = sdCog(p+vec3(0.5, .87, 0.), -time); d = min(d, d1); } Obj ob1 = Obj(d, 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<100; i++) { vec3 p = ro + rd * t; res = mapScene(p); t += res.distance; if (t > 20.0 || res.distance < abs(0.001*t) ) break; } if (t > 20.0) t = -1.0; res.distance = t; return res; } float castShadow(vec3 ro, vec3 rd) { float res = 1.0; float t = 0.001; for(int i = 0; i < 100; 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(.001, 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); } vec3 fresnel( vec3 F0, vec3 h, vec3 l ) { return F0 + ( 1.0 - F0 ) * pow( clamp( 1.0 - dot( h, l ), 0.0, 1.0 ), 5.0 ); } vec3 shading(vec3 v, vec3 n, vec3 dir, int material) { float shininess = 1.; vec3 final = vec3( 0.0 ); vec3 ref = reflect( dir, n ); vec3 Ks = vec3( 0.5 ); vec3 Kd = vec3( 1.0 ); vec3 outMaterial = vec3(0.1255, 0.1255, 0.1255); if (material == 0) { outMaterial = vec3(0.1412, 0.1412, 0.1412); shininess = 3.1; } else if (material == 1) { outMaterial = vec3(0.1765, 0.1961, 0.2275); shininess = 21.; } // light 0 { vec3 light_pos = vec3( -2.,.3, 10. ); vec3 light_color = vec3(0.71, 0.51, 0.72) * 5.; vec3 vl = normalize( light_pos - v ); vec3 diffuse = Kd * vec3( max( 0.0, dot( vl, n ) ) ); vec3 specular = vec3( max( 0.0, dot( vl, ref ) ) ); vec3 F = fresnel( Ks, normalize( vl - dir ), vl ); specular = pow( specular, vec3( shininess ) ); final += outMaterial * specular * light_color * mix( diffuse, specular, F ); } // light 1 { vec3 light_pos = vec3( 5.0, 5.0, -20.0 ); vec3 light_color = vec3(0.14, 0.36, 0.83)* 7.; vec3 vl = normalize( light_pos - v ); vec3 diffuse = Kd * vec3( max( 0.0, dot( vl, n ) ) ); vec3 specular = vec3( max( 0.0, dot( vl, ref ) ) ); vec3 F = fresnel( Ks, normalize( vl - dir ), vl ); specular = pow( specular, vec3( shininess ) ); final += outMaterial * specular * light_color * mix( diffuse, specular, F ); } { vec3 SUN_DIR = vec3(0. , .4, 1.); float sun_dif = clamp(dot(n, SUN_DIR), 0., 1.); float shadow = castShadow(v + n*0.02, SUN_DIR); final += outMaterial * vec3(1.1,1.2, 1.5) * sun_dif * sun_dif * shadow; } { vec3 SUN_DIR = vec3(0. , .6, -1.); float sun_dif = clamp(dot(n, SUN_DIR), 0., 1.); final += outMaterial * vec3(0.0353, 0.2667, 0.4784) * sun_dif; } return final; } void main() { vec2 p = (gl_FragCoord.xy * 2. - resolution.xy) / min(resolution.x, resolution.y); // vec2 p = (2.0 * gl_FragCoord.xy - resolution.xy) / resolution.y; float angle = time*0.4; vec3 ta = vec3(0.0, 0., 0.0); vec3 ro = ta + vec3(4.*sin(angle), cos(angle), 4.*cos(angle)); // *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.4*ww); // camera // global light vec3 col = vec3(0.1451, 0.1098, 0.1608) - vec3(0.9725, 0.5176, 0.0) *rd.y; Obj t = castRay(ro, rd); if (t.distance > 0.) { vec3 pos = ro + rd * t.distance; vec3 nor = calcNormal(pos); col = shading(pos, nor, rd , t.material); // apply fog col = applyFog(col, t.distance); } gl_FragColor = vec4( pow(col, vec3(1.0/1.3) ), 1.0 ); }