Using Bloom Post-Processing in ThreeJS without NPM in Pure JavaScript

I'm in search of a bloom effect for my scene while using an emissive map, similar to what's showcased in this ThreeJS Example.

Attempting to decipher the code has left me feeling stuck. The examples rely on NPM, which isn't part of my project workflow. I believe it's possible to achieve the bloom effect without NPM, but I'm struggling to piece it all together.

My current setup involves just the basics with StandardMeshMaterial:

scene = new THREE.Scene();
loader = new THREE.TextureLoader()
camera = new THREE.PerspectiveCamera( 47, (window.innerWidth/window.innerHeight) / (windowHeight*heightRatio), 0.01, 10000 );
renderer = new THREE.WebGLRenderer( { canvas: document.getElementById( canvasElement ), antialias: true, alpha: true } );
controls = new THREE.OrbitControls( camera, renderer.domElement );

etc..

function animate() {
    requestAnimationFrame( animate );           
    controls.update();              
    renderer.render( scene, camera );           
};  
        
etc..

I'm eager to incorporate a post-processing effect that truly makes my emissive materials glow, as they currently don't appear as such. Any advice on the simplest way to achieve this outcome?

Answer №1

NPM was not used to create the examples.

Check out the example below. The only modifications made were to the paths of the modules and the model URL.

#info > * {
  max-width: 650px;
  margin-left: auto;
  margin-right: auto;
}
<link type="text/css" rel="stylesheet" href="https://threejs.org/examples/main.css">
<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="module">
  import * as THREE from 'https://threejs.org/build/three.module.js';

  import Stats from 'https://threejs.org/examples/jsm/libs/stats.module.js';
  import { GUI } from 'https://threejs.org/examples/jsm/libs/dat.gui.module.js';

  import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
  import { GLTFLoader } from 'https://threejs.org/examples/jsm/loaders/GLTFLoader.js';
  import { EffectComposer } from 'https://threejs.org/examples/jsm/postprocessing/EffectComposer.js';
  import { RenderPass } from 'https://threejs.org/examples/jsm/postprocessing/RenderPass.js';
  import { UnrealBloomPass } from 'https://threejs.org/examples/jsm/postprocessing/UnrealBloomPass.js';

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

  const params = {
    exposure: 1,
    bloomStrength: 1.5,
    bloomThreshold: 0,
    bloomRadius: 0
  };

  init();

  function init() {

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

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

    clock = new THREE.Clock();

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

    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 );

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

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

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

    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.bloomThreshold;
    bloomPass.strength = params.bloomStrength;
    bloomPass.radius = params.bloomRadius;

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

    new GLTFLoader().load( 'https://threejs.org/examples/models/gltf/PrimaryIonDrive.glb', function ( gltf ) {

      const model = gltf.scene;

      scene.add( model );

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

      animate();

    } );

    const gui = new GUI();

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

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

    } );

    gui.add( params, 'bloomThreshold', 0.0, 1.0 ).onChange( function ( value ) {

      bloomPass.threshold = Number( value );

    } );

    gui.add( params, 'bloomStrength', 0.0, 3.0 ).onChange( function ( value ) {

      bloomPass.strength = Number( value );

    } );

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

      bloomPass.radius = Number( value );

    } );

    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() {

    requestAnimationFrame( animate );

    const delta = clock.getDelta();

    mixer.update( delta );

    stats.update();

    composer.render();

  }

</script>

To enable

<script type="module">
for modern import statements, follow these steps:

Create the directory structure as shown below and adjust your paths accordingly:

someFolder
 |
 ├-build
 | |
 | +-three.module.js
 |
 +-examples
   |
   +-jsm
     |
     +-controls
     | |
     | +-OrbitControls.js
     | +-TrackballControls.js
     | +-...
     |
     +-loaders
     | |
     | +-GLTFLoader.js
     | +-...
     |
     ...

Refer to this article for more details.

Answer №2

In contrast to a framework, NPM serves as a package manager designed to simplify the process of incorporating external libraries into your project. It eliminates the need for manual downloading and copying of scripts by providing a convenient way to manage dependencies. It seems you may not be well-versed in utilizing this modular approach. Are you looking to include scripts related to three.js and have them accessible through the global namespace THREE?

If you have downloaded the three.js library to a folder named three, you can import the necessary scripts by following these steps. Make sure to fetch the scripts from the directory examples/js rather than examples/jsm.

<script src="three/build/three.min.js"></script>
<script src="three/examples/js/controls/OrbitControls.js"></script>
<script src="three/examples/js/loaders/GLTFLoader.js"></script>
<script src="three/examples/js/postprocessing/EffectComposer.js"></script>
<script src="three/examples/js/postprocessing/RenderPass.js"></script>
<script src="three/examples/js/postprocessing/UnrealBloomPass.js"></script>

You can now utilize these classes within the THREE namespace.

const renderScene = new THREE.RenderPass( scene, camera );

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

Refer to the sample code, exclude the import statements, and insert THREE where needed.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leveraging the combination of <Form>, jQuery, Sequelize, and SQL for authentication and navigation tasks

