Best Approach for Highlighting a Selected Mesh in a Room Planner Project

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:

  1. Using BoxHelper to draw a simple wireframe box around the selected item.
  2. Applying a glow or outline effect using post-processing (e.g., OutlinePass from EffectComposer).
  3. 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>
    </>
  );
}

:slightly_smiling_face:

Perhaps some variation of this? three.js examples

1 Like

I have already used this approach.
But I am finding more beautiful effect.
Thanks for your reply