Share MeshStandardMaterial with environment Map accross multiple Scenes?

Hi!

We’re trying to apply a MeshStandardMaterial (working in the main scene) accross multiple additional scenes, but when we assign the material to objects in another scene, they’re been rendered black and we don’t know why. Console ist ok, the material is assigned correctly (same uuid + x).

Is this approach generally ok / possible?

Thanks! :grin:

What do you mean by scene? THREE.Scene or a different WebGLRenderer?

THREE.Scenes with each own WebGLRenderer.
Scenes are beeing rendered to different canvases.

You can’t share them, the first renderer rendering will allocate resources (the program) for it’s own context, though, you could use just one renderer and just canvases for the other and render the renderer.domElement on them.

1 Like

Ok, thanks, we will try something like that out!

Hi,

still no success, but it could be that we misunderstood your proposal

you could use just one renderer and just canvases for the other and render the renderer.domElement on them.

May be I should explain more what we are trying to achieve:

We have 2 scenes.
Scene 1 contains complex, partially (sometimes) animated geometry.
Scene 2 contains multiple objects with very simple animated (sometimes) geometry
Both scenes should share the same environment for reflections etc.

We want to layer the two scenes:
Scene 1 (opaque) as background.
Scene 2 (transparent) as overlay

Why? :point_right: Performance: in case the geometry in Scene 1 (complex) is not being animated we don’t wan’t to re-render it (expensive) while Geometry in Scene 2 (simple) is being animated (cheap).

Our first try was to create two separate renderers for each scene, render to two different canvases while using the material already created for the first scene including the environment map etc., but this doesn’t function.

We could create two separate renderers, create the environment the same way two times and render to two different canvases (opaque and transparent), but some other solutions reusing the material and already created environment-map would be more elegant of course (if possible, but it seems it’s not).

We’ve searched for some kind of “layered” rendering option, but this doesn’t seem to be possible?

We’re currently considering rendering Scene 1 to a texture as canvas-background or something similar… :thinking:

Could you show me a screencap to understand your situation? If you have objects you want to hide when not used you could just set their visible property to false.

1 Like

Hi @Fyrestar!

An update on progress:
We got awesome performance increase (we are developing “mobile first”) by rendering Scene 1 containing complex model / animation into a renderTarget.texture and applying it to a plane placed inside Scene 2 as background.

This tutorial was very usefull: Three.js Render Targets

All we have to do now is properly fit the plane to the camera / device-screen, I hope this will nail it (thanks again for finding it):

… and tweak the background-plane texture / material as it looks a bit dull (low color / contrast) at the moment.

We will post the result and a short solution description as soon as we are 100% sure this approach meets our needs.

One more thing:
As we’re now using only one renderer, we can also use the same reflection-material / environment map in both scenes.

:fist:

1 Like

Good luck :smile:

I still don’t know your exact case, but by how you describe with overlaying the second scene you could save the render target by drawing it over the existing like this, maybe it helps:

renderer.autoClear = false;
renderer.clear();
renderer.render(scene1, camera);
renderer.render(scene2, camera);

… we tried that, but what we need is optional (expensive) rendering / re-rendering of the complex scene 1 & we still want a visible static rendering of it in the background if it’s not being animated.

This way…

renderer.autoClear = false;
renderer.clear();
renderer.render(scene1, camera);
renderer.render(scene2, camera);

scene 1 would not be rendered at all if optioned out.

I see you want to pause the other scene, that makes sense of course, but you could still use it and render the RenderTarget in a post processing manner, something like this:

const backgroundCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
const backgroundScene = new THREE.Scene;
const plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2, 1, 1), new THREE.MeshBasicMaterial({
    map: renderTarget.texture,
    depthWrite: false
}));
backgroundScene.add(plane);

renderer.setRenderTarget(renderTarget);
renderer.render(scene1, camera);
renderer.setRenderTarget(null);

renderer.autoClear = false;
renderer.clear();
renderer.render(backgroundScene, backgroundCamera);
renderer.render(scene2, camera);

edit: setting depthWrite to false is better of course

1 Like

thanks! looks like worth trying out / comparing.
At the moment we have something like this (pretty similar):

simplified (:point_up: do not copy/paste! :wink:) :

backgroundPlane.material.map = renderTarget.texture;
scene2.add(backgroundPlane);

if( renderScene1 ) {
    renderer.setRenderTarget( renderTarget );
    renderer.render(scene1, camera1);
    renderer.setRenderTarget (null);
}

renderer.render( scene2, camera2 );
1 Like

Yes it is basically the same but by rendering it as fullscreen quad you don’t need to artifically place the backgroundPlane in the second scene to cover the screen, but it should work too.

1 Like

yes, your approach might be better, no distortion, might be easier to make responsive too, must try it + will give feedback. thanks. :slight_smile:

1 Like

Hi! A quick feedback on your method, works great :+1:, we only had to change it slightly:

  1. PlaneBufferGeometry to PlaneGeometry (Plane was not visible with PlaneBufferGeometry :point_right:?)
  2. Set renderer.autoClear to “true” before rendering to renderTarget in order to display the animation frames correctly (otherwise frames were drawn into the texture overlapping each other).
const backgroundCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
const backgroundScene = new THREE.Scene;
const plane = new THREE.Mesh(new THREE.PlaneGeometry(2, 2, 1, 1), new THREE.MeshBasicMaterial({
    map: renderTarget.texture,
    depthWrite: false
}));
backgroundScene.add(plane);

renderer.autoClear = true;
renderer.setRenderTarget(renderTarget);
renderer.render(scene1, camera);
renderer.setRenderTarget(null);

renderer.autoClear = false;
renderer.clear();
renderer.render(backgroundScene, backgroundCamera);
renderer.render(scene2, camera);

thanks! :+1::sunglasses:

1 Like