Click-to-Select Parts on a 3D GLTF Model with Three.js and Vue
Raycaster-based part selection is the standard interaction pattern for WebGL product configurators, maintenance training sims, and digital twins. This walkthrough bundles the full loop — picking, highlighting, name mapping, and cleanup — into a single Vue component that can be dropped into any project loading multi-part GLTF models.
A complete Vue component loads a missile-launcher GLTF model and wires up a Raycaster to detect clicks on individual sub-meshes. Each click restores the previously selected part to its original material, then turns the newly clicked mesh semi-transparent red. A hardcoded name map translates internal mesh names like `defaultMaterial_9` into human-readable labels shown in an overlay panel.
The implementation covers the full lifecycle: model loading with GLTFLoader, orbit controls for camera movement, coordinate conversion from screen space to NDC for the raycaster, and a disposal routine that tears down geometries, materials, the renderer, and controls to prevent memory leaks when the component unmounts.
Because the model’s sub-parts carry distinct `name` properties, the same pattern works on any multi-mesh GLTF asset — industrial equipment, mechanical assemblies, or architectural models — without modifying the source file.
The hardcoded name-to-label map (`defaultMaterial_9` → 'Missile Body') is brittle; any model re-export that changes internal mesh names will break the mapping silently. A more robust approach would store metadata in GLTF extras or a sidecar JSON.
The highlight logic directly mutates the original mesh material’s color and opacity, which means the original material state is lost unless explicitly saved beforehand. For models with complex PBR materials, a separate highlight material or an outline pass would preserve the original look.
Binding `document.onclick` globally instead of scoping the listener to the canvas means clicks outside the 3D viewport still trigger the raycaster, which is wasteful and risks unintended interactions with other UI elements.