Azzkikr wrote: ↑Fri Dec 13, 2019 10:30 am
I think I found the culprit: when I draw everything to a canvas first (including sprites and 'primitives'), then it works as I expected. I'm not sure why though.
Rectangles are rendered as quads (pairs of triangles). The texture in their interior would be blurred if it wasn't plain, but they are rendered with a texture which consists just of one plain colour, and the effect of blurring can't possibly be seen there. The blurring can't affect the borders, because they are the hard edge of the rectangle and beyond it, nothing is drawn. It can only affect the image drawn inside.
When you draw the rectangle to a canvas that encloses said rectangle, then the whole interior of the canvas is blurred, including the border of the rectangle which is now part of the image. The border of the canvas will still not be blurred, so if it's smaller than the screen, you will still see the hard edges of the canvas when you draw it. Drawing it in full screen should work as you expect.
As for the intensity of the effect, note that (1) you're doing one single pass of an average filter with radius 1 (using "taxi metric", which is the metric where a constant radius delimits a square, not a circle), and (2) the effect can be smaller if the dimensions aren't right.
A radius 1 average is a very crude approximation to a Gaussian filter, and it has a small effect. If you want the effect to be stronger, you need to apply it more times, and/or use a bigger kernel. This "kernel" thing is a fancy word for the weights of the pixels to sum; in your case each pixel has a weight of 1/9 therefore your kernel is a 3x3 matrix full of 1/9's with the target pixel being in the middle of the matrix.
This page:
http://homepages.inf.ed.ac.uk/rbf/HIPR2/gsmooth.htm gives this radius 2 kernel as an approximation of a gaussian filter:
Code: Select all
1 4 7 4 1
4 16 26 16 4
1/273 * 7 26 41 26 7
4 16 26 16 4
1 4 7 4 1
with the target pixel at the centre of the matrix, of course. This means that instead of x-1, x, x+1 you need to go from x-2 to x+2, and same with y, doing something like this (this is pseudocode; in practice you would do it similarly to how you're doing it, but with the bigger radius):
Code: Select all
s = 0
s += image[x-2, y-2] * 1
s += image[x-1, y-2] * 4
s += image[x, y-2] * 7
s += image[x+1, y-2] * 4
s += image[x+2, y-2] * 1
s += image[x-2, y-1] * 4
s += image[x-1, y-1] * 16
...
s += image[x+2, y+2] * 1
s /= 273
If the effect is still not enough for your purposes, I suggest doing two passes: render the canvas to another canvas with the filter active. This method converges quickly to a gaussian no matter the kernel, but even more quickly if the kernel is "good" to start with.
http://nghiaho.com/?p=1159 shows an example with a box kernel (simple average using taxi metric, like the one you're using) that is virtually indistinguishable from a Gaussian after 4 iterations.
As for your comment "I know it's verbose and maybe there's better way to do this... but bear with me", don't be sorry: unrolling the loops is good for performance. Jumps (e.g. backward jumps like the ones needed for loops) badly hurt performance in shaders. Also, applying the kernel is easier with the loops unrolled.