Open g-rauhoeft opened 3 months ago
Here's the user space workaround for the bug:
import { Canvas, events, LocalState, RootState } from '@react-three/fiber';
<Canvas
events={(state) => {
return {
...events(state),
filter: (intersections) => {
const getClosestPriority = (o: Object3D): number => {
if ((o as any)["__r3f"] !== undefined) {
return ((o as any)["__r3f"] as LocalState).root.getState().events
.priority;
} else {
return o.parent ? getClosestPriority(o.parent) : 0;
}
};
return intersections
.sort((a, b) => {
const aPriority = getClosestPriority(a.object);
const bPriority = getClosestPriority(b.object);
return bPriority - aPriority;
});
},
};
}}
>
{...}
</Canvas>
Hello Poimandres! Thank you for this awesome library! :)
I believe I've found a bug within the library concerning the event priority in conjunction with
createPortal
and glTF scenes. If I create a primitive and assign the gltf.scene as the object and add a click handler with prevent default, then add a portal in front of it containing a different object also with a click handler, the click handler of the object closest to its respective camera will be used instead of the one with the highest priority. This is because the__r3f
data is only assigned to the top level of the primitive, not to the children of it's object. If a child is clicked it causes thehits
array in theintersect
function to be assembled based on the distance instead of the priority, because no priority can be found, becausegetRootState
can't find the__r3f
object on the child.Here's a small reproduction of the issue: https://codesandbox.io/p/sandbox/tender-lederberg-43dr55
If you click on the ViewCube overlaying Suzanne, the click handler of Suzanne is executed, not the one of the ViewCube, which has a higher priority. The ViewCube at the bottom left works as expected, but only because Suzanne isn't behind it.
A user of the library can work around this by defining the filter function on the canvas for events, traversing the intersections upwards until a
__r3f
object is found and then sorting by priority, but this is inefficient, becauseintersect
also performs a sort.I can imagine two ways to fix this issue. I'd be happy to provide a pull request if you could let me know which fix is preferred.
__r3f
object to each child.getRootState
traverses the object hierarchy upwards if it can't find the__r3f
object on its parameter, until it finds an object that has the__r3f
object.Have a great day!