varying vec2 destcoords; // destination location uniform sampler2D src; // previous attractor /*---- convert plane-to-texture -------*/ uniform float texscale,texscalei; float T(float x) { // plane to texture x*=texscale; return x/sqrt(1.0+x*x)*0.5+0.5; } vec2 T(vec2 p) { return vec2(T(p.x),T(p.y)); } float P(float s) { // texture to plane float u=2.0*s-1.0; return texscalei*u/sqrt(1.0-u*u); } vec2 P(vec2 s) { return vec2(P(s.x),P(s.y)); } /*---------------- w0 -----------------*/ uniform vec4 color0; uniform vec2 w0x,w0y,w0o; // w0's parameters uniform float w0j,w0v; float jacobian0(vec2 t) {return 1;} vec4 f0(vec2 inv) { // runs at each inverse float area=1e-2+abs(w0j*jacobian0(inv)); vec2 t=T(w0x*inv.x+w0y*inv.y+w0o); return (exp2(texture2D(src,t)*20)-1)/area; } vec4 nonlinear_inverse0(vec2 p) { p=p*w0v; // Draves' variation coefficient return f0(p); } /*---------------- w1 -----------------*/ uniform vec4 color1; uniform vec2 w1x,w1y,w1o; // w1's parameters uniform float w1j,w1v; float jacobian1(vec2 t) { float r2=dot(t,t); return (1-2*t.y*t.y/r2)/r2; } vec4 f1(vec2 inv) { // runs at each inverse float area=1e-2+abs(w1j*jacobian1(inv)); vec2 t=T(w1x*inv.x+w1y*inv.y+w1o); return (exp2(texture2D(src,t)*20)-1)/area; } vec4 nonlinear_inverse1(vec2 p) { p=p*w1v; // Draves' variation coefficient float ix = 0.5/p.x; float det=1 - 4*p.x*p.x*p.y*p.y; if (det>=0) { float sq = sqrt(det); return f1(vec2(ix*(1 - sq),p.y)) +f1(vec2(ix*(1 + sq),p.y)); } else { return vec4(0); } } /* Combined inverse-sampling function */ vec4 sum_inverses(vec2 p) { vec4 sum=vec4(0); sum+=color0*nonlinear_inverse0(p); sum+=color1*nonlinear_inverse1(p); return log2(sum+1)*(1.0/20); } void main(void) { gl_FragColor = sum_inverses(P(destcoords)); }