Visibility do not apply to child objects #1524

Closed
zz85 opened this Issue Mar 16, 2012 · 20 comments

Projects

None yet

10 participants

@zz85
Contributor
zz85 commented Mar 16, 2012

while using three inspector i noticed if

parent = new THREE.Object3D();
parent.add(mesh1);
parent.add(mesh2);
parent.visible = false;

mesh1 and mesh 2 are still visible.
is this intended or bug?

@mrdoob
Owner
mrdoob commented Mar 16, 2012

I think this should work on CanvasRenderer and SVGRenderer but not on WebGLRenderer (yet).

@alteredq
Contributor

We have been discussing this and for some reason we decided it was better like this. I already don't remember why.

That's why there is SceneUtils.showHierarchy to provide this functionality:

https://github.com/mrdoob/three.js/blob/master/src/extras/SceneUtils.js#L7

@huanghuan

Just run into this issue recently. I add some sprites to an Object3D for grouping. By changing parent visibility or opacity I expect all children are affected, but apparently they are not. Really keen to know the reason behind :-)

@zz85
Contributor
zz85 commented May 3, 2012

seems like SceneUtils.showHierarchy 04a7ac4 was added after c580473

if for some technical problems it was difficult to do children visibility in webgl, perhaps it might be easier to do a workaround similar to something done in the render loop like updateMatrices()

for each child,
 THREE.SceneUtils.traverseHierarchy( root, function( node ) { node.__visible = child.visible; } )

then inside webglRenderer instead of using .visible, it can retrieve the values of .__visible.

this way, we can keep the compatibility of how the scenegraph visibility is supposed to work?

@gero3
Contributor
gero3 commented May 3, 2012

wouldn't it be better to just add a method which updates all children visible property ??

Object3d.prototype.changeVisibility = function( visible, recursively ) {
     this.visible = visible;
     if(recursively){
         for(var i = 0,il = this.children.length;i<il;i++){
             this.children[i].changeVisibility(visible,recursively);
         }
     }

};
@zz85
Contributor
zz85 commented May 3, 2012

that seems to be what SceneUtils.showHierarchy is doing. This is not ideal because at times, you do not wish to overwrite your children visibility states when toggling the parent's.

example.

var basket = new THREE.Object3D();
var apple = new THREE.Object3D();
var bananas = new THREE.Object3D();
var oranges = new THREE.Object3D();

// hide apple and bananas
apple.visible = false;
oranges.visible = false;
render(); // display oranges


// hide basket
basket.visible = false;
render(); // shows nothing

// show basket = false;
render(); // show oranges
@mrdoob
Owner
mrdoob commented May 3, 2012

That's what basket.material.visible = false solves :)

@zz85
Contributor
zz85 commented May 3, 2012

hmm... i was thinking of this too, but my concerns are

  1. the material is being shared (eg. by 100 baskets) - good idea to create 100 separate materials?
  2. there may not be any basket material (if its basket is an Object3D for grouping)
@mrdoob
Owner
mrdoob commented May 3, 2012
  1. the material is being shared (eg. by 100 baskets) - good idea to create 100 separate materials?

Yeah that should be ok.

  1. there may not be any basket material (if its basket is an Object3D for grouping)

Then that object won't be visible so no need to make it invisible, no?

@mrdoob
Owner
mrdoob commented May 3, 2012

So here's the explanation of the current situation...

I think the behaviour should be that if you set visible to false to an object, the object and all its children should go invisible. That's how it works in CanvasRenderer, SVGRenderer and all the renderers that get the list of objects to render out of Projector.

The reason WebGLRenderer doesn't work like this is because it handles way more objects and there is the concern that updating an array with the objects that need to be rendered every frame may decrease the performance considerably.

Basically, what Projector does every frame is parsing all the scene graph, and adding to an array all the visible objects that are in the frustum. This array gets cleaned every frame with objects.length = 0, which seemed to be the most performant approach back when I tested it. The benefits of this is that the ideal behaviour gets done for free and the code is also pretty clean.

On the other hand, WebGLRenderer does it's own scene graph parsing and for the invisible objects or objects outside the frustrum it sets some internal booleans (or just continue the loop) and also has some internal arrays in the Scene that only get updated when a new element gets added or removed...

__lights
__objects
__objectsAdded
__objectsRemoved
__webglFlares
__webglObjects
__webglObjectsImmediate
__webglSprites

So, I'm supposed to do some more performance tests some day, to see whether nowadays browsers still have a performance hit with updating arrays every frame or not and try see if WebGLRenderer could use Projector for the scene parsing instead.

If anyway wants to give it a go... :)

@idflood
idflood commented May 11, 2012

The showHierarchy method of THREE.SceneUtils works great but I expected this to be the default behavior.

@mrdoob mrdoob closed this Sep 25, 2012
@nhalloran
Contributor

FYI: I just upgraded to r52, but this appears to still be at large. I'm using traverseHierarchy, which is unexpected but fine, but it wipes the visibility state of children.

@nhalloran
Contributor

I see. This was closed at the time SceneUtils.traverseHierarchy was moved to object.traverse (a change I like btw). I figured the visibility issue was fixed at that time.

@mrdoob
Owner
mrdoob commented Oct 17, 2012

Yeah. We still need to find a good solution for this. But object.traverse should do the trick until then.

This was referenced Jan 17, 2013
@Wandalen
Contributor

Yeah. We still need to find a good solution for this.

I can commit a good one.

@mrdoob
Owner
mrdoob commented May 18, 2014

uh?

@felixturner
Contributor

In case it's not clear from the above: Setting visible on a parent now affects children also. (tested with r71)

@zz85
Contributor
zz85 commented Jun 10, 2015

yeh!

@jesseazueta

Hi everyone, not sure if this has already been clarified, but Im trying to set up an enclosed room with some soft lighting. I wanted to use area lights to achieve this but the light source is visible. Is there a way to keep the light emitting but hide the visibility of the light source itself? Any help would be greatly appreciated!

@mrdoob
Owner
mrdoob commented Feb 1, 2017

@jesseazueta please, don't post in old conversations with unrelated questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment