Issues migrating from UnrealBloomPass to BloomEffect

I’m currently using the UnrealBloomPass from the jsm and would like to instead use the BloomEffect from the postprocessing library.

Here’s my current code:

<script type="x-shader/x-vertex" id="vertexshader">
  varying vec2 vUv;

    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
  </script>
<script type="x-shader/x-fragment" id="fragmentshader">
  uniform sampler2D baseTexture;
    uniform sampler2D bloomTexture;
    varying vec2 vUv;

    void main() {
      gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );
    }
  </script>
<script type="module">
  import * as THREE from 'https://unpkg.com/three/build/three.module.js';
  import {
    OrbitControls
  } from 'https://unpkg.com/three/examples/jsm/controls/OrbitControls.js';
  import {
    EffectComposer
  } from 'https://unpkg.com/three/examples/jsm/postprocessing/EffectComposer.js';
  import {
    RenderPass
  } from 'https://unpkg.com/three/examples/jsm/postprocessing/RenderPass.js';
  import {
    ShaderPass
  } from 'https://unpkg.com/three/examples/jsm/postprocessing/ShaderPass.js';
  import {
    UnrealBloomPass
  } from 'https://unpkg.com/three/examples/jsm/postprocessing/UnrealBloomPass.js';
  const DISTANCE_SCALE = 23.49;
  const EARTH_RADIUS = 6371;
  const STAR_RADIUS = 696340;
  const STAR_OFFSET = STAR_RADIUS / EARTH_RADIUS;
  const SUNLIGHT_INTENSITY = Math.floor(3.846 * 1026 / DISTANCE_SCALE);

  function setupScene() {
    function Sphere(radius, dist, colour, star) {
      const obj = new THREE.Group();
      obj.position.set(0, 0, dist * DISTANCE_SCALE);
      const sphereMat = new THREE.MeshPhongMaterial({});
      if (star) {
        sphereMat.color = new THREE.Color(colour);
      } else {
        obj.position.z += STAR_OFFSET;
      }
      obj.add(new THREE.Mesh(new THREE.SphereGeometry(radius / EARTH_RADIUS, 32, 32), sphereMat));
      const objScene = star ? starScene : scene;
      objScene.add(obj);
    }
    Sphere(STAR_RADIUS, 0, "#ff5e00", true);
    Sphere(EARTH_RADIUS, 1, "#0000FF", false);
  }

  function setupLighting() {
    starScene.add(new THREE.AmbientLight(0x111111, 1));
    const sunLight = new THREE.PointLight(0xFFFFFF, SUNLIGHT_INTENSITY);
    scene.add(sunLight);
    const renderScene = new RenderPass(starScene, camera);
    const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
    bloomPass.threshold = 0;
    bloomPass.strength = 10;
    bloomPass.radius = .55;
    bloomComposer = new EffectComposer(renderer);
    bloomComposer.addPass(renderScene);
    bloomComposer.addPass(bloomPass);
    const finalPass = new ShaderPass(
      new THREE.ShaderMaterial({
        uniforms: {
          baseTexture: {
            value: null
          },
          bloomTexture: {
            value: bloomComposer.renderTarget2.texture
          }
        },
        vertexShader: document.getElementById('vertexshader').textContent,
        fragmentShader: document.getElementById('fragmentshader').textContent,
        defines: {}
      }), "baseTexture"
    );
    finalPass.needsSwap = true;
    finalComposer = new EffectComposer(renderer);
    finalComposer.addPass(renderScene);
    finalComposer.addPass(finalPass);
  }

  function render() {
    renderer.autoClear = true;
    renderer.render(scene, camera);
    renderer.autoClear = false;
    finalComposer.render();
    bloomComposer.render();
  }
  const renderer = new THREE.WebGLRenderer({});
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.toneMappingExposure = Math.pow(.9, 4.0);
  renderer.autoClear = false;
  document.body.appendChild(renderer.domElement);
  renderer.setSize(window.innerWidth, window.innerHeight);
  const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.05, 20000);
  camera.position.set(0, 720, 720);
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 0, DISTANCE_SCALE + STAR_OFFSET);
  const scene = new THREE.Scene();
  const starScene = new THREE.Scene();
  setupScene();
  let bloomComposer;
  let finalComposer;
  setupLighting();
  renderer.setAnimationLoop(render);
</script>

My progress so far (following the example):

    const bloomEffect = new BloomEffect({
        intensity: 10,
        luminanceThreshold: 0,
        luminanceSmoothing: 0.1,
        kernelSize: KernelSize.MEDIUM
    });
    const bloomPass = new EffectPass(camera, bloomEffect);
    bloomPass.renderToScreen = true;

    const bloomComposer = new EffectComposer(this.renderer);
    bloomComposer.autoRenderToScreen = true;
    bloomComposer.addPass(renderScene);
    bloomComposer.addPass(bloomPass);

Also, the bloomTexture attribute on line 77 is now:

bloomTexture: {value: bloomComposer.inputBuffer.texture}

But I’m not getting the same result, clearly because they work differently.

Additionally, I have to render the composers after I render the scene that has no bloom effect on it and this means the objects in that scene are not shown.

Any guidance is greatly appreciated.

Just a thought, but I’m currently implementing the selective BloomPass and it “toggles off” objects by setting their materials to black at the front of render loop and then restoring the material at the end, so it doesn’t pick up any bloom. You might need to do something like that

1 Like

Hi @okonno, I see the selective bloom example in that repo (as well as the one in the three.js repo) but I thought I could get around it by just placing the objects into another scene.

I’ll look into that but right now my main issue is the effect is not the same - I realised I should’ve included the result of using the UnrealBloomPass:

Not sure how to achieve the above effect using BloomEffect.