Post Processing Bloom Effect & Composer Only Creating White Screen

Hello!
This problem has been posted by others before, but not resolved from what I can see. I have a program that runs fine, but the moment that I include post processing effects like Composer and BloomPass all I get is a solid white screen for output. No, this is not because the light is set too high, I’ve set my light intensity about as low as I can. This is also not because the computers I have cannot handle the effects.
Example: this React version will likely initially load as white output, but then auto-loads the required dependencies that will then properly display the exact bloom effects I’m looking for. https://codesandbox.io/p/sandbox/bloom-hdr-workflow-gnn4yt?file=%2Fsrc%2Findex.js I can interact with the shapes and you’ll be able to do the same and see the bloompass effect.
This is what I am trying to get into my version, but no matter what adjustments I make I cannot get it to work.

What I want to do is reference these dependencies in my HTML file:

<script src="https://cdn.jsdelivr.net/npm/three/examples/jsm/postprocessing/RenderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three/examples/jsm/postprocessing/UnrealBloomPass.js"></script>

and to implement the js portion I tried adding this:

    const composer = new THREE.EffectComposer(renderer);
    const renderPass = new THREE.RenderPass(scene, camera);
    composer.addPass(renderPass);

    const bloomPass = new THREE.UnrealBloomPass(
        new THREE.Vector2(window.innerWidth, window.innerHeight),
        0.2, // Strength of the bloom
        0.2, // Radius
        0.35 // Threshold
    );
    composer.addPass(bloomPass);

By all accounts this should work, but as mentioned, all I get is a white screen. Per the React Three example that I provided, that clearly works, and I think the same applies to my code. The issue seems to be that I cannot get the dependencies that I need. I don’t know, maybe that’s wrong, but all I know is my code works fine otherwise. It’s when I try to add bloom effects that everything goes white. How can I get these effects to work on individual light sources that I add?

1 Like

You can’t import the source files via the script tag like that. You have to use ES6 import syntax. Use the source code of this demo as a reference: webgl_postprocessing_unreal_bloom

Besides, don’t forget to add an instance of OutputPass to your effect chain otherwise tone mapping and output color space conversion is missing.

composer.addPass( new OutputPass() );
1 Like

I’m trying see project files for reference and it’s not letting me view or see any of the source to reference how this is done. I’m not sure how this is done in ES6 so I’m stuck on how this is referenced. Is there no way to see source files for the WebGL postprocessing example that you provided? I clicked all links and nothing is working.

see How to View the HTML Source Code of a Web Page

Yes, I’ve known how to view page source since 1999, and that’s exactly the problem I’m having nothing is coming up when it would normally come up from right-clicking. Nothing is displaying.

Aside from the fact that right-clicking does nothing on that page, I cannot see how it’s being done, so I’ve put in the following into my js file:
import * as THREE from ‘three’;
import { EffectComposer } from ‘three/addons/postprocessing/EffectComposer.js’;
import { RenderPass } from ‘three/addons/postprocessing/RenderPass.js’;
import { UnrealBloomPass } from ‘three/addons/postprocessing/UnrealBloomPass.js’;
import { OutputPass } from ‘three/addons/postprocessing/OutputPass.js’;

and according to the threejs website, this is how to properly import it, and even though I added instance of OutputPass like so:
const outputPass = new OutputPass();
composer.addPass(outputPass);

I’m still getting a solid white screen. What am I still missing?

copy the text in " " into the browser

“view-source:three.js webgl - postprocessing - unreal bloom

works for me with Chrome and Firefox

