Hello everyone,
I’m working on a room planner project using Three.js and React-Three-Fiber, and I’m currently focusing on applying a beautiful highlight effect to a selected mesh.
Current Scenario:
- The scene consists of walls and various items (e.g., furniture).
- When an item is selected, I want to show a highlight or bounding box around it to indicate selection.
My Challenge:
I’m exploring the best and most visually appealing way to achieve this effect, but I’m unsure which approach would be the best. Some ideas I’ve considered:
- Using BoxHelper to draw a simple wireframe box around the selected item.
- Applying a glow or outline effect using post-processing (e.g., OutlinePass from
EffectComposer
). - Adding a semi-transparent selection shader around the mesh.
I’d love to hear your thoughts! Which approach do you recommend for achieving a professional and aesthetically pleasing selection effect?
Here’s my current code:
Thanks in advance for your help!
import React, { useEffect, useRef } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { Mesh, BoxGeometry, LineSegments, EdgesGeometry, Vector3 } from "three";
import * as THREE from "three";
import useRoomPlannerStore from "@store/threeStore";
import { MeshType } from "src/typings/types";
function getMeshSize(mesh: THREE.Mesh): THREE.Vector3 {
const size = new Vector3();
mesh.geometry.computeBoundingBox();
mesh.geometry.boundingBox?.getSize(size);
return size;
}
export default function SelectedItem() {
const { selectedItem } = useRoomPlannerStore();
const { scene } = useThree();
const edgeRef = useRef<LineSegments>(null);
useEffect(() => {
if (edgeRef.current) scene.add(edgeRef.current);
const edge = edgeRef.current;
return () => {
if (edge) scene.remove(edge);
};
}, [scene]);
useEffect(() => {
if (!edgeRef.current)
return;
if (!selectedItem || !(selectedItem instanceof Mesh)) {
edgeRef.current.visible = false;
return;
}
edgeRef.current.visible = true;
// Identify mesh type
const meshType = selectedItem.userData.meshType;
// Handle edges for walls
if (meshType === MeshType.WALL) {
edgeRef.current.geometry = new EdgesGeometry(selectedItem.geometry);
} else {
const size = getMeshSize(selectedItem);
edgeRef.current.geometry = new EdgesGeometry(new BoxGeometry(size.x + 0.05, size.y + 0.05, size.z + 0.05));
}
edgeRef.current.position.copy(selectedItem.position);
edgeRef.current.rotation.copy(selectedItem.rotation);
edgeRef.current.scale.copy(selectedItem.scale);
}, [selectedItem]);
useFrame(() => {
if (!selectedItem) return;
if (edgeRef.current) {
edgeRef.current.position.copy(selectedItem.position);
edgeRef.current.rotation.copy(selectedItem.rotation);
edgeRef.current.scale.copy(selectedItem.scale);
}
});
return (
<>
<lineSegments ref={edgeRef}>
<lineBasicMaterial attach="material" color="#00bbff" linewidth={10} />
</lineSegments>
</>
);
}