2 diferent webGPU and postprocess on same page Fail

I’m trying to create 2 different scenes with 2 different webgpus and 2 different postprocess, they give an error when using postprocess.

Without postprocess it works, check this example:

With double and Postprocess: https://didisoftwares.ddns.net/19/index.html
With double and not Postprocess: https://didisoftwares.ddns.net/19/index.html#noGPU
With one and Postprocess: https://didisoftwares.ddns.net/19/index.html#oneGPU

var allProject = [];
var updating = false;

//updates anywhere ( loop all created Project class)
function update() {
	allProject.forEach((project) => {		
		var delta = project.clock.getDelta();		
		if (delta && delta != null && project.renderer) { //if started
			//... other stuffs

			//if prostProcess render created, use it
			if (project.postProcessRender && project.postProcessRender != null) {				
				project.postProcessRender.renderAsync();
			} else {
				//if not created use without postprocess
				project.renderer.renderAsync(project.scene, project.camera);
			}			
		}
	});

	requestAnimationFrame(update);
}

export class Project {
	constructor() {
		//... scene and other global variables

		//external add this to allProject if not updating, start update loop
		allProject.push(this);        
        if(updating==false){
            updating=true;
            update();
        }
	}

	//create postprocess renderer
	createP(renderer) {		
		var outputTexture = this.scenePass.getTextureNode('output');
		var bloomPass = THREE.bloom(outputTexture, 0.2, 0.1, 0);
		var renderOutput = new THREE.PostProcessing(renderer);
		renderOutput.outputNode = bloomPass;
		return renderOutput;
	}

	async init(element, mode) {
		const width = element.innerWidth || element.offsetWidth;
		const height = window.innerHeight || element.offsetHeight;
		this.mainDiv = element;
		this.camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 1000);
		this.scene = new THREE.Scene();
		this.scene.add(this.camera);

		this.renderer = new THREE.WebGPURenderer({ alpha: false, antialias: true });
		this.renderer.setSize(width, height);
		this.renderer.shadowMap.enabled = true;
		this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
		this.renderer.toneMappingExposure = 1;
		this.renderer.toneMapping = THREE.ReinhardToneMapping;
		
		//prepare to use in postprocess creator (createP)
		this.scenePass = THREE.pass(this.scene, this.camera);
		this.scenePass.setMRT(THREE.mrt({
			output: THREE.output,
			emissive: THREE.emissive,
		}));

		//create postProcessRenderer
		//if comment postProcessRender, uses default renderer ( works )
		this.postProcessRender = this.createP(this.renderer, this.scene, this.camera);
	}
}

Do you mind explaining why you need two renderers? Multi-view setups can be achieved with a single renderer.

Do you think you can manage to share an editable live example like a fiddle (see three.js dev template - module - JSFiddle - Code Playground) with a minimal setup?

This is a fiddle sample,

works on default render:

function update() {
    var delta = clock.getDelta();
    
    for (var i = 0; i < allProject.length; i++) {
        var project = allProject[i];
        if (delta && delta != null && project.postProcessRender) {
            project.postProcessRender.renderAsync(project.scene, project.camera);
            //default render
            //project.renderer.renderAsync(project.scene, project.camera);
        }
    }
    requestAnimationFrame(update);
}

I wanted to have different webgpu and postprocess because I want to create scenes with totally different postprocess side by side, or even one with postprocess and another with the default render.

1 Like

I’ve checked the fiddle and there are warnings in the browser console. Do you mind reporting this issue at the three.js GitHub repository? This need a closer investigation.

right, maybe the internal resources used to render post-processing are global, so even creating another THREE.WebGpu when releasing the shaders it releases all webgpus created

@didi_softwares maybe just for fun try pasting the following code in your fiddle.

It is modified and it should show 2 views, one with bloom and one without, but it did not create any console errors for me.

import * as THREE from 'three';
import { pass } from 'three/tsl';
import { bloom } from 'three/addons/tsl/display/BloomNode.js';

var allProject=[];
var updating=false;
const clock = new THREE.Clock();

