# How to blur a background Texture?

**URL:** <https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433>\
**Category:** Questions\
**Tags:** image, background, blurry, textures\
**Created:** [June 20, 2022, 12:40pm UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433 "2022-06-20T12:40:55Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![vois](https://avatars.discourse-cdn.com/v4/letter/v/8e8cbc/32.png) [@vois](https://discourse.threejs.org/u/vois)\
**Post date:** [June 20, 2022, 12:40pm UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/1 "2022-06-20T12:40:56Z")

</div>

Hi everyone,  
I have a png image that I want to load it as texture. But, I want to show it blurry, like this:  
Original image loaded:

 ![immagine](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/0/9/09dc4406f5ed4571d817df7fbf2ac7e36d405b67.jpeg)  
Want to achive this:  
 ![Gull_portrait_ca_usa](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/b/0/b034e31809dcefec5a2090cf515729046290383b.jpeg)

This is my source code:

```javascript
const backgroundImg = './assets/backgroundImg.png';
this.bgTexture = await new TextureLoader().loadAsync(backgroundImg);
// how to make loaded image blurry?
this.scene.background = this.bgTexture;

```

thanks for the replies

---

<div class="post-metadata">

**Author:** ![Ranao](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ranao/32/26878_2.png) [@Ranao](https://discourse.threejs.org/u/Ranao)\
**Post date:** [June 20, 2022, 2:03pm UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/2 "2022-06-20T14:03:45Z")

</div>

add blur to the image

```javascript
let image=new RGBLoader().
image.load( 'bird.png' , img => {
	new BlurredEnvMapGenerator( renderer ).generate( img , 0 )
} )

```

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [June 20, 2022, 2:28pm UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/3 "2022-06-20T14:28:20Z")

</div>

Can you please specify where does `BlurredEnvMapGenerator` come from?

---

<div class="post-metadata">

**Author:** ![Ranao](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ranao/32/26878_2.png) [@Ranao](https://discourse.threejs.org/u/Ranao)\
**Post date:** [June 20, 2022, 3:33pm UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/4 "2022-06-20T15:33:05Z")

</div>

threejs to bvh [BlurredEnvMapGenerator](https://github.com/gkjohnson/three-gpu-pathtracer/blob/75024a97bb7b9e0d58bc401e3bbc8a910797c4f2/example/index.js)

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [June 21, 2022, 4:50am UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/5 "2022-06-21T04:50:57Z")

</div>

Its using mipmap level for bluring  
`gl_FragColor = textureCubeUV( envMap, rayDirection, blur );`

> <https://github.com/gkjohnson/three-gpu-pathtracer/blob/75024a97bb7b9e0d58bc401e3bbc8a910797c4f2/src/utils/BlurredEnvMapGenerator.js>

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [June 21, 2022, 7:56am UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/6 "2022-06-21T07:56:08Z")

</div>

> [@Chaser\_Code](#):
>
> Its using mipmap level for bluring

Just want to add that the code uses the mipmaps from `PMREMGenerator`. These are different ones than the default mipmaps generated by `gl.generateMipmap()`.

Related: [Ability to reuse the PMREM generated texture from scene.environment - #5 by Mugen87](https://discourse.threejs.org/t/ability-to-reuse-the-pmrem-generated-texture-from-scene-environment/37752/5)

Apart from that, I’m not even sure something like `BlurredEnvMapGenerator` is useful for the OP since the original post just adds a “normal” texture to `Scene.background` (so no env map).

It’s probably best if you prepare the texture offline with a tool like GIMP before using it in your app. Alternatively, you can work with render-to-texture and use `HorizontalBlurShader` and `VerticalBlurShader` to apply a gaussian blur and then use the resulting render target as the background.

---

<div class="post-metadata">

**Author:** ![vois](https://avatars.discourse-cdn.com/v4/letter/v/8e8cbc/32.png) [@vois](https://discourse.threejs.org/u/vois)\
**Post date:** [June 21, 2022, 10:05am UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/7 "2022-06-21T10:05:26Z")

</div>

I really appreciate for your replay. Can you show an example how to implement render-to-texture using `HorizontalBlurShader` and `VerticalBlurShader` in order to modify the texture?  
Thanks

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [June 21, 2022, 11:52am UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/8 "2022-06-21T11:52:38Z")

</div>

Here is a complete live example: [Edit fiddle - JSFiddle - Code Playground](https://jsfiddle.net/fse4m0ck/2/)

And the plain code:

```nohighlight
let camera, scene, renderer;

init().then( render );

async function init() {

  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);

  scene = new THREE.Scene();
  
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  const loader = new THREE.TextureLoader();
  const texture = await loader.loadAsync('https://threejs.org/examples/textures/uv_grid_opengl.jpg');
  //scene.background = texture;

  scene.background = blurTexture( texture );

}

function blurTexture(texture) {

  const width = texture.image.width;
  const height = texture.image.height;

  const cameraRTT = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
  const sceneRTT = new THREE.Scene();

  // render targets

  const renderTargetTemp = new THREE.WebGLRenderTarget(width, height);
  const renderTargetFinal = new THREE.WebGLRenderTarget(width, height);

  // shader materials

  const hBlurMaterial = new THREE.ShaderMaterial({
    vertexShader: THREE.HorizontalBlurShader.vertexShader,
    fragmentShader: THREE.HorizontalBlurShader.fragmentShader,
    uniforms: THREE.UniformsUtils.clone(THREE.HorizontalBlurShader.uniforms)
  });

  hBlurMaterial.uniforms.tDiffuse.value = texture;
  hBlurMaterial.uniforms.h.value = 1 / width;

  const vBlurMaterial = new THREE.ShaderMaterial({
    vertexShader: THREE.VerticalBlurShader.vertexShader,
    fragmentShader: THREE.VerticalBlurShader.fragmentShader,
    uniforms: THREE.UniformsUtils.clone(THREE.VerticalBlurShader.uniforms)
  });

  vBlurMaterial.uniforms.tDiffuse.value = renderTargetTemp.texture;
  vBlurMaterial.uniforms.v.value = 1 / height;

  // fullscreen quad

  const planeGeometry = new THREE.PlaneGeometry(2, 2);

  const fullScreenQuad = new THREE.Mesh(planeGeometry, hBlurMaterial);
  sceneRTT.add(fullScreenQuad);

  // first pass

  renderer.setRenderTarget(renderTargetTemp);
  renderer.render(sceneRTT, cameraRTT);
  renderer.setRenderTarget(null);

  // second pass

  fullScreenQuad.material = vBlurMaterial;

  renderer.setRenderTarget(renderTargetFinal);
  renderer.render(sceneRTT, cameraRTT)
  renderer.setRenderTarget(null);
  
  //
  
  return renderTargetFinal.texture;

}

function render() {

  renderer.render(scene, camera);

}

```

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [December 6, 2023, 8:25am UTC](https://discourse.threejs.org/t/how-to-blur-a-background-texture/39433/9 "2023-12-06T08:25:27Z")

</div>

Looks like the `TriangleBlurShader` works a lot better. Here’s an fiddle using triangle blur: [Edit fiddle - JSFiddle - Code Playground](https://jsfiddle.net/s54trkby/).

The function is:

```js
const {OrthographicCamera, Scene, WebGLRenderTarget, ShaderMaterial, UniformsUtils, PlaneGeometry, Mesh, TriangleBlurShader, Vector2} = THREE

function makeTriangleBlurShader(iterations = 10) {
	// Remove texture, because texture is a reserved word in WebGL 2
	const {texture, ...uniforms} = TriangleBlurShader.uniforms

	const TriangleBlurShader2 = {
		...TriangleBlurShader,

		name: 'TriangleBlurShader2',

		uniforms: {
			...uniforms,

			// Replace texture with blurTexture for WebGL 2
			blurTexture: {value: null},
		},
	}

	// Replace texture with blurTexture for WebGL 2
	TriangleBlurShader2.fragmentShader = TriangleBlurShader2.fragmentShader.replace(
		'uniform sampler2D texture;',
		'uniform sampler2D blurTexture;',
	)
	TriangleBlurShader2.fragmentShader = TriangleBlurShader2.fragmentShader.replace(
		'texture2D( texture',
		'texture2D( blurTexture',
	)

	// Make iterations configurable.
	TriangleBlurShader2.fragmentShader = TriangleBlurShader2.fragmentShader.replace(
		'#define ITERATIONS 10.0',
		'#define ITERATIONS ' + iterations + '.0',
	)

	console.log('shader:', TriangleBlurShader2.fragmentShader)

	return TriangleBlurShader2
}

function triangleBlurTexture(
	renderer,
	texture,
	radius = 10,
	passes = 1,
	iterations = 10,
) {
	const width = texture.image.width
	const height = texture.image.height

	// renderer = new WebGLRenderer()

	const cameraRTT = new OrthographicCamera(-1, 1, 1, -1, 0, 1)
	const sceneRTT = new Scene()

	// render targets

	const renderTarget1 = new WebGLRenderTarget(width, height)
	const renderTarget2 = new WebGLRenderTarget(width, height)

	// shader materials

	const shader = makeTriangleBlurShader(iterations)

	const blurMaterial = new ShaderMaterial({
		vertexShader: shader.vertexShader,
		fragmentShader: shader.fragmentShader,
		uniforms: UniformsUtils.clone(shader.uniforms),
	})

	blurMaterial.uniforms.delta.value = new Vector2(1, 1)

	// fullscreen quad

	const planeGeometry = new PlaneGeometry(2, 2)

	const fullScreenQuad = new Mesh(planeGeometry, blurMaterial)
	sceneRTT.add(fullScreenQuad)

	// passes

	let lastTexture = texture

	while (passes--) {
		// vertical pass

		blurMaterial.uniforms.blurTexture.value = lastTexture
		blurMaterial.uniforms.delta.value = new Vector2(radius / width, 0)

		renderer.setRenderTarget(renderTarget1)
		renderer.render(sceneRTT, cameraRTT)
		renderer.setRenderTarget(null)

		lastTexture = renderTarget1.texture

		// horizontal pass

		blurMaterial.uniforms.blurTexture.value = lastTexture
		blurMaterial.uniforms.delta.value = new Vector2(0, radius / height)

		renderer.setRenderTarget(renderTarget2)
		renderer.render(sceneRTT, cameraRTT)
		renderer.setRenderTarget(null)

		lastTexture = renderTarget2.texture
	}

	//

	return lastTexture
}

```

The radius is a lot easier to control with the triangle blur, here for example a value of 40: [Edit fiddle - JSFiddle - Code Playground](https://jsfiddle.net/dcz9pswr/)
