#version 120 // Parameters from our host // x: Scene+Zeit // y: Hoehe // z: Aspec uniform vec4 Y; vec3 L; #define saturate(x) clamp(x, 0, 1) // Maximum/minumum elements of a vector float vmax(vec2 v) { return max(v.x, v.y); } float vmax(vec3 v) { return max(max(v.x, v.y), v.z); } float vmax(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); } float vmin(vec2 v) { return min(v.x, v.y); } float vmin(vec3 v) { return min(min(v.x, v.y), v.z); } float vmin(vec4 v) { return min(min(v.x, v.y), min(v.z, v.w)); } void pR(inout vec2 p, float a) { p = cos(a)*p + sin(a)*vec2(p.y, -p.x); } float fSphere(vec3 p, float r) { return length(p) - r; } // Plane with normal n (n is normalized) at some distance from the origin float fPlane(vec3 p, vec3 n, float distanceFromOrigin) { return dot(p, n) + distanceFromOrigin; } // Cheap Box: distance to corners is overestimated float fBoxCheap(vec3 p, vec3 b) { //cheap box return vmax(abs(p) - b); } // Box: correct distance to corners float fBox(vec3 p, vec3 b) { vec3 d = abs(p) - b; return length(max(d, vec3(0))) + vmax(min(d, vec3(0))); } // Same as above, but in two dimensions (an endless box) float fBox2Cheap(vec2 p, vec2 b) { return vmax(abs(p)-b); } float fBox2(vec2 p, vec2 b) { vec2 d = abs(p) - b; return length(max(d, vec2(0))) + vmax(min(d, vec2(0))); } vec4 mcol = vec4(0); float DE(in vec3 z0){ float r = sqrt(2.0) * 0.5; mcol = vec4(0.8, 0.8, 0.8, 0.7); float d1 = fSphere(z0 + vec3( 0.5, -0.5, 0.5), r); float d2 = fSphere(z0 + vec3( 0.5, 0.5, -0.5), r); float d3 = fSphere(z0 + vec3(-0.5, 0.5, 0.5), r); float d4 = fSphere(z0 + vec3(-0.5, -0.5, -0.5), r); return min(min(min(d1, d2), d3), d4); } float linstep(float a, float b, float t){float v=(t-a)/(b-a);return clamp(v,0.,1.);}//from knighty float rand(vec2 co){// implementation found at: lumina.sourceforge.net/Tutorials/Noise.html return fract(sin(dot(co*0.123,vec2(12.9898,78.233))) * 43758.5453); } float FuzzyShadow(vec3 ro, vec3 rd, float coneGrad, vec2 fragCoord){ float t=0.0,d=1.0,s=1.0; ro+=rd*0.01; for(int i=0;i<16;i++){ //if(s<0.1)continue;//uncommenting this makes shadows and reflections disappear - WTF? float r=t*coneGrad;//radius of cone d=DE(ro+rd*t)+r*0.5; s*=linstep(-r,r,d); t+=abs(d)*(0.5+0.5*rand(fragCoord.xy*vec2(i)))+0.005; } return clamp(s*0.8+0.2,0.0,1.0); } vec3 Background(vec3 rd){return vec3(0.2)*(0.3+0.7*pow(max(0.0,dot(rd,L)),2.0));} void main() { vec3 ro=vec3(0.5,0.7,-0.5)*(0.19+Y.x*0.1) + vec3(-0.2, -0.2, 0.2); vec3 rd = vec3((gl_FragCoord.xy / Y.y - 0.5), 1.0); rd = normalize(vec3(rd.x - Y.z, rd.y, rd.z)); pR(rd.xy,Y.x); pR(rd.yz,-0.717); pR(rd.xz,-0.717); L=normalize(vec3(0.5,0.5,-0.5)); vec3 col=Background(rd); float refl = 1.0; for (int r = 0; r < 12; ++r) { float t=0.0002,d=1.0; for(int i=0;i<48;i++){ if(t>10.0 || d<0.0001) break; t+=d=DE(ro+rd*t); } if(d>0.02) break; ro+=rd*t; mcol=vec4(0.0); const vec2 v=vec2(0.001,0.0); vec3 N=normalize(vec3(-DE(ro-v.xyy)+DE(ro+v.xyy),-DE(ro-v.yxy)+DE(ro+v.yxy),-DE(ro-v.yyx)+DE(ro+v.yyx))); rd=reflect(rd,N); refl*=mcol.w; vec3 scol=mcol.rgb*saturate(dot(N,L)); scol += 4*pow(saturate(dot(rd,normalize(N+L))), 128); float shadowConeGrad = 0.15; scol*=refl*FuzzyShadow(ro,L,shadowConeGrad,gl_FragCoord.xy);//the cone grad could be calculated for each lights position col=mix(scol,col,refl); } col=pow(col,vec3(1.0/2.2)); gl_FragColor = vec4(saturate(col),1.0); }