Multiple Scenes vs Layers

But what do you do when you have more methods such as this? Say the bool changes along with 3 others, you’d traverse the same scene in the same frame. While, if you have to traverse it at least once to figure out the layer stuff, or whats visible and what not, you could pull from this state and do it all in one pass. Still, this traversal from your snippet is cheap, but you can’t do that with a matrix i think, even if you assign it like that internally the setter calls copy(), yielding another loop and increments.

I’m still thinking though, layers may potentially avoid this overhead and achieve the same use case, if say you’re rendering certain meshes in additional passes. With a named set, you could call render(Object3D[], camera) but since it has to be a scene, you can’t just reparent them. If you keep a copy of a mesh and are trying to sync it, it might be easier and even faster to render just one more time with a certain layer.

Can you give some concrete examples of the kind of methods you mean?

You mean you’d have to traverse the scene three times to check for three different things? I’d say that’s just a sign you need to refactor your app.

I don’t really understand what you’re getting at here. If you are rendering a scene two times without changing object transforms, why would you need to copy matrices? The matrices are already set. By the same logic, why would you use two scenes?

Maybe it would help me understand if you provide an example of when you need to do this?

For the selective bloom pass I did test two methods - mesh.visible, and material.colorWrite.
Setting visibility gives a different result since the objects are not written to the depth buffer, with color write they are. Both are nice results, depending on what you want - e.g. if you want the bloomed object to be visible through walls, set visibility.

I think layers would give the same result as mesh.visible. It would be useful to test these and see if there is any performance difference.

1 Like

I’m having a hard time remembering what i was trying to do. It’s possible that i was trying to render completely different meshes, at the same spot. I think i had a high-resolution mesh with no mapping for example, and then a portion of that mesh, with mapping. Imagine you delete a bunch of triangles from a mesh, and you export both as two different GLTF.
I wanted to draw one on top of the other, so use the same matrix4 derived from one position, rotation, scale,

i had to do something like

