Switch effortlessly between various THREE.EffectComposer scenes with a single renderer in three.js

Currently, I'm experimenting with creating intricate scenes using Composer in three.js. I'm curious to know if it's achievable to switch between two scenes with distinct composer effects applied to them. To better understand this concept, I've set up an example that demonstrates toggling between two normally rendered scenes.

Check out the two scene example

Based on my understanding of how composer functions, you first create an instance of it and then add a render pass like this:

    this.composer = new THREE.EffectComposer(this.renderer.default.init);
    this.renderPass = new THREE.RenderPass(this.stage,  this.camera);
    this.renderPass.renderToScreen = true;
    this.composer.addPass(this.renderPass); 

After that, you can render using composer like this:

    this.composer.render();

Therefore, the question arises - if I have a second scene with a composer instance, how can I:

  1. Utilize the same renderer (if feasible)
  2. Switch between scene 1 and scene 2 similar to the example I've provided

Answer №1

To transition from one effectComposer to another, simply follow the same process as switching between scenes. This can be achieved with the code snippet below:

const environments = [
  new THREE.Scene(), 
  new THREE.Scene()
];

const composers = environments.map(function(environment) {
  const composer = new THREE.EffectComposer(renderer);

  // set up render passes
  const renderpass = new THREE.RenderPass(environment, camera);
  renderpass.renderToScreen = true;
  composer.addPass(renderpass);

  environment.composer = composer;
  return composer;
});

// utilize the composer for the environment
let activeEnvironment = environments[0];
activeEnvironment.composer.render();

If desired, you can also recycle specific render passes for efficiency.

Answer №2

https://i.sstatic.net/RhsdW.gif

Before I delve into this topic, I want to give credit to Martin Schuhfuß for his valuable insights that led to this solution.

Disclaimer

As a non-expert in JavaScript programming, I want to clarify that my approach is not the only way to tackle this issue. My explanation is meant to be interpreted in a broad sense, as the implementation may vary based on individual architecture.

Architecture

In this example, I am employing an Object-Oriented Programming (OOP) method, but feel free to adapt the solution to suit your preferred method.

Method

Building upon Martin's example, we noticed the capability of adding the composer property/object to our scene object, allowing scenes to inherit similar composer effects. However, in my scenario with multiple scenes featuring different composer effects, I needed to rethink the approach.

1. Creating a Composer object.

I established an object to contain composer objects, maintaining the 'composer' naming convention for referencing my effects.

This.composer = {};

2. Developing a function to initialize RenderPasses for the respective scenes.

Prior to utilizing the composer, it is essential to define and initialize the RenderPasses. RenderPasses enable us to apply desired effects (known as shaders). In my case with two scenes, I had to create:

  1. Two RenderPasses.
  2. One RenderPass duplicating the scene.
  3. Another RenderPass implementing a sepia effect to its scene.

Sample Code:

this.init = function() {

stackoverflow.webgl.pass.base = new THREE.RenderPass(stackoverflow.webgl.scene.default, 
stackoverflow.webgl.camera);

stackoverflow.webgl.pass.base2 = new THREE.RenderPass(stackoverflow.webgl.scene.test, 
stackoverflow.webgl.camera);

stackoverflow.webgl.pass.sepia = new 
THREE.ShaderPass(THREE.SepiaShader);
stackoverflow.webgl.pass.sepia.renderToScreen = true;

stackoverflow.webgl.pass.copy = new THREE.ShaderPass(THREE.CopyShader);
stackoverflow.webgl.pass.copy.renderToScreen = true;

} 

Note: File names had to be altered for legal reasons, but the functionality remains intact as part of a larger object.

3. Creating a start function and assigning composers to scenes.

This function serves as a demonstration of unifying all components. The code snippet showcases:

// Creating an object as a reference for EffectComposer objects
    this.composer = {};

// Designating the desired scene
    this.activeScene = this.scene.default;

// Wrapper function for initialization
    this.start = function () {

// Initializing RenderPasses
    stackoverflow.webgl.pass.init();

// Setting up the WebGLRenderer scene (as per personal method)
    stackoverflow.webgl.renderer.default.setup;

// Creating composers for scenes
    this.composer.ui = new THREE.EffectComposer(stackoverflow.webgl.renderer.default.init);

    this.composer.ui2 = new THREE.EffectComposer(stackoverflow.webgl.renderer.default.init);

// Assigning composers to scenes
    this.scene.default.composer = stackoverflow.webgl.composer.ui;
    this.scene.test.composer = stackoverflow.webgl.composer.ui2;

// Validating the setup
    console.log(this.scene.default);
    console.log(this.scene.test);
    console.log(this.composer);

// Adding passes (function 'render') - customize based on code structure
    stackoverflow.webgl.render();

    }

4. Integrating pass declarations into the architecture.

Following the setup, adding pass declarations is necessary for the effects to manifest.

this.render = function () {    
stackoverflow.webgl.composer.ui.addPass(stackoverflow.webgl.pass.base);        
stackoverflow.webgl.composer.ui.addPass(stackoverflow.webgl.pass.copy);      
stackoverflow.webgl.composer.ui2.addPass(stackoverflow.webgl.pass.base2);
stackoverflow.webgl.composer.ui2.addPass(stackoverflow.webgl.pass.sepia);
};

5. Implementing the EffectComposer render method.

This line of code must be inserted where composer processing occurs, tailored to the setup.

stackoverflow.webgl.activeScene.composer.render();

Ensure the 'activeScene' part references the current scene for seamless scene transitions.

6. Creating a button to toggle between scenes.

Using dat.gui, I added two buttons for toggling between scenes.

Customize buttons or functions as per your preference.

// Update 'activeScene' value accordingly

