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);
}
}
Mugen87
November 6, 2024, 11:12am
2
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.
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