scene2.traverse(o=>o.matrixWorld.copy(o.userData.master.matrixWorld)

But i just realized that this is more or less completely unrelated :smiley: layers don’t help here, something like this possibly would, but could be an antipattern

o.transform = new THREE.Transform()
o2.transform = o.transform

Now i could organize the render order however i want, by renderOrder or several scenes, and the update is for sure going to be cached. Ie. if its calculated it doesnt need to copy() just skip.

1 Like

I just meant

function setColorWrite( val ) { root.traverse(...) }
function setVisible(val) { root.traverse(...) }
function setFOO( foo ) {...}
function setBAR( bar ) {...}

Will all have to do their own traversal using this pattern.

And then you can do stuff like

setColorWrite(false)
setColorWrite(true)
setColorWrite(false)
render()

Three traversals,. but only the last one’s effect is visible.

I’m not exactly sure what the solution is. I suggested onBeforeUpdate and onAfterUpdate at the same time i pushed for onBeforeRender. But it’s not as straightforward, because i don’t think it’s guaranteed to visit when updating matrices. The idea is, if you’re making an object that can react to these few methods - color, visible, foo, bar:

class MyObject extends Object3D {
  constructor( store ) {
    this.store = store
  }
  onAfterUpdate(){
    this.colorWrite = store.colorWrte //just copy
    if ( this.visible !== store.visible ) this.visible = store.visible //compare to store
    if ( store.dirtyFoo ) this.foo = store.foo //store resets flag after this pass
  }
}

This may be a total anti pattern, but the idea is that three can automatically traverse your scene and update stuff. Actually needs to traverse everything visible to draw stuff, even if doesn’t have to update. So instead of doing N traversals for N of these properties that need to be set, you do just one. Now:

store.setColorWrite(true)
store.setColorWrite(false)
store.setColorWrite(true)
store.setColorWrite(false)
store.setColorWrite(true)
render()

Only does one traversal.

I agree with this, but i think the boundary of “your app” and three in this case is a bit ambiguous. I usually have a layer that wraps around three, but is not really my app, something that i can use in other apps that use three. In this case, what comes to mind is turning off autoUpdate and just making custom update loop. Something that visits all of the nodes even if the matrices are clean. From there, lots of options :smiley:

Can EffectComposer with multiple RenderPasses be used to achieve layering?

I’m not sure what you understand by “layering”, the layer object is a bitmask to determine if a camera has the same flag as the object has in the layer mask and will render it then.

As others mentioned already this concept isn’t really good as it requires traversing the entire scene all time with all the matrix computations, for EffectComposer some examples do it a more proper way by having a separate scene, what is a bit messy to manage though.

I implemented custom render lists for components like deferred lights, those objects are regular part of the main scene hierarchy to be attached to others or have children, but at the culling phase it will be pushed instead to the actual render list to another that will go into a further render call at the light pass.

This only required a single line added to the WebGLRenderer, a callback (onProject) for the Object3D class as i suggested here.

It would be good if THREE would implement layers as custom lists to prevent repeating the entire process.

How would layer lists (sets) work? While traversing the tree only once (in WebGLRenderer), at each node, the system would check which layer set the node is in, and render it to that render target (or whatever it renders to)?

What I was thinking to do, on the outside of Three.js in user code, was to track which objects are in which layer (layers being a construct I would make outside of Three.js). In my render loop, I’d traverse the tree once per layer (for each), and during that traversal I’d set nodes to visible or not visible depending on if the node is in the current layer. So if there’s 9 layers, there there’s 9 traversals unfortunately. But seems like easiest way to manage it outside of three.js in a simpler way than Three.js layers system, and not limited to 32 layers (though still I don’t imagine having more than 32 layers, but having to wrangle bits is not ideal, especially inserting or swapping layer order)

When THREE is about to render the scene it generates a render list of all visible objects in the culling phase, this list determines what is rendered, by pushing it into a separate custom list instead, this list can be used in another pass in which those objects should be visible, without further scene traversal or culling, straight to the render calls.

That way you’re also not limited to any amount of layers, i can determine flag or component wise if an object goes into another pass, in this or maybe both, you would just implement the lists assignment rule yourself.

Anyway without adding such an internal callback layers are easier to manage than manually using a separate scene, especially when you need those objects to be children of some main scene objects.

That sounds great! Hopefully someday it’ll exist.

True. I’m thinking to use only one scene, but modify objects’ visible each time I render with the same scene (as you said, to take advantage of one hierarchy, and we only need visual separation (imagine a UI has a toggle for “always render this thing behind everything else” regardless where in the hierarchy that thing is)).

As far as I know, layers and visible are the only way to tell Three.js (from the outside user code) which things to render or not render, right?

EDIT, see examples in comments further below for a layering system.


Here’s a simple example of two layers using one scene, and two renderers (probably not ideal, probably should use one renderer, multiple render calls):

and here’s my attempt at using two RenderPasses with one renderer:

Seems the last RenderPass draws over the first one (not sure about perf implications either).

Basically yes, layers also won’t stop recursion which was suggested once but i agree with Mugen this shouldn’t stop recursion as the purpose of layers is different from visibility and can conflict if it would stop there.

What you can do from outside too is add a “added” and “removed” callback, and use a separate scene as said, but don’t add it, instead myGlowPassScene.children.push( this );, and disable matrix update on that myGlowPassScene, so you at least got a reduced flat list for that render pass while the object remains integrated in the main scene.

Oh, so visible stops traversal (recursion) of the tree, and the subtree is therefore also not rendered? If so, then that scraps my plans of using visible.

That myGlowPassScene idea is good! It’s like the internal render lists idea in a way. So if I have ultiple “layers” (backed by the extra scenes), maybe I never render the scene that has everything (assuming every object belongs to a layer), and use it only for matrix update, then always render each layer scene (flat list) on its own.

Just gotta think of a good way to manage this (to make it easy for users of my scene lib to use). By “scene lib”, I mean a rendering system built on top of three, and the end users still have only one “scene” but it’s a higher-level scene, and under the hood there’d be multiple Three.js scenes in the “scene lib” implementation.

You could also simply patch the base classes prototypes with a custom add and remove method, taking care of proper push and removal from the flat lists.

I made this simple patcher to make monkey patching easier with THREE, as all classes based on Object3D already inherited the prototype methods.

function Patch( root ) {

	this.root = root;
	this.list = [];

	for ( let name in root )
		this.list.push( root[name] ) ;

}

Patch.prototype = {
	each: function( property, value, prototype ) {

		for ( let i = 0, l = this.list.length; i < l; i ++ ) {

			const object = this.list[ i ];

			if ( object.prototype instanceof Object && object.prototype[property] === value ) {

				Object.assign( object.prototype, prototype );

			}

		}

	}
};

const three = new Patch( THREE );

three.each( 'isObject3D', true, {

	add: function( ... ) {},
	remove: function ( ... ) {}

});

Nice, thanks. I imagine changing the signature of add/remove to some like

const add = Object3D.prototype.add
const remove = Object3D.prototype.add
patcher.each( 'isObject3D', true, {
	add(...objects) {
		if (typeof objects[objects.length - 1] === 'string') {
			// if the last arg is a string, it is a layer name, add the object to a separate scene in the layer-scene map.
			objects.pop()
		} else { ... add to default layer scene ... }
		add.apply(this, objects)
	},
	remove: function ( ... ) { ... similar ... }
});

I suppose certain things like lights may need to be in all layers. Maybe last arg can be a string or string[] or some shortcut like all to add to all layers.

You should store what pass an object gets into on the object, like in userData, on removal it shouldn’t be necessary to explicitly tell again which list or lists it was part of. Also you might try avoiding the usage of apply with array arguments, that can’t be optimized and should be very slow unless it got improved.

I suppose certain things like lights may need to be in all layers

That depends if those further passes will use or need lights. But you might be careful about THREE lights making sure there won’t be some recompiling of materials going on, should work fine though i guess.

Seems nowadays (at least in Chrome) .apply is pretty fast (perf test)

But you might be careful about THREE lights making sure there won’t be some recompiling of materials going on

Yeah, I’m not sure, does sticking lights in multiple scenes cause re-compiling of materials? At the moment my scenes are small enough, to where I just want one light hitting all objects (which will be in different layers)

Alright, first version of a layer system. The demo has some UI to toggle layering on/off and to change layer order:

Updated, with layer visibility toggles and OrbitControls:

Selectively applying a bloom filter to objects in a scene seems like a good use for multiple layers: http://jsfiddle.net/prisoner849/mjfckw02/ (from this thread)

If there’s a way to accomplish this without multiple layers though, I’d like to hear about it!