There is one old problem for me, but still I can't find same issue in task tracker.
Have a look at this line:
https://github.com/mrdoob/three.js/blob/a1daef37e5a6b80d0173af54edd000202b95fca5/src/core/Raycaster.js#L46
Why Raycaster checks visible
property only on intersectable's object? I mean, if I set visible = false
in parent, children become invisible for renderer, but still intersectable. Should Raycaster check nearest parents until find invisible? I have to check result of intersection for invisible parents in every single project. Is it any reason for not checking parents here?
My code:
var bool;
THREE.Object3D.prototype.isVisible = function() {
bool = true;
this.traverseAncestors((parent) => {
if (!parent.visible) bool = false;
});
return bool;
};
Is this what you are doing?
parent.add( object );
parent.visible = false;
raycaster.intersectsObjects( [ object ], recursive );
Um, this behavior is somewhat inconsistent. From my point of view, it would be actually better if intersectObject()
does not check the visibility at all and delegates this to the app level code.
If we keep if ( object.visible === false ) return;
, we might consider to check the hierarchy, too. However, this will impact performance.
@WestLangley nope. Recursive means raycaster will trigger all children of intersectable object. But I need to check parent's visibility recursive
@Disorrder How is that different from the code snippet I posted?
Um, this behavior is somewhat inconsistent. From my point of view, it would be actually better if
intersectObject()
does not check the visibility at all and delegates this to the app level code.
Yeah, I don't know what the solution is. We try to help the user but we can't handle situations like @Disorrder's.
For his use-case... he should either start the raycast test from the parent or use gpu picking.
Right. We can't handle situations like @Disorrder's. But we could change raycasting behavior to disregard the object's visible
property. I think it is worth giving that serious consideration.
I suggest to remove the test on Object3D.visible
and add a test based on Layers
instead. This idea was already suggested here https://github.com/mrdoob/three.js/issues/7551#issuecomment-154400499 and it would be similar to how raycasting works in Unity. In this way, we decouple the raycast from the visibility of the object but still allow to filter out unwanted objects. Something like this in intersectObject()
might work:
function intersectObject( object, raycaster, intersects, recursive ) {
if ( object.layers.test( raycaster.layers ) ) {
object.raycast( raycaster, intersects );
}
if ( recursive === true ) {
var children = object.children;
for ( var i = 0, l = children.length; i < l; i ++ ) {
intersectObject( children[ i ], raycaster, intersects, true );
}
}
}
Notice that children would still be tested even if the layer test evaluates to false
for the current object. In this way, layers in Raycaster
are treated similar like in WebGLRenderer
. Unfortunately, this change might break user code so it's problematic to get it into the library...
Is there any workaround or solution to use raycasting with invisible meshes?
Is there any workaround or solution to use raycasting with invisible meshes?
mesh.visible = true;
mesh.material.visible = false;
In this case, it will make the renderer draw it even if its material is invisible, won't it?
In this case, it will make the renderer draw it even if its material is invisible, won't it?
No, the renderer does only push renderable objects in the render list if the respective material is visible:
Then it's cool, thank you.
Related: #11312
I'd love to get this in, it could be super useful when interacting with different elements that you want to toggle on/off using the same raycaster, eg: opening the UI and hiding the elements on your scene or so.
There is one side effect when introducing THREE.Layer
to THREE.Raycaster
which is important to highlight. Let's say you want to exclude certain objects from raycasting via layers. This could be achieved by shifting objects from the default layer 0
to layer 1
via:
object.layers.disable( 0 );
object.layers.enable( 1 );
You have to be aware that with this configuration, objects in layer 1
won't get rendered since the renderer only processes objects which have a common layer with the camera. To render all objects AND to exclude certain objects from raycasting, you also need to configure the camera. In the above case you need to enable layer 1
.
camera.layers.enable( 1 );
So although the introduction of THREE.Layer
will provide great flexibility, the dependency to Camera.layers
might be a confusing bit for users. However, this could be clarified with the documentation.
But, we could add layers
to Raycaster
too.
raycaster.layers.set( 1 );
object.layers.enable( 1 );
But, we could add layers to Raycaster too.
Yes, that's just the other way around. I guess we only need to highlight in the docs how this approach is intended to be used.
11312 was pretty much there.
Yes, the question is should we remove the test on Object3D.visible
and only rely on layers instead. The current way how Object3D.visible
is handled is a bit inconsistent as the OP pointed out.
Yes, the question is should we remove the test on
Object3D.visible
and only rely on layers instead. The current way howObject3D.visible
is handled is a bit inconsistent as the OP pointed out.
Yes, I vote for removing the Object3D.visible
check (even if we may break user-land code). And implement Layers
.
+1 for removing .visible
in favor of layers
well, I really don't need this _feature_ , I need to ignore the invisible objects for raycast.
so someone need to raycast invisible, and someone still need to ignore invisible when raycast, why not create a switch so users can decide when to ignore invisible objects?
I think using THREE.Layers
should provide you this flexibility now.
Just updated to the latest version of THREE which includes this Raycaster.layers
feature (which is a great idea by the way), and at first it seemed to break our previous implementation of Raycaster. We use Layers in our application to show/hide different entities, and both Layers and Raycaster had previously worked great prior to updating THREE.
Once I updated, Raycaster.intersectObjects()
started returning an empty array. It seems that I now need to use raycaster.layers.set()
to enable all of our entities on layers to be visible to the Raycaster. Once I made this change Raycaster.intersectObjects()
began working properly again.
So, now I'm curious about the default state of Raycaster. I figured that Raycaster would by default check all layers if no layers were 'set', but the opposite seems to be true. You now need to tell Raycaster explicitly what layers to include, even if that means running all layers through raycaster.layers.set()
. Just hoping to get some clarification on why it was built this way. Thanks!
The default state is the same like for cameras. Raycaster only checks objects in channel zero. If you assign objects to different layers, you also have to configure the camera and raycaster accordingly.
Most helpful comment
I suggest to remove the test on
Object3D.visible
and add a test based onLayers
instead. This idea was already suggested here https://github.com/mrdoob/three.js/issues/7551#issuecomment-154400499 and it would be similar to how raycasting works in Unity. In this way, we decouple the raycast from the visibility of the object but still allow to filter out unwanted objects. Something like this inintersectObject()
might work:Notice that children would still be tested even if the layer test evaluates to
false
for the current object. In this way, layers inRaycaster
are treated similar like inWebGLRenderer
. Unfortunately, this change might break user code so it's problematic to get it into the library...