My objective is to extract the values from the IDs #username-l and #pwd-l in an HTML form upon the user clicking the submit button. I aim to compare these values with those stored in a SQL database, and if they match exactly, redirect the user to a specifi ...

Is it possible to search a JSON Array using a variable as the criteria

I have a JSON Array that needs to be searched: [ { "Device_ID":"1", "Image":"HTC-One-X.png", "Manufacturer":"HTC", "Model":"One X", "Region":"GSM", "Type":"Phone" }, { "Device_ID":"2", "Image":"Motorol ...

Changing the Style of a CSS Module Using JavaScript

Embarking on a journey into Javascript and React, I am currently working on my first React app. My aim is to adjust the number of "gridTemplateRows" displayed on the screen using a variable that will be updated based on data. Right now, it's hardcode ...

"Encountering problem with sending data to server through Ajax

I am facing a very complex issue that requires an in-depth understanding. If this interests you, please continue reading. I have developed a program from scratch that generates an HTML page for user data input and submission. The submitted data is sent to ...

Guide to integrating custom fields in Wordpress with mapbox-gl js to generate map markers

Currently, I am in the process of generating a map that will display various points using Mapbox and WordPress. To achieve this, I have set up a custom post type within WordPress where the coordinates are stored in custom meta fields. Although the fields h ...

Dealing with JS and Spring issues

I created a simple script that retrieves longitude and latitude values and populates an input form. Here is the HTML: <p id="demo">Click the button to get your coordinates:</p> <button onclick="getLocation()">Try It</button> <sc ...

Is there a way to transfer an image from background.js to background.html?

I'm in the process of creating a chrome extension that involves making an API call every hour to retrieve an image, which I then want to save in chrome.storage.local. However, the size of the image is quite large, so I'm resizing it using a canv ...

Unable to start initial Cucumber+javascript demonstration

I attempted to run the initial example provided in the official documentation found here. Using Windows 7x64 bit and node.js version 6.11 I ran the following commands but encountered the same outcome. * node_modules/cucumber/bin/cucumber.js autotests/c ...

Struggling to capture a "moment in time" of a form without losing any of the data

My form is highly dynamic, with interacting top-level elements triggering a complete transformation of the lower-level elements. I needed a method to maintain state so that if users partially entered data in one category, switched temporarily to another, a ...

One set of objects is active in retrieving data, while the other remains inactive

I'm working with an array of objects and here is what it looks like: const default_apps = [ { 'post_title': 'Excel', }, { 'post_title': 'Word', }, { 'post_title': 'SharePoi ...

Extracting the content within HTML tags using regular expressions

There is a specific string structure that needs to be processed: <div class="myClass"> Some Text. </div> <div class="otherClass"> Some Text. </div> The task at hand involves parsing the div with myClass and replacing certa ...

Having difficulty retrieving cookie from fetch() response

Many times, the issue of fetching cookies from a SO response has been raised on sites like: fetch: Getting cookies from fetch response or Unable to set cookie in browser using request and express modules in NodeJS However, none of the solutions provide ...

The Javascript/Jquery code executes just once on the initial event, doubles on the subsequent event, and continues to increase in

There is a JS function attached to an HTML button's onclick attribute: function AddFbLikes() { $('#fbform').on('submit', function(e) { e.preventDefault(); // stop form submission $("input:checkbox:checked").each(function(i ...

Tips for sending JSON data from JavaScript to PHP servers

After encoding an array into JSON using JavaScript, I set up my ajaxrequest object like this: var data = JSON.stringify(cVal); function ajaxRequest(url, method, data, asynch, responseHandler){ var request = new XMLHttpRequest(); request.open(meth ...

jQuery AJAX chained together using promises

In my current project, I am facing an issue where I have 4 get requests being fired simultaneously. Due to using fade effects and the asynchronous nature of these requests, there are times when empty data is received intermittently. To address this issue, ...

Animate a div to sense whether it has reached the top or bottom position

Is it possible for a div to animate when it reaches almost halfway while scrolling? I'm looking to achieve this effect on a sticky sidebar, similar to how it works on this website: sample This is the code I have: $(function(){ // document ready ...

A guide to implementing the map function on Objects in Stencil

Passing data to a stencil component in index.html <app-root data="{<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b5d4d7d6f5d2d8d4dcd99bd6dad8">[email protected]</a>, <a href="/cdn-cgi/l/email-pro ...

The process of obtaining the downloadedURL for a resized image from Firebase Storage

Context Currently, I am uploading an image to Firebase after selecting it using a file input. The process involves using the default settings on the Firebase resize image extension, which resizes the images to 200x200 with no specified file path or folder ...

Unable to extract properties from event.body

I'm encountering an issue where I am unable to destructure from event.body. exports.handler = async (event, context) => { const { items } = event.body; const allItems = await getProducts(); return { statusCode: 200, bod ...

Issue with AngularJs failing to display data

As a newcomer to AngularJS, I am looking to utilize AngularJs to display the Json output from my MVC controller. Here is the code snippet for my MVC Controller that generates Json: [HttpGet] public JsonResult GetAllData() { ...