Description:
According to the A-Frame docs (https://aframe.io/docs/0.8.0/components/material.html#properties_visible), raycasters should ignore entities that have material="visible: false;". This doesn't seem to be the case when raycaster="objects: ... ;" is defined. In this case, all qualifying objects are raycasted regardless of visibility.
Should material.visible not still affect raycasting on these entities?
0.7.* - 0.8.*I had the problem few days ago and material="visible: false;" didn't work neither.
My solution today is to set a class .interactible on my visible entities which should interact with the raycaster.
On my cursor I setted
<a-entity id='myCursor'
cursor="fuse: true;"
raycaster="interval: 200; objects: .interactible"
...
Then, after each interactible objects update I launch
AFRAME.scenes[0].querySelector('[raycaster]').components.raycaster.refreshObjects();
Hope it can help.
It might be a change in three.js logic. But setting objects is best practice.
You probably don't have to manually refresh.
You probably don't have to manually refresh.
^Assuming A-Frame 0.8+. The raycaster should log something if you are using an objects selector it can't auto-refresh.
They still auto-refresh with or without the selector.
Yes, but there are some selectors that autorefreshing will not catch. E.g., if setAttribute() call is not serialized to the DOM. I just mean that you'll see a warning logged if you are using one of these selectors.
Thanks, @ArnaudRemi @ngokevin @donmccurdy . I typically use the same practices you outlined, @ArnaudRemi , however the material.visible functionality doesn't work as documented, hence the issue.
I may be mistaken, but I'm pretty sure I still had to manually refresh the objects when adding/removing classes for raycaster objects. I'll have to test this again to be sure.
I have a somewhat related issue open (#3552), also with a demo illustrating that material="visible: false;" doesn't appear to affect the raycaster regardless of whether or not raycaster objects are defined. The only difference between this issue and #3552 is that, in the latter, visible="false" is ignored by the raycaster rather than material="visible: false;". This seems to be the opposite of what is documented.
I hit this issue recently and found the following three.js change log item from r72: https://github.com/mrdoob/three.js/issues/6758
This behavior matches what @dsinni describes and seems like a conscious design decision on three.js's part that's been around for a couple years.
The "Raycasters will ignore invisible materials." line in the documentation has been there since 0.3.0, which used r76.1. But I was able to reproduce the raycaster intersecting an object with material="visible: false;" in 0.3.0 (gaze to the right of the yellow box):
<html>
<head>
<script src="https://aframe.io/releases/0.3.0/aframe.min.js"></script>
<script>
// Component to change to random color on click.
AFRAME.registerComponent('cursor-listener', {
init: function () {
var COLORS = ['red', 'green', 'blue'];
this.el.addEventListener('click', function (e) {
var randomIndex = Math.floor(Math.random() * COLORS.length);
this.setAttribute('material', 'color', COLORS[randomIndex]);
this.setAttribute('material', 'visible', true);
console.log('I was clicked!', e);
});
}
});
</script>
</head>
<body>
<a-scene>
<a-entity camera="userHeight: 1.6" look-controls wasd-controls>
<a-entity raycaster="objects: .clickable" cursor="fuse: true" position="0 0 -1" scale="0.05 0.05 0.05" geometry="primitive: ring" ></a-entity>
</a-entity>
<a-entity material="visible: false;" class="clickable" cursor-listener geometry="primitive: box" position="1 0 -3"></a-entity>
<a-entity material="color: yellow;" class="clickable" cursor-listener geometry="primitive: box" position="0 0 -3"></a-entity>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
</html>
So, while it seems that the documentation is the inverse of what is true between material="visible: false;" and visible="false", would it still not make the most sense for the raycaster to ignore an entity with visible="false" regardless of whether or not it qualifies as a raycaster object? That, to me, seems like the most consistent way of handling it.
If it's desired for the entity to not be visible while also being raycastable, material="visible: false;" can still be used. This seems cleaner to me than having to add/remove/replace query selectors.
Out of curiosity, if this method were to be used, would raycaster objects still need to be refreshed manually?
would it still not make the most sense for the raycaster to ignore an entity with visible="false" regardless of whether or not it qualifies as a raycaster object?
I often have hidden raycaster targets to pad the click range (e.g., small targets). Often, you still want to trigger with invisible objects. I even have a raycaster-target helper component that drops a hidden raycaster target by width/height.
If it's desired for the entity to not be visible while also being raycastable, material="visible: false;" can still be used. This seems cleaner to me than having to add/remove/replace query selectors.
Regardless, you want to use query selectors, else everything will be raycastable. Some things I do is I create a raycastable component that can be mixed in. Or data-raycastable with a helper component that toggles them on / off based on like what menu you're on. Or with the state component, bind-toggle__raycastable. I always limit exactly to what should be raycastable because it's expensive.
Explicit > implicit in this case, especially as it involves performance and visibility of objects is not always a determining factor.
But yeah, docs should be updated with best practices. Been building complex menus and have mastered the art of the raycaster.
Thanks for the reply @ngokevin. I'm sure you have it all figured out, because you're the dude. haha. But it seems rather complex for something somewhat trivial.
If the raycaster ignores visible="false" but not material="visible: false;" then the latter could be used for invisible, raycastable entities. The problem is that, _when_ using raycaster objects, _both_ are raycastable.
I'm wondering if it's possible to still follow the former paradigm _even when_ raycaster objects are defined, since there are two workable options to choose from already without needing to use external components.
Essentially, I think it would be beneficial to have a way (right out of the box) to make a qualifying raycaster object _not_ be raycastable due to its invisibility.
Is this something that could even be done in A-Frame, or would it need to be implemented in THREE.js?
Not anymore without hacking the component, it's best practice and prescribed to control what is being raycasted. What I propose wasn't showing off (I'm not a wizard), it is simple. Rather than depending on what is somewhat an arbitrary condition (visibility) and doing object3D.visible = false, do either like <a-entity data-no-raycast> or <a-entity data-raycastable> with objects: [data-raycastable] or objects: :not([data-no-raycast].
If you are depending solely on visibility, it sounds like the app has no system in place to toggle what is being raycasted, and your app is raycasting every single object, which is a killer for performance.
Don't be modest, @ngokevin; you are a wizard.
I feel like I may not be communicating my thoughts very well, though. I'm not suggesting solely depending on visibility, but more a combination of raycaster objects _and_ visibility, i.e., the raycaster handling visibility the same way regardless of whether or not raycaster objects are defined. This is not currently the case. Both material.visible and visible are completely disregarded (the entity is still raycastable) if raycaster objects are defined. This is inconsistent with how the raycaster behaves when they are _not_ defined.
I agree that a better system can be utilized to keep track (for those who are savvy enough), but the inconsistency has potential to cause confusion when a simple approach could be possible.
I think that's just three.js behavior. Regardless, you should always define objects, and never depend on visibility. It is consistent if you ignore the case where you don't define objects because that should be done, or perhaps even required.
Docs no longer say anything about visibility affect raycaster and prescribe setting objects.
Apologies for commenting on this old thread. I have a problem and I cannot find the solution anywhere for it.
How do i add raycasting objects in aframe-react.
This is my cursor component.
<Entity
// color={cursorColor}
primitive="a-cursor"
animation__click={{
property: "scale",
startEvents: "click",
from: "0.1 0.1 0.1",
to: "1 1 1",
dur: 150
}}
/>
i.e I want to add click/hover only to an entity with the id 32. How can I achieve this?
On a side-not: So setting material: visible to false would still raycast?
@SaudTauqeer I recommend stack overflow for usage questions. We use Github for bugs and feature requests
Most helpful comment
I hit this issue recently and found the following three.js change log item from r72: https://github.com/mrdoob/three.js/issues/6758
This behavior matches what @dsinni describes and seems like a conscious design decision on three.js's part that's been around for a couple years.
The "Raycasters will ignore invisible materials." line in the documentation has been there since 0.3.0, which used r76.1. But I was able to reproduce the raycaster intersecting an object with
material="visible: false;"in 0.3.0 (gaze to the right of the yellow box):