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.
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