It’s not much code: :slightly_smiling_face:

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - postprocessing - unreal bloom</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
		<style>
		#info > * {
			max-width: 650px;
			margin-left: auto;
			margin-right: auto;
		}
		</style>
	</head>
	<body>

		<div id="container"></div>

		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - Bloom pass by <a href="http://eduperiment.com" target="_blank" rel="noopener">Prashant Sharma</a> and <a href="https://clara.io" target="_blank" rel="noopener">Ben Houston</a>
			<br/>
			Model: <a href="https://blog.sketchfab.com/art-spotlight-primary-ion-drive/" target="_blank" rel="noopener">Primary Ion Drive</a> by
			<a href="http://mjmurdock.com/" target="_blank" rel="noopener">Mike Murdock</a>, CC Attribution.
		</div>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';

			import Stats from 'three/addons/libs/stats.module.js';
			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
			import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
			import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
			import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
			import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';

			let camera, stats;
			let composer, renderer, mixer, clock;

			const params = {
				threshold: 0,
				strength: 1,
				radius: 0,
				exposure: 1
			};

			init();

			async function init() {

				const container = document.getElementById( 'container' );

				clock = new THREE.Clock();

				const scene = new THREE.Scene();

				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 100 );
				camera.position.set( - 5, 2.5, - 3.5 );
				scene.add( camera );

				scene.add( new THREE.AmbientLight( 0xcccccc ) );

				const pointLight = new THREE.PointLight( 0xffffff, 100 );
				camera.add( pointLight );

				const loader = new GLTFLoader();
				const gltf = await loader.loadAsync( 'models/gltf/PrimaryIonDrive.glb' );

				const model = gltf.scene;
				scene.add( model );

				mixer = new THREE.AnimationMixer( model );
				const clip = gltf.animations[ 0 ];
				mixer.clipAction( clip.optimize() ).play();

				//

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.setAnimationLoop( animate );
				renderer.toneMapping = THREE.ReinhardToneMapping;
				container.appendChild( renderer.domElement );

				//

				const renderScene = new RenderPass( scene, camera );

				const bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
				bloomPass.threshold = params.threshold;
				bloomPass.strength = params.strength;
				bloomPass.radius = params.radius;

				const outputPass = new OutputPass();

				composer = new EffectComposer( renderer );
				composer.addPass( renderScene );
				composer.addPass( bloomPass );
				composer.addPass( outputPass );

				//

				stats = new Stats();
				container.appendChild( stats.dom );

				//

				const controls = new OrbitControls( camera, renderer.domElement );
				controls.maxPolarAngle = Math.PI * 0.5;
				controls.minDistance = 3;
				controls.maxDistance = 8;

				//

				const gui = new GUI();

				const bloomFolder = gui.addFolder( 'bloom' );

				bloomFolder.add( params, 'threshold', 0.0, 1.0 ).onChange( function ( value ) {

					bloomPass.threshold = Number( value );

				} );

				bloomFolder.add( params, 'strength', 0.0, 3.0 ).onChange( function ( value ) {

					bloomPass.strength = Number( value );

				} );

				gui.add( params, 'radius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {

					bloomPass.radius = Number( value );

				} );

				const toneMappingFolder = gui.addFolder( 'tone mapping' );

				toneMappingFolder.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {

					renderer.toneMappingExposure = Math.pow( value, 4.0 );

				} );

				window.addEventListener( 'resize', onWindowResize );

			}

			function onWindowResize() {

				const width = window.innerWidth;
				const height = window.innerHeight;

				camera.aspect = width / height;
				camera.updateProjectionMatrix();

				renderer.setSize( width, height );
				composer.setSize( width, height );

			}

			function animate() {

				const delta = clock.getDelta();

				mixer.update( delta );

				stats.update();

				composer.render();

			}

		</script>

	</body>

</html>

It just says this page cannot be displayed. This is the first time I’ve encountered the inability to view page source of anything, but this is also my first time using three.js but there should be no reason why this isn’t working. However, I followed the same syntax that threejs.org specifies on this page: https://threejs.org/docs/#manual/en/introduction/How-to-use-post-processing so I have no idea what I’m still leaving out. As I mentioned above, I also made sure to add the instance of OutputPass like Mugen87 said, and it still isn’t working.

Exactly! That’s how I did it per my above example in my previous message, but it’s still not working.

Sometimes computers do strange things. I turn the thing off and let it rest. After restarting it sometimes works - but not always!!!

You now have the code above.

Then I can recommend the collection

e.g. from 2024 eXtended eXamples

1 Like

You are correct, I do now have the code and I greatly appreciate that assistance. However, when I run it exactly as-is inside of an index.html file, this is what I get:

It’s very cool, and I would love to have my projects display the bloom effect as well, but no matter what, all I get is white.

Have you installed a local server? This has been essential since ES6 modules at the latest. When I started with three.js in 2017, I was able to start the examples simply by clicking in the folder.

