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)); |
}
|