#ifdef GL_ES
precision mediump float;
#endif
uniform mat3 worldToOutput;
uniform sampler2D inputImage[1];
uniform mat3 outputToInput[1];
mat3 worldToInput = outputToInput[0] * worldToOutput;
uniform float threshold;
uniform float brightness;
uniform float radius;
uniform float angle;
uniform float halo;
float det(mat3 m) { return m[0][0] * m[1][1] - m[0][1] * m[1][0]; }
float scale = sqrt(abs(det(worldToOutput)));
float angle_ = radians(angle);
float sin_ = sin(angle_);
float cos_ = cos(angle_);
float threshold_ = 1.0 - 0.01 * threshold;
float rad_ = radius * scale;
const vec3 lVec = vec3(0.298980712, 0.587036132, 0.113983154);
#define STEPS_PER_PIXEL 4.0
float stepsCount = ceil(STEPS_PER_PIXEL * rad_);
float halo_ = 0.01 * (halo + 1.0) * stepsCount;
float rayWeight(float s)
{
s /= halo_;
return clamp(1.0 - s * s, 0.0, 1.0);
}
vec4 lightValue(const vec2 texCoord)
{
vec4 col = texture2D(inputImage[0], texCoord);
float l = dot(lVec, col.rgb);
return smoothstep(threshold_, 1.0, l) * col;
}
bool filterLine(inout vec4 col, const vec2 p, const vec2 dx, float s_y)
{
float rw = rayWeight(s_y);
if(rw == 0.0)
return false;
float dw = max(1.0 - s_y / stepsCount, 0.0);
col += dw * rw * lightValue(p);
vec2 s = vec2(0.0, s_y);
for(s.x = 1.0; s.x < stepsCount; s.x += 1.0)
{
dw = max(1.0 - length(s) / stepsCount, 0.0);
col += rw * dw * (
lightValue(p + s.x * dx) +
lightValue(p - s.x * dx));
}
return true;
}
void main( void )
{
vec2 texCoord = (outputToInput[0] * vec3(gl_FragCoord.xy, 1.0)).xy;
float step = radius / stepsCount;
mat2 transf =
mat2((worldToInput * vec3(1.0, 0.0, 0.0)).xy,
(worldToInput * vec3(0.0, 1.0, 0.0)).xy) * // worldToInput without translational part
mat2(cos_, sin_, -sin_, cos_) * // angle shift by uniform parameter
step; // [-stepsCount,stepsCount]^2 to [-radius, radius]^2
// Filter lines in the 2 orthogonal directions
vec4 addCol = vec4(0.0);
// Horizontal
filterLine(addCol, texCoord, transf[0], 0.0);
for(float s = 1.0; s < stepsCount; s += 1.0)
{
if(!filterLine(addCol, texCoord + s * transf[1], transf[0], s))
break;
filterLine(addCol, texCoord - s * transf[1], transf[0], s);
}
// Vertical
filterLine(addCol, texCoord, transf[1], 0.0);
for(float s = 1.0; s < stepsCount; s += 1.0)
{
if(!filterLine(addCol, texCoord + s * transf[0], transf[1], s))
break;
filterLine(addCol, texCoord - s * transf[0], transf[1], s);
}
float weight = stepsCount * STEPS_PER_PIXEL;
vec4 col = texture2D(inputImage[0], texCoord);
gl_FragColor = col + addCol * (brightness / weight);
}