I have tried this on my regular server online as well as just trying to open the file locally on my computer, but neither has worked. Let me ask you, given the above screenshot that I provided of the code that you supplied me, what does that tell you about my situation? Because given the original example that I included, https://codesandbox.io/p/sandbox/bloom-hdr-workflow-gnn4yt?file=%2Fsrc%2Findex.js the effect clearly runs on my machine/laptops and other desktop computers, both PC and Mac, but nothing is working with my code, but I know my code is not the problem. This has to be a separate dependency issue. What do you think is going on? I’m happy to also supply my code if that would help too.

That is difficult to say. Do you have the import folder correctly?

Have you downloaded the correct three.js revision in full and in the right place?

I use a simplified schema for my collection, but it requires some customization. Not sure if you should start this way as a beginner.

But have a look at the notes
Module usage … Local use of the examples
at the bottom of * discourse.threejs.hofk.de

Try to see if you can get examples from my collection to work correctly.

Everything is running in the 2017 folder that is not using bloom effects. Otherwise, I’m just getting solid white just like before.

Hey, I was having problems with it as well and with the help of others I could find the answer.

First of all, if you are using toneMapping, render it after the bloom, I was hours trying to make bloom work to only realize I was rendering toneMapping first.

Also I didn’t use the postprocessing embedded in three js, but used the postprocessing library, don’t know if there are so many differences though but this was the one that worked for me.

set the luminanceThreshold to 1 in the bloom properties and use emissive and emissiveIntensity on the material you want make glow.

These were the things that worked for me after struggling with it.

I really appreciate the response, and maybe you could clarify some more things for me, because I would love to be past the struggling part and have this work. I tried setting my tonemapping after rendering the bloom but maybe I did something wrong. Also, I’m not sure what you mean by postprocessing embedded in three js, but the library. Here’s my code for the js program:

import * as THREE from ‘three’;
import { EffectComposer } from ‘three/addons/postprocessing/EffectComposer.js’;
import { RenderPass } from ‘three/addons/postprocessing/RenderPass.js’;
import { UnrealBloomPass } from ‘three/addons/postprocessing/UnrealBloomPass.js’;
import { OutputPass } from ‘three/addons/postprocessing/OutputPass.js’;

//Scene, Camera, Renderer
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(
window.innerWidth / -50,
window.innerWidth / 50,
window.innerHeight / 50,
window.innerHeight / -50,
0.1,
100
);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

//Ambient Light
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);

//Ground
const groundGeometry = new THREE.PlaneGeometry(50, 50);
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0x333333,
metalness: 0.2,
roughness: 0.8
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);

//Cubes
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
for (let i = 0; i < 10; i++) {
const cubeMaterial = new THREE.MeshStandardMaterial({
color: 0x7777ff,
metalness: 0.3,
roughness: 0.6
});
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set((Math.random() - 0.5) * 20, 0.5, (Math.random() - 0.5) * 20);
cube.castShadow = true;
cube.receiveShadow = true;
scene.add(cube);
}

//Point Light
const mainLight = new THREE.PointLight(0xffffff, 5.0, 25, 1.5);
mainLight.castShadow = true;
mainLight.shadow.mapSize.width = 2048;
mainLight.shadow.mapSize.height = 2048;
scene.add(mainLight);

//Helper Sphere for Main Light
const lightSphereGeometry = new THREE.SphereGeometry(0.3, 16, 16);
const lightSphereMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const lightSphere = new THREE.Mesh(lightSphereGeometry, lightSphereMaterial);
scene.add(lightSphere);

//Post-processing
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);

const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.5, //Strength
0.4, //Radius
0.85 //Threshold
);
composer.addPass(bloomPass);

//Output Pass for proper tone mapping and output encoding
const outputPass = new OutputPass();
composer.addPass(outputPass);

//Mouse Control for Light
const mouse = new THREE.Vector2();
const raycaster = new THREE.Raycaster();
window.addEventListener(‘mousemove’, (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(ground);
if (intersects.length > 0) {
    const point = intersects[0].point;
    mainLight.position.set(point.x, 1, point.z);
    lightSphere.position.copy(mainLight.position);
}

});

//Animation Loop
const animate = () => {
requestAnimationFrame(animate);
composer.render();
};

animate();