140 lines
3.4 KiB
GLSL
140 lines
3.4 KiB
GLSL
#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);
|
|
}
|