GLSL "glow" effects


Using 2D image processing to emphasize the 3D points rendering



Glow effects

glow effects used in glChAoS.P


Bilateral threshold effect

This is typical 2D noise reduction algorithm, with settable/notFixed sigma, that I tried to optimize for GLSL :


//  fX = exp( -(x*x) * invSigmaSqx2 ) * invSigmaxSqrt2PI;
//  fY = exp( -(y*y) * invSigmaSqx2 ) * invSigmaxSqrt2PI;
//  where...
//      invSigmaSqx2     = 1.0 / (sigma^2 * 2.0)
//      invSigmaxSqrt2PI = 1.0 / (sqrt(2 * PI) * sigma)
//
//  now, fX*fY can be written in unique expression...
//
//      e^(a*X) * e^(a*Y) * c*c
//
//      where:
//        a = invSigmaSqx2, X = (x*x), Y = (y*y), c = invSigmaxSqrt2PI
//
//           -[(x*x) * 1/(2 * sigma^2)]             -[(y*y) * 1/(2 * sigma^2)]
//          e                                      e
//  fX = -------------------------------    fY = -------------------------------
//                ________                               ________
//              \/ 2 * PI  * sigma                     \/ 2 * PI  * sigma
//
//      now with...
//        a = 1/(2 * sigma^2),
//        X = (x*x)
//        Y = (y*y) ________
//        c = 1 / \/ 2 * PI  * sigma
//
//      we have...
//              -[aX]              -[aY]
//        fX = e      * c;   fY = e      * c;
//
//      and...
//                 -[aX + aY]    [2]     -[a(X + Y)]    [2]
//        fX*fY = e           * c     = e            * c
//
//      well...
//
//                    -[(x*x + y*y) * 1/(2 * sigma^2)]
//                   e
//        fX*fY = --------------------------------------
//                                        [2]
//                          2 * PI * sigma
//
//      now with assigned constants...
//
//          invSigmaQx2   = 1/(2 * sigma^2)
//          invSigmaQx2PI = 1/(2 * PI * sigma^2) = invSigmaQx2 * INV_PI
//
//      and the kernel vector
//
//          k = vec2(x,y)
//
//      we can write:
//
//          fXY = exp( -dot(k,k) * invSigmaQx2) * invSigmaQx2PI


// reductFactor = 1.0 if used alone -> bilateral threshold
// reductFactor = 0.2 if used with gaussian blur - > gaussian + bilateral
////////////////////////////////////////////////////////////////////
vec4 bilateralSmartSmooth(float reductFactor)
{
    float bsigma = threshold*reductFactor;
    float radius = float(round(sigma.y*sigma.x-1.f));
    float radQ = radius * radius;

    float invSigma = 1.f/sigma.x;
    float invSigmaQx2 = .5 * invSigma * invSigma;           // 1.0 / (sigma^2 * 2.0)
    float invSigmaQx2PI = INV_PI * invSigmaQx2;             // 1.0 / (sqrt(PI) * sigma)
//	float invSigmaxSqrt2PI = INV_SQRT_OF_2PI * invSigma;    // 1.0 / (sqrt(PI) * sigma)

    float invBSigma = 1.f/bsigma;
    float invBSigmaSqx2 = .5 * invBSigma * invBSigma;       // 1.0 / (sigma^2 * 2.0)
    float invBSigmaxSqrt2PI = INV_SQRT_OF_2PI * invBSigma;  // 1.0 / (sqrt(2*PI) * sigma)

    vec4 centrPx = texelFetch(origTexture,ivec2(gl_FragCoord.xy),0);

    float Zbuff = 0.0;
    vec4 accumBuff = vec4(0.0);

    vec2 d;
    for (d.x=-radius; d.x <= radius; d.x++)	{
        float pt = sqrt(radQ-d.x*d.x);
        for (d.y=-pt; d.y <= pt; d.y++) {
            float blurFactor = exp( -dot(d , d) * invSigmaQx2 ) * invSigmaQx2;

            vec4 walkPx =  texelFetch(origTexture, ivec2(gl_FragCoord.xy+d),0 );
            vec4 dC = walkPx-centrPx;
            float deltaFactor = exp( -dot(dC, dC) * invBSigmaSqx2) * invBSigmaxSqrt2PI * blurFactor;

            Zbuff     += deltaFactor;
            accumBuff += deltaFactor*walkPx;
        }
    }
    return accumBuff/Zbuff;
}
            

