Toams wrote:
Yes.
I had written a comment two days ago and was looking something up when my internet bummed out.
I'll try again tomorrow. Could you post the shader code?
The shader code has a lot of custom pre-processing/fixed values that are unique to my engine, so the most I can do is post the blur vertical and horizontal shaders for everyone to use - even they have custom 1/4 resolution texture hard-coded, in the future I will have the buffer size configurable and this 1/4 size setting will be dynamic, but for now here's the blurs as they are.
Excuse the lack of GLSL standards, I haven't optimised any of the shaders and I plan on making them all GLSL 1.40 compliant.
#define TYPE solid is a bwrpg engine specific optimisation, it has no effect on the shader so you can ignore it or remove it, of course if you are using the bwrpg engine you leave the line in ;)
xi_inverseResolution is a vec2() of the inverse size of the target frame buffer
xi_textureSample2 is the glow buffer
Horizontal blur
- #define TYPE solid
-
- vec2 offsetArray[7];
-
- #define STEP_ONE ( 0.25 )
- #define STEP_TWO ( 0.75 )
- #define STEP_THREE ( 1.25 )
-
- void main() {
- offsetArray[0] = vec2( 0.0, 0.0 );
- offsetArray[1] = vec2( -STEP_ONE * xi_inverseResolution.x, 0.0 );
- offsetArray[2] = vec2( STEP_ONE * xi_inverseResolution.x, 0.0) ;
- offsetArray[3] = vec2( -STEP_TWO * xi_inverseResolution.x, 0.0 );
- offsetArray[4] = vec2( STEP_TWO * xi_inverseResolution.x, 0.0 );
- offsetArray[5] = vec2( -STEP_THREE * xi_inverseResolution.x, 0.0 );
- offsetArray[6] = vec2( STEP_THREE * xi_inverseResolution.x, 0.0 );
-
- vec4 blurColour = vec4( 0.0, 0.0, 0.0, 0.0 );
-
- for( int ii = 0; ii < 7; ++ii ) {
- blurColour += texture2D( xi_textureSample2, clamp( gl_TexCoord[0].xy + offsetArray[ii] * 3.0, vec2( 0.001, 0.001 ), vec2( 0.999, 0.999 ) ) );
- }
-
- blurColour *= 0.1429; // divide by 7
-
- gl_FragColor = blurColour;
- }
Expand to see the code.
Vertical blur is the same except the offsetArray has the X and Y flipped:
- offsetArray[1] = vec2( 0.0, -STEP_ONE * xi_inverseResolution.x);
- offsetArray[2] = vec2( 0.0, STEP_ONE * xi_inverseResolution.x ) ;
- offsetArray[3] = vec2( 0.0, -STEP_TWO * xi_inverseResolution.x );
- offsetArray[4] = vec2( 0.0, STEP_TWO * xi_inverseResolution.x );
- offsetArray[5] = vec2( 0.0, -STEP_THREE * xi_inverseResolution.x );
- offsetArray[6] = vec2( 0.0, STEP_THREE * xi_inverseResolution.x );
Expand to see the code.
Also to note, this code is adapted from various free-to-distribute online sources, this method for blurring is well-known so there are probably better/cleaner implementations out there.
The final stage is to blend it with the colour buffer with the new bloom buffer.
xi_textureSample3 is the buffer where we store the blurred result.
xi_textureUV0 is the screen's rectangle texture co-ordinates.
xi_textureSample0 is the colour buffer where we rendered the world normally.
- #define TYPE solid
-
- void main() {
- vec3 bloom = texture2D( xi_textureSample3, xi_textureUV0 ).rgb;
-
- gl_FragColor = vec4( texture2D( xi_textureSample0, xi_textureUV0 ).rgb + bloom, 1.0 );
- }
Expand to see the code.
You could cheat and just use
offsetArray[ii].yx in the loop to avoid having to swap those lines, but I don't think this is as readable as just showing that X and Y are swapped.
To note: There is no reason to combine the alpha, so we only take the rgb channels and we set the alpha to 1.0.
Why do we blur horizontally and vertically?The obvious question is why not blur in a single shader, rather than with two shaders. Simply put, because we can only set one fragment at a time in the shader pipeline if we were to read it's neighbouring fragments in two directions the blur patten would be a + shape, the horizontal blur makes it a - shape and when you vertically blur that you get a square.
The fix for this is to increase the number of fragment reads so the blur takes a square reading of it's neighbouring fragments, however this will cut performance to the point where it's faster to run two post-processing shaders.