GLSL "glow" effects


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



Glow effects

glow effects used in glChAoS.P


Glow threshold effect

This really is a deNoise bilateral filter with variable sigma radius and threshold

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