1

I was looking into fast glsl blur effects which render quickly regardless of size. That led me to this article that describes the use of box blurs to simulate Gaussian blurs.

The box blur is faster for large kernels since a weighted average can be used. However to use a weighted average you need to read the pixels from a texture individually.

That's impossible I thought! Until I saw this line of code in their fragment shader on line 7:

imageStore( uTex1, ivec2( x, y ), vec4( colourSum * recKernelSize, 1.0 ) 

I looked at the openGL wiki and found this page, which describes using images like 2d arrays, where you can access pixels arbitrarily.

However setting this up you need to use image units instead of texture units. I tried to find documentation on this for webgl, but even google left me with nothing.

So can image units be utilized in webgl, and if so how would I go about setting one up?

Edit: Also can an existing texture be converted into an image unit?

YAHsaves
  • 1,697
  • 12
  • 33

2 Answers2

1

Image Load/Store is not available to WebGL 2.0, but you don't need Image Load/Store just to be able to fetch data for a specific texel. texelFetch indexes the texture by integer texels rather than by floating-point texture coordinates, and that is available to WebGL 2.0.

But really, it's not that hard to make texture fetch from integer coordinates, so long as you use nearest filtering and provide the texture resolution to the shader via a uniform.


FYI:

Also can an existing texture be converted into an image unit?

Textures contain one or more images. An image unit is an indexed location to which you bind one of the images stored in a texture. You're just saying "access mipmap layer X of this texture as an image"; no "conversion" happens.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Thank you! This helps a lot, yes I understand fetching a single texel from a texture can be done by calculating the coordinates, but the box blur algorithm processes the pixels one at a time. As far as I know this can't be done using textures. – YAHsaves Aug 24 '19 at 03:03
  • @YAHsaves: "*the box blur algorithm processes the pixels one at a time. As far as I know this can't be done using textures*" ... why not? – Nicol Bolas Aug 24 '19 at 03:04
  • If the kernel is 7x7, the box blur calculates the average of the first 7 pixels. Then when it shifts to the next pixel it adds the new pixel to the weighted value, while subtracting the left most pixel. Always keeping 7 pixels in the weighted average. How can you only average 7 pixels at a time with textures? – YAHsaves Aug 24 '19 at 03:08
  • @YAHsaves: You have confused a specific algorithm with the *objective*. A 7x7 box filter computes a pixel value by taking the nearest 7 pixels to that pixel and averaging them together. Exactly *how* you accomplish that is distinct from what you're trying to accomplish. The algorithm you cite is not a useful one for shaders, but that shouldn't stop you from finding an algorithm more appropriate to a shader. – Nicol Bolas Aug 24 '19 at 03:10
  • Yes good point, unfortunately that is the only algorithm I could find that didn't add complexity as the blur size increased. I saw this algorithm implemented in glsl as I linked to above, which is why I tried to understand how it could work in webgl. I guess I'll keep looking though, thanks for your help! – YAHsaves Aug 24 '19 at 03:12
  • @YAHsaves: It's using a compute shader, which is not a thing in WebGL yet either. – Nicol Bolas Aug 24 '19 at 03:24
0

This has been answer probably at least 12 times before but I'm too lazy and S.O. search is bad so ...

In WebGL1 you can look up a pixel in a texture by setting filtering to NEAREST and using

vec4 color = texture2D(someSampler, (pixelCoord + 0.5) / textureResolution);

So for example if your texture is 75x35 and you want to look up pixel 15,31 then

vec2 textureResolution = vec2(75, 35);
vec2 pixelCoord = vec2(15, 31);
vec4 color = texture2D(someSampler, (pixelCoord + 0.5) / textureResolution);

Of course normally you'd probably make textureResolution a uniform so you can pass it in and pixelCoord based on some formula or data

In WebGL2 you can use texelFetch which takes integer coordinates and a mip level

ivec2 pixelCoord = ivec2(15, 31);
int mipLevel = 0;
vec4 color = texelFetch(someSampler, pixelCoord, mipLevel);

As for blurring this article does 3x3 kernel.

gman
  • 100,619
  • 31
  • 269
  • 393
  • Thanks Gman for your added input! I tried to search for this question on SO before asking it, sorry I couldn't find the answer. Question though, you mentioned sampling a single pixel with WebGL1 using texture2D. Is that going to be as slow as sampling an entire texture? Say I wanted to implement the box blur algorithm I linked to where each pixel needs to be referenced individually. I would be calling texture2D over 2 million times, but only for a single pixel. I'm guessing this would count as 2 million texture calls and bring everything to a crawl? – YAHsaves Aug 26 '19 at 22:15