Gaussian blur algorithm

Classic 2-pass gaussian blur algorithm, with settable/notFixed sigma, applied to a two-dimensional texture as two independent one-dimensional calculations, so for any pixel we processing 2*sigma fragments, instead of sigma*sigma
The algorithm is mixed with original texture to obtain the glow effect: the mixing parameters are settable.

vec4 gPass(sampler2D tex, vec2 direction)
{
    //vec2 offset = wSize;

    //compute the radius across the kernel
    float radius = sigma.y*sigma.x-1.f;

    float Zbuff = 0.0;
    vec4 accumBuff = vec4(0.0);

    //precompute factors used every iteration
    float invSigma = 1.f/sigma.x;
    float invSigmaSqx2 = .5 * invSigma * invSigma;          // 1.0 / (sigma^2 * 2.0)
    float invSigmaxSqrt2PI = INV_SQRT_OF_2PI * invSigma;    // 1.0 / (sqrt(PI) * sigma)

    // separable Gaussian
    for (float r = -radius; r <= radius; r++) {
        float factor = exp( -(r*r) * invSigmaSqx2 ) * invSigmaxSqrt2PI;
        vec4 c = texelFetch(tex, ivec2(gl_FragCoord.xy + r * direction), 0);
        accumBuff += factor * c;
    }

    return accumBuff;
}

//  Pass1 Gauss Blur
////////////////////////////////////////////////////////////////////////////
vec4 radialPass1()
{
    return gPass(origTexture, vec2(1.0, 0.0));
}

//  Pass2 Gauss Blur
////////////////////////////////////////////////////////////////////////////
vec4 radialPass2()
{
    vec4 original = texelFetch(origTexture,ivec2(gl_FragCoord.xy),0) * texControls.y; //origTex * intensity
    vec4 blurred = gPass(pass1Texture, vec2(0.0, 1.0))* texControls.x;                //blur * intensity

    return mix(original,blurred,mixTexture); // return blurred texture, mixed with original

}
        

Gaussian + bilateral threshold effect

vec4 gPass(sampler2D tex, vec2 direction)
{
    //vec2 offset = wSize;

    //compute the radius across the kernel
    float radius = sigma.y*sigma.x-1.f;

    float Zbuff = 0.0;
    vec4 accumBuff = vec4(0.0);

    //precompute factors used every iteration
    float invSigma = 1.f/sigma.x;
    float invSigmaSqx2 = .5 * invSigma * invSigma;          // 1.0 / (sigma^2 * 2.0)
    float invSigmaxSqrt2PI = INV_SQRT_OF_2PI * invSigma;    // 1.0 / (sqrt(PI) * sigma)

    // separable Gaussian
    for ( float r = -radius; r <= radius; r++) {
        float factor = exp( -(r*r) * invSigmaSqx2 ) * invSigmaxSqrt2PI;
        vec4 c = texelFetch(tex, ivec2(gl_FragCoord.xy + r * direction), 0);
        accumBuff += factor * c;
    }

    return accumBuff;
}

//  Pass1 Gauss Blur
////////////////////////////////////////////////////////////////////////////
vec4 radialPass1()
{
    return gPass(origTexture, vec2(1.0, 0.0));
}

//  Pass2 Gauss Blur + threshold -> reduced (1/4) bilateral
////////////////////////////////////////////////////////////////////////////
vec4 radialPass2withBilateral()
{
    vec4 original = texelFetch(origTexture,ivec2(gl_FragCoord.xy),0) * texControls.y;
    vec4 blurred = gPass(pass1Texture, vec2(0.0, 1.0))* texControls.x;
    vec4 newBlur = bilateralSmartSmooth(.2) * texControls.z;

    return newBlur;
}