-
-
Notifications
You must be signed in to change notification settings - Fork 36.1k
Make layers apply recursively #19012
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
|
As outlined earlier (see #18937 (comment)), I do not vote to make this change and leave the code as it is for greater flexibility. |
|
@gkjohnson yes this would solve my issue. My only comment is that, if layers are recursive, the current default layer mask is flawed. In my opinion, the default should be all layers, just as the default "visibility" is true. Otherwise, to match a camera on layer 2 only, the user would have to traverse the tree to set the layer of each parent to 2 ( Another alternative is to default layers to |
This comment has been minimized.
This comment has been minimized.
|
Just thought of one more thing. Three.js allows the user to specify For a completely additive approach: (the only two workflows that are possible now) // Workflow 1
Layers.DefaultMask = 1;
var object1 = new THREE.Object3D();
object1.layers.enable(2); // Selectively add object1 and its child, but not object2
object1.add(child);
var object2 = new THREE.Object3D();
// Workflow 2 (This is the only impossible workflow after the PR, and it happens to be least common)
Layers.DefaultMask = 1;
var mesh1 = new THREE.Mesh();
var child2 = new THREE.Mesh();
object1.add(child2);
child2.layers.enable(2); // Selectively add child2 but hide its parent, mesh1For a completely subtractive approach: (2nd camera on layer 2 only) // Workflow 3
Layers.DefaultMask = 0xffffffff;
var object1 = new THREE.Object3D();
var child = new THREE.Mesh();
object1.add(child);
object1.layers.disable(2); // Selectively remove object1 and its child but keep object2
// Workflow 4
Layers.DefaultMask = 0xffffffff;
var mesh1 = new THREE.Mesh();
var child2 = new THREE.Mesh();
object1.add(child2);
child2.layers.disable(2); // Selectively remove child2 but keep its parent, mesh1For a mixed approach: (camera 1 has mask 5 and camera 2 has mask 10) // Workflow 5
Layers.DefaultMask = 0xffffff00;
var object1 = new THREE.Object3D();
var child1 = new THREE.Mesh();
object1.add(child1);
child1.layers.disable(10); // Selectively remove child 1 for camera 2
var child2 = new THREE.Mesh();
object1.add(child2);
child2.layers.enable(5); // Selectively enable child2 for camera 1
// Workflow 6
Layers.DefaultMask = 0xffffff00;
var object1 = new THREE.Object3D();
var child1 = new THREE.Mesh();
object1.add(child1);
child1.layers.disable(10); // Selectively remove child 1 from camera 2
class DefaultHiddenMesh extends THREE.Mesh {
constructor(..args) {
super(...args);
this.layers.disableAll();
}
}
var child2 = new DefaultHiddenMesh();
child2.layers.enable(5); // Selectively enable child2 for camera 1The only missing functionality, as I see it, is if a In summary, one uncommon workflow is rendered impossible but four more common workflows are made possible. |
I saw and I tried to inquire further (#18937 (comment)). Can you explain how you feel it's more flexible and what is lost by supporting this feature? As it is there seem to be no use cases that use parent node layers so this change will make them more powerful and capable than before. This PR gives a purpose to setting the layers of a parent node which are otherwise useless right now. I also think the behavior being different from I don't see this logic as application specific. Not every application is going to be managing every single object in the hierarchy. I see this as a tool for enabling encapsulated objects as extensions that can manage themselves and be treated as a whole. |
|
It's conceivable that some parent mesh could be disabled via layers while children are still enabled. I'd be hesitant to make this change as it's a breaking change, at least unless a way to make the new behavior optional is included. |
|
I think we could add |
Thanks that works for me! I am curious as to the reasoning behind wanting to keep the layers applying to leaves only by default when they otherwise have no influence on parent nodes. I just want to clarify so I can make more reasonable and agreeable contributions in the future. If backwards compatibility is a concern then defaulting parent nodes to layers |
As far as I understand, that's how Blender layers behave. I don't really have a preference but I would align to Blender, Unity, Unreal, etc |
|
I just made the changes! If I've added a unit test for raycasting and tested rendering by modifying the gltf.scene.layers.disableAll();
gltf.scene.layers.recursive = true; |
| } | ||
|
|
||
| var children = object.children; | ||
| if ( ! object.layers.recursive || object.layers.recursive && layerTest ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess ideally this would simply be:
if ( object.layers.recursive ) {Is this why you were proposing recursive = true by default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm open to make it true by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition is the way it is to accommodate the two cases of "traverse and render all children regardless of parent layer" (layers.recursive = false) and "only traverse and render children if parent layer passes test" (layers.recursive = true).
I originally suggested only supporting the layers.recursive = true behavior which would change this condition to be:
if ( layerTest ) {| if ( recursive === true ) { | ||
| } | ||
|
|
||
| if ( recursive === true ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we can also get rid of the custom recursive in Raycaster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I follow -- this recursive is the argument passed into the intersectObject function to indicate whether children should be traversed. It serves a different purpose. Are you suggesting getting rid of that argument?
|
@mrdoob any further thoughts on this PR? If needed I can try to explain the logic more clearly. Would it help if I separated the separated the conditions instead of putting all the logic in a single boolean statement? It also occured to me that that condition could be simplified to |
Fix #18937
This PR changes layers to apply recursively -- so if a parent object does not pass the layer test then raycasting and rendering traversal will stop. This will let users treat groups of objects as a whole and is more consistent with the way object visibility works.
Ping @finnbear to see if this addresses your usecase, too.