There is a geometry in the scene. The texture on it requires two one -dimensional Gaussian blur. How does this image processing process be implemented with Threejs?
If you need to blur a texture on every frame dynamically, you should probably do it in a custom shader code.
The quickest and dirtiest solution I know is to fake uv gradient when sampling a texture, itās not Gaussian blur, but it looks like a blur (especially at a low blur strength):
Thank you for your replyć
No need for dynamic blurć I hope to finish processing this image and save it as a texture, or export it as wellć Because it requires two blurs and two fragement shaders.
You can load your image using TextureLoader into THREE, then render it on WebGLRenderTarget using custom shader that does Gaussian blur. Render target has a property .texture that you then can use for all intents and purposes.
I konw this solution ļ¼but how to set camera ? use OrthographicCamera? Original webgl, or like shdertoy, does not need a camera, but Threejs does not seem to workć
The easiest is to work in NDC space, so you need to create BufferGeometry with 4 vertices located at the corners of NDC space (-1, 1) on X and Y and zero Z, to make a quad that will fill in the screen.
Use ShaderMaterial with that to make a mesh.
You vertex shader will look something like this:
varying vec2 vuv;
void main() {
gl_Position = vec4(position, 1.0);
vuv = uv;
}
your frag shader will do the blur.
You wonāt use any matrices, so your camera setup will not be used, THREE requires a camera to work, so define any camera as a plug, it wonāt matter.
yeah! I forget this. Thank youļ¼ļ¼
Another option is to pass the image through canvas 2D and use its blurring filter (i.e. no shaders, no render targets, no separate cameras).
Its work! I also had a solution similar to this idea beforeć
It is to use SVG to draw images, and use SVGās built-in Gaussian filters and cropping to achieve the desired results, and then use the SVG image as a texture to paste on the geometry. But this is constantly generating images, and the interface is somewhat blocked.
Iāve been trying to figure out how to use a Gaussian blur in three.js. If I were doing this in openFrameworks, I would do multiple passes with two shaders, one for x and y each. But it seems that in three.js, when using a shader material on a single mesh (not global post-processing), you either need to stack multiple meshes in the same shape, which is not good for performance, or do everything in one shader. Iāve been trying to do the latter, with limited success.
Here is the code for my fragment shader. This is the best Iāve been able to get, but the blur is not very smooth:
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D u_tex;//u_camTexL, u_camTexR;
uniform vec2 u_res;
uniform float u_blurAmount;
float a = 0.000229;
float b = 0.005977;
float c = 0.060598;
float d = 0.241732;
float e = 0.382928;
float f = 0.241732;
float g = 0.060598;
float h = 0.005977;
float i = 0.000229;
varying vec2 vUv;
void blurPass(inout vec4 color, sampler2D tex, vec2 coord, vec2 res, int passAmount)
{
for(int pass = 0; pass < passAmount; ++pass)
{
//I'm a little uncertain on my use of res here, since I'm using a varying uv. I'm passing in the viewport size, but it mostly allows me to input larger values for u_blurAmount
vec2 blurX = vec2(u_blurAmount / res.x, 0.0) / pow(2.0, float(pass));
vec2 blurY = vec2(0.0, u_blurAmount / res.y) / pow(2.0, float(pass));
color += a * texture2D(tex, coord + blurX * -4.0);
color += b * texture2D(tex, coord + blurX * -3.0);
color += c * texture2D(tex, coord + blurX * -2.0);
color += d * texture2D(tex, coord + blurX * -1.0);
color += e * texture2D(tex, coord + blurX * 0.0);
color += f * texture2D(tex, coord + blurX * 1.0);
color += g * texture2D(tex, coord + blurX * 2.0);
color += h * texture2D(tex, coord + blurX * 3.0);
color += i * texture2D(tex, coord + blurX * 4.0);
color += a * texture2D(tex, coord + blurY * -4.0);
color += b * texture2D(tex, coord + blurY * -3.0);
color += c * texture2D(tex, coord + blurY * -2.0);
color += d * texture2D(tex, coord + blurY * -1.0);
color += f * texture2D(tex, coord + blurY * 1.0);
color += g * texture2D(tex, coord + blurY * 2.0);
color += h * texture2D(tex, coord + blurY * 3.0);
color += i * texture2D(tex, coord + blurY * 4.0);
color /= (2.0 * (a + b + c + d) + e) * 2.0; //this normalization is not quite right. As you can see below, the output is a bit darker than the original.
}
}
void main()
{
vec2 coord = vUv;
vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
blurPass(color, u_tex, coord, u_res, 1);
gl_FragColor = color;
}
original image:

shader output:

I necro-posted because I tried looking at @tfoller 's jsfiddle example but the output is just a black screen with the xyz lines. Any advice is appreciated!
EDIT: The darkened image problem is at least partly fixed by overriding the alpha to 1.0 at output.
Thanks for letting me know!
Unsplash public API for random images doesnāt seem to work anymore, thatās the reason for the empty canvas.
I fixed it:
Use āblurā checkbox to compare blurred image vs the original.
Also, I commented out the wave distortion in the shader code:
//uv.x = 0.5 * (1.0 + amp * sin(freq * vuv.y + time)) + (1.0 - amp) * (uv.x - 0.5);
turn it back on, if you need it.
Ah, thanks. Yeah, Iād tried replacing that url but didnāt notice I needed to click ārunā.
So neither yours nor the one I posted is a nice, smooth gaussian. The textureGrad one is blocky, but it is interesting how it seems to change resolution depending on how close the camera is to it:
whereas the gaussian attempt I posted creates the effect of an image being split into four directions:
Seems itās quite a difficult problem to get a smooth, evenish distribution of the colors in one pass.
Still, I guess these are two interesting effects in their own way.
Technically, it is not a problem. You just need two nested loops, one for horizontal blur, and one for vertical. Computationally, however, it is a problem, because instead of 2n, the number of texture samplings raises to n2. For large n even the best GPU will choke.
One loop with mixed horizontal and vertical samplings will create vertically and/or horizontally biased blurs.
it may be a little unorthodox but you can also use plain old meshphysicalmaterial + transmission + roughness on a plane mesh in front of your image. it has that blocky look though, for better results use meshtransmissionmaterial which you will find for vanilla as well. it looks more like frosted glass though.
it looks like this https://codesandbox.io/p/sandbox/frosted-glass-imn42
My code is not Gaussian blur, as far as I remember, it āfakesā uv gradient in textureGrad call, forcing GPU to choose a lower resolution mipmap then necessary, that mipmap is then stretched over the quad, so youāre essentially looking at bilinear interpolation (?) upsampling of a mipmap. It is very fast, not sure if you can improve the quality of that, my memory in this matters faded away, I donāt do that much 3D anymoreā¦
Yeah, I was taking the demands of a gaussian blur for granted, since I usually do it in a c+±made exe, which is probably faster to begin with than something in the browser. Also, Iāve only ever done it for maximum of five textures. In contrast, Iām able to use your mipmapBlur (and also my bias simple-Gaussian) on 500 meshes at once, and it seems to run fine- havenāt tried it on older mobile devices yet though.