//External Update
function update() {
    var delta = clock.getDelta();
    
    for ( var i = 0; i < allProject.length; i++ ) {
        var project = allProject[ i ];

        if ( delta && delta != null ) {
          if ( project.postProcessRender ) {
            project.postProcessRender.renderAsync( project.scene, project.camera );
          } else {
            //default render
            project.renderer.renderAsync( project.scene, project.camera );
          }
        }
    }

    requestAnimationFrame(update);
}


//Project Class contains WebGPU data creation
class Project {
	constructor( pp = true ) {		
		this.pp = pp;
		this.scene = null;
		this.renderer = null;
		this.camera = null;
		this.control = null;		
		this.postProcessRender = null; //Hold posprocess render node
		this.mainDiv = null;		

		//put in external global variable and start update
		allProject.push( this );

		if ( updating === false ) {
			updating = true;
			update();
		}
	}

	createPostProcessRender(renderer) {
		var outputTexture = this.scenePass.getTextureNode( 'output' );
		var bloomPass = bloom( outputTexture, 2.5, 0.35 );    
		var renderOutput = new THREE.PostProcessing( renderer );
		renderOutput.outputNode = bloomPass;
		return renderOutput;
	}

	async init( element, mode ) {
		const width = element.innerWidth || element.offsetWidth;
		const height = element.innerHeight || element.offsetHeight;
		this.mainDiv = element;
		this.camera = new THREE.OrthographicCamera( width / -2, width / 2, height / 2, height / -2, 1, 1000 );
		this.scene = new THREE.Scene();
		this.scene.add( this.camera );

		this.renderer = new THREE.WebGPURenderer( { alpha: false, antialias: true } );
		this.renderer.setSize( width, height );
		this.renderer.shadowMap.enabled = true;
		this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
		this.renderer.toneMappingExposure = 1;
		this.renderer.toneMapping = THREE.NeutralToneMapping;
		//this.renderer.autoClear=false;

		//create default scene pass to use late in 'createPostProcessRender'
		this.scenePass = pass( this.scene, this.camera );
		this.scenePass.setMRT( THREE.mrt({
			output: THREE.output,
			emissive: THREE.emissive,
		}));

		if ( this.pp === true ) {
			//create postprocess Renderer	
			this.postProcessRender = this.createPostProcessRender( this.renderer, this.scene, this.camera );        
		}

		this.mainDiv.appendChild(this.renderer.domElement);
		//this.control = new THREE.OrbitControls( this.camera, this.renderer.domElement );

		await this.initSuccess();
		this.mainDiv.addEventListener( 'resize', this.onWindowResize.bind( this ) );
		this.onWindowResize();
	}

	onWindowResize() {
		const width = this.mainDiv.innerWidth || this.mainDiv.offsetWidth;
		const height = this.mainDiv.innerHeight || this.mainDiv.offsetHeight;
		this.renderer.setSize(width, height);

		this.camera.left = width / -2;
		this.camera.right = width / 2;
		this.camera.top = height / 2;
		this.camera.bottom = height / -2;
		this.camera.updateProjectionMatrix();
	}

	async initSuccess() {
		this.camera.position.set( 0, 0, 10 );
		this.createLights();
		await this.createPlane();
	}

	createLights() {
		var light1 = new THREE.AmbientLight( 0xffffff, 1 );
		this.scene.add( light1 );
	}

	async createPlane() {
		const geometry = new THREE.BoxGeometry( 20, 1, 20 );
		const box = new THREE.Mesh( geometry, new THREE.MeshPhongNodeMaterial() );
		box.rotateX( Math.PI / 2 );
		box.receiveShadow = true;
		this.scene.add( box );		
	}
}

//create a project WebGPU1 with bloom
var project1 = new Project( true );
var element1 = document.getElementById( 'div1' );
project1.init( element1 );

//create a project WebGPU2 without bloom
var project2 = new Project( false );
var element2 = document.getElementById( 'div2' );
project2.init( element2 );

yes, precisely if there are not 2 or more postprocesses it does not cause an error