Very low FPS when using composer with 2 viewports and 1 renderer

Hi,

I want to add several viewports of same rendered scene with different cameras and I’ve got FPS degradation from 60 to 0-2 when adding 2 viewports. I’ve realized that FPS drop was caused by composer.render() in render update loop…If comment this line in code FPS back to 60. How to make it right and avoid these freezes (r118) ? And I’m wondering is it ok that I’m using one composer with only one camera in RenderPass…I’ve tried use two composers with different cameras but with same renderer - same effect. All I need are multiple views of same scene but without FPS degradation…
Thanks in advance!

function renderLoop(){
...
	composer.render();	// this line drops FPS to 0

	renderer.setScissorTest( true );

	renderer.setScissor( 0, 0, window.innerWidth, window.innerHeight );
	renderer.setViewport( 0, 0, window.innerWidth, window.innerHeight );
	renderer.render( scene, camera1 );

	renderer.setScissor( 100, 100, 400, 200 );
	renderer.setViewport( 100, 100, 400, 200 );
	renderer.render( scene, camera2 );
...
}

function init(){
...
	renderer = new THREE.WebGLRenderer({antialias: true});
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.physicallyCorrectLights = true;
	renderer.outputEncoding = THREE.sRGBEncoding;
	renderer.shadowMap.enabled = true;
	renderer.shadowMap.type = THREE.PCFSoftShadowMap;
	renderer.toneMapping = THREE.ReinhardToneMapping;
	renderer.toneMappingExposure = Math.pow( params.exposure, 4.0 );
...
	bulbLight = new THREE.SpotLight(0xffee88);
	hemiLight = new THREE.HemisphereLight( 0xddeeff, 0x0f0e0d, 0.6 );
...
	camera1 = new THREE.PerspectiveCamera( 60, aspect, 0.01, 2000 );
	camera1.position.set( 8, 10, 8 );
	camera1.lookAt( 0, 3, 0 );

	camera2 = new THREE.PerspectiveCamera( 60, aspect, 1, 20 );
	camera2.position.set( 0, 3, 0 );
	camera2.lookAt(0,0,0);
...
	scene.add(camera1);
	scene.add(camera2);
...
	composer = new EffectComposer( renderer );
	composer.addPass( new RenderPass( scene, camera1 ) );
	composer.addPass( new SMAAPass( window.innerWidth * renderer.getPixelRatio(), window.innerHeight * renderer.getPixelRatio() ) );
...
}

UPD

Ok, the mistake with FPS is to use composer.render() together with renderer.render() due to renderer.render() called during composer.render()… but if I need render via composer, so what is the optimal solution in this case when sometimes I need show additional camera somewhere on screen? In case of two chained RenderPass with different cameras it shows only last one and clear result of first one…so how to prevent clearing in case of using composer? Is this solution good for perfomance ?

When using EffectComposer, composer.render() replaces the call of renderer.render( scene, camera ). So it’s definitely to do both.

The beauty pass is always done with RenderPass and there is always one per pass chain. If you need to process multiple views, you have to use multiple effect composers like in the following demo:

https://threejs.org/examples/webgl_postprocessing_advanced

Thank you for an explanation! Yes, I’ve found that the only way that works fine is using two independent composers:

function renderLoop(){
...

	renderer.setViewport( 0, 0, window.innerWidth, window.innerHeight );
	composer.render();	

	renderer.setViewport( 100, 100, 400, 200 );
	composer2.render();	
...
}

function init(){
...
	renderer.autoClear = false;
...
	let passFilter = new SMAAPass( window.innerWidth * renderer.getPixelRatio(), window.innerHeight * renderer.getPixelRatio() );
	composer = new EffectComposer( renderer );
	composer.addPass( new RenderPass( scene, camera1 ) );
	composer.addPass( passFilter );

	composer2 = new EffectComposer( renderer );
	composer2.addPass( new RenderPass( scene, camera2 ) );
	composer2.addPass( passFilter );
...
}

Is it necessary to use THREE.WebGLRenderTarget for composers to achieve best performance or above usage is optimal ?

What you have looks good. But keep in mind that EffectComposer always works with render targets. You just have the option to pass in a pre-configured render target if required.

Thanks for advice. Now I’m trying to realize is it possible to make two WebGLRenderTarget with different width & height for one renderer without visual degradation? Continue the subject, I need small second camera view that shows only small part of whole scene… and if I set WebGLRenderTarget width & height for composer of this small viewport to, for example, 400x200(*window.devicePixelRatio)… then I’ve got poor quality picture of the whole scene whose composer’s WebGLRenderTarget has width & height of whole window (i.e. window.innerWidth & window.innerHeight *window.devicePixelRatio). I bealive it is due to both composers have the same renderer…and the second composer change WebGLRenderTarget of this renderer and as result I’ve got super fast but low quality picture :)…But if I set both composers same size (whole window) I get serious FPS degradation (especially on mobile devices)… Is there any way to make two different render buffers of same renderer with different quality/size to avoid performance issue…?

UPD It seems that the only way in this case is new renderer… in this case FPS is similar.