I am a React Three Fiber novice and am using postprocessing effects to try and highlight interactable objects (child meshes) on a main mesh. I am using raycaster to determine the exact location of the cursor and an array with mesh names to check if a child is interactable or not. So far I have tried several approaches I could find on the internet, but none of them fits what I am trying to do, or I could not manage to adapt it. I found this example: https://codesandbox.io/p/sandbox/react-pp-outlines-nurp5t?file=%2Fsrc%2FEngine.js which I assume might work, but it would require me to rewrite a big part of my existing code which I spent a lot of time on and truly would not like to do right now, as I do not have the time (unless that is the only way).
If you would like to take a look at the entirety of the code, here is my codesandbox:
https://codesandbox.io/p/github/fatbigcat/DesignFundamentals/main?file=%2Fsrc%2Fmodels%2FIsland.jsx&workspaceId=14a9ef26-7da3-4f29-a311-91e333afdd58
I am using a custom function to handle pointer movement, which registers when an interactable object is hovered over and even logs the name, so this part works:
const handlePointerMove = (e) => {
mouse.x = (e.clientX / gl.domElement.clientWidth) * 2 - 1;
mouse.y = -(e.clientY / gl.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
const intersectedObject = intersects[0].object;
// console.log('Intersected object:', intersectedObject.name);
if (interactableMeshNames.includes(intersectedObject.name)) {
setHovered(intersectedObject);
console.log('Hovered:', intersectedObject.name);
} else {
setHovered(null);
}
}
//handles dragging to turn
if (pointer) { //implemented a let so that it doesn't register dragging whenever pointer is down
_setIsRotating(true);
e.stopPropagation();
e.preventDefault();
isDragging.current = true;
if (isDragging.current) {
const deltaX = e.clientX - lastX.current;
rotationSpeed.current = deltaX * 0.002;
lastX.current = e.clientX;
}
if (isRotating) {
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const deltaX = (clientX - lastX.current) / viewport.width;
islandRef.current.rotation.y += deltaX * Math.PI * 0.009;
lastX.current = clientX;
rotationSpeed.current = deltaX * 0.0001 * Math.PI;
}
}
};
Currently the outline shows up when an interactable mesh is hovered over, but it outlines the entire mesh, not only the child under the cursor, like I would like it to.
This is how I am wrapping the model (<Island/>) in my Home component with the <Selection> :
<Selection>
<EffectComposer multisampling={8} autoClear={false}>
<Outline
blur
visibleEdgeColor="white"
edgeStrength={10}
width={1000}
/>
</EffectComposer>
<Island
position={islandPosition}
scale={islandScale}
rotation={islandRotation}
isRotating={isRotating}
_setIsRotating={_setIsRotating}
setCurrentStage={setCurrentStage}
/>
</Selection>
Is there any way for me to outline the hovered-over mesh only, without completely scrapping and rewriting a large chunk of my code to try and follow the example above? If I try to move the <Select> anywhere other than the position it is now, the outline stops working. Looking at how the code behaves currently, I expect that the problem is in the way I wrap objects inside the <Select>, so I have tried traversing the child meshes and wrapping them in <Select> individually, like this:
return (
<group ref={islandRef} {...props}>
{scene.children.map((child) => (
<Select key={child.uuid} enabled={hovered === child}>
<primitive object={child} />
</Select>
))}
... Other models
);
but this removes the outline alltogether.
How could I make this work? Is it even possible? Why does this approach not work as I imagine it should? I would be very grateful for an explanation of the logic, as I am doing this for the first time and trying to understand how Three Fiber works.