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.