This is a basic example of using the Raycaster to mouse pick objects in the scene.
The scene is traversed and all individual objects are added to the pickableObjects array that is used by the Raycaster. The sphere and plane are deliberately excluded from this so they will not be mouse picked.
The plane also receives shadows while everything else only casts shadows.
Loading a GLB scene, traversing the child objects to individually add and/or copy properties for later use.
Using the Raycaster to detect if the mouse is over certain objects and changing there material.
Resources
The 3D model used in this lesson can be easily created using Blender. If you don't want to use blender to create the model, then you can download it from the zip file named models5.zip. Extract the models5.zip contents into the ./dist/client/models/ folder.
import*asTHREEfrom'three'import{OrbitControls}from'three/examples/jsm/controls/OrbitControls'import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader'importStatsfrom'three/examples/jsm/libs/stats.module'constscene=newTHREE.Scene()scene.add(newTHREE.AxesHelper(5))constlight=newTHREE.SpotLight(0xffffff,1000)light.position.set(12.5,12.5,12.5)light.castShadow=truelight.shadow.mapSize.width=1024light.shadow.mapSize.height=1024scene.add(light)constcamera=newTHREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)camera.position.set(15,15,15)constrenderer=newTHREE.WebGLRenderer()renderer.shadowMap.enabled=truerenderer.setSize(window.innerWidth,window.innerHeight)document.body.appendChild(renderer.domElement)constcontrols=newOrbitControls(camera,renderer.domElement)controls.enableDamping=trueconstpickableObjects:THREE.Mesh[]=[]letintersectedObject:THREE.Object3D|nullconstoriginalMaterials:{[id:string]:THREE.Material|THREE.Material[]}={}consthighlightedMaterial=newTHREE.MeshBasicMaterial({wireframe:true,color:0x00ff00,})constloader=newGLTFLoader()loader.load('models/simplescene.glb',function(gltf){gltf.scene.traverse(function(child){if((childasTHREE.Mesh).isMesh){constm=childasTHREE.Mesh//the sphere and plane will not be mouse picked. THe plane will receive shadows while everything else casts shadows.switch(m.name){case'Plane':m.receiveShadow=truebreakcase'Sphere':m.castShadow=truebreakdefault:m.castShadow=truepickableObjects.push(m)//store reference to original materials for lateroriginalMaterials[m.name]=(masTHREE.Mesh).material}}})scene.add(gltf.scene)},(xhr)=>{console.log((xhr.loaded/xhr.total)*100+'% loaded')},(error)=>{console.log(error)})window.addEventListener('resize',onWindowResize,false)functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeightcamera.updateProjectionMatrix()renderer.setSize(window.innerWidth,window.innerHeight)render()}constraycaster=newTHREE.Raycaster()letintersects:THREE.Intersection[]constmouse=newTHREE.Vector2()functiononDocumentMouseMove(event:MouseEvent){mouse.set((event.clientX/renderer.domElement.clientWidth)*2-1,-(event.clientY/renderer.domElement.clientHeight)*2+1)raycaster.setFromCamera(mouse,camera)intersects=raycaster.intersectObjects(pickableObjects,false)if(intersects.length>0){intersectedObject=intersects[0].object}else{intersectedObject=null}pickableObjects.forEach((o:THREE.Mesh,i)=>{if(intersectedObject&&intersectedObject.name===o.name){pickableObjects[i].material=highlightedMaterial}else{pickableObjects[i].material=originalMaterials[o.name]}})}document.addEventListener('mousemove',onDocumentMouseMove,false)conststats=newStats()document.body.appendChild(stats.dom)functionanimate(){requestAnimationFrame(animate)controls.update()render()stats.update()}functionrender(){renderer.render(scene,camera)}animate()