// Button 1 switches to scene 2
stackoverflow.webgl.activeScene = stackoverflow.webgl.scene.test;

// Button 2 reverts to scene 1
stackoverflow.webgl.activeScene = stackoverflow.webgl.scene.default;

Conclusion

This methodology represents my approach to achieving the desired effect. Feel free to contribute alternative or improved methods to enrich the discussion.

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

Using SVG files as properties in React from a data.js file

I have a website where I store my content in a data.js file and pass it to my components using props. Everything is working correctly, except for my .svg files. When I try to display them, they do not appear. However, if I change the extension of the image ...

Winning opportunities created by using credits in the slot machine

**Greetings, I have created a slot machine using JavaScript, but I am looking to enhance the player's chances based on their credits. Can anyone guide me on how to achieve this? Essentially, I want the player's odds to increase proportionally wit ...

How can I programmatically refresh a recursive ng-include in AngularJS?

Using a recursive script within my Angular application, I am displaying a visualization of multiple objects. However, whenever I modify the structure of an object dynamically, the view does not automatically update. It appears that the ng-include directiv ...

Having trouble retrieving multiple selected values from the paper listbox in Polymer 3

I'm attempting to retrieve multiple selected values in a paper-listbox element in Polymer. <paper-dropdown-menu label="{{_getLabel('Activity Type')}}" id="fromMenu" on-paper-dropdown-close="fromAccountChanged" searchable="true"> ...

Challenges with handling multiple concurrent AJAX requests in jQuery

The challenge here is that the application needs to make multiple requests to a web service using $.ajax, but the number of times these requests need to be made depends on the user. Due to this dynamic nature, it appears that using $.when might not be suit ...

The process of integrating a Loader in Javascript

I am in need of a simple "page loading" animation while my photo is being uploaded. Unfortunately, when I tried using the "blockUI" JavaScript for this purpose, it didn't seem to work with my form. For uploading the image, I have employed a div as a ...

Am I making a mistake in my implementation of sending Socket.io messages to a designated room?

Upon a user joining, I alter their ID to a shortened random code. This change is made to utilize the id as a visible session ID on the front-end. I mention this to prevent confusion regarding non-standard socket IDs and their relation to potential issues. ...

How can an ESM-only package be included using the require method?

My current situation involves a node dependency that was previously included in version 2 using require. However, with the release of version 3, the library can now only be included with import. I encountered the following error: [ERR_REQUIRE_ESM]: requi ...

Instead of leaving an Enum value as undefined, using a NONE value provides a more explicit

I've noticed this pattern in code a few times and it's got me thinking. When you check for undefined in a typescript enum, it can lead to unexpected behavior like the example below. enum DoSomething { VALUE1, VALUE2, VALUE3, } f ...

JavaScript not displaying properly in Django application deployed on Heroku

Recently deployed a Django application on Heroku, and encountered an issue where the Javascript file hosted on Amazon S3 is not rendering on any page except for the home page. However, upon checking the Console in Inspect Element, it appears that everythin ...

Is it possible to create a unit test for a JavaScript function that manipulates an HTML element?

I'm struggling with testing a function that includes a modal displayer like this: function modaldisplayer(){ $('.mymodal').modal('show'); return 'success'; } In my code, there is another function called 'foo&a ...

How can I convert base64 data to a specific file type using React Cropper JS?

I have successfully implemented the crop functionality using react cropper js. Now, I am faced with a challenge of sending the cropped image as a file type. Currently, I can obtain the base64 string for the cropped image. However, when I submit the cropped ...

utilizing window.location.href to direct to a page with javascript capabilities

I am currently developing my own personal website. It is designed to be very light in terms of loading and content. This website relies heavily on the use of jquery, so if a user's browser does not have JavaScript enabled, the site will not function ...

The switch/case function I implemented is functioning correctly, however, an error is being displayed in the console stating "Cannot read property 'name' of null"

Check out the live codepen demo here After selecting "elephant" from the third dropdown, the console.log(brand.name) displays "elephant" as expected and executes the rest of the switch statement successfully. However, there seems to be a console error oc ...

Designing Checkboxes and Radio Buttons

I am seeking a way to customize the appearance of checked and unchecked checkboxes using images without modifying the HTML structure. I would prefer not to add labels, classes, or IDs to the elements. The provided example only works in Webkit browsers, s ...

HTML experiences confusion as JSON tosses undefined data

Can someone assist me with API integration? I am new to this and trying to display the Poster, Title, and Year from an API URL. Here is the code I have been working on. When I log in, it shows JSON in an array but throws "undefined" in front-end. Your help ...

Ways to extract a number that comes after a specific word in a URL

I have a URL and need to extract a specific value from it by removing a certain step. I am looking for a regex solution to accomplish this task For example, if I have the window.location.href, the URL might look like this: https://mypage/route/step-1/mor ...

Is there a way for me to use an ajax xmlhttprequest to submit all the selected values from my radio buttons?

Here's the situation: I have four input forms [A-D] and I have selected options A and B. I want to transfer this information to another page, but I'm not sure how to do it. I've tried searching for tutorials on AJAX, but most of them focus ...

Tips for displaying res.locals information in the console for debugging purposes using ExpressJS and Nodejs

Currently, I am delving into the world of Node.js and ExpressJS as a novice in this realm. My primary requirement is to log the entire or partial content of res.locals in my console for debugging purposes. Here's what I've attempted: var foo_ro ...

Angular JS is encountering an issue where the promise object is failing to render correctly

I'm currently learning Angular and I have a question about fetching custom errors from a promise object in Angular JS. I can't seem to display the custom error message on my HTML page. What am I missing? Below is my HTML file - <!DOCTYPE htm ...