Why Raycast with GLTF not working

This is my code i don’t know why array of intersects is empty after intersectObjects and raycasting is not working

import * as THREE from 'three'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

const renderer = new THREE.WebGL1Renderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.01, 1000)
camera.position.set(0.8, 2.4, 2.0)

const scene = new THREE.Scene()

scene.add(new THREE.AxesHelper(5))

const light = new THREE.PointLight()
light.position.set(3, 5, 5)
scene.add(light)

const controls = new OrbitControls(camera, renderer.domElement)

const loader: GLTFLoader = new GLTFLoader()

const raycaster = new THREE.Raycaster()
const sceneMeshes: THREE.Object3D[] = []

loader.load('models/vanguard.glb', 
    (object) => {
        console.log('object', object)
        object.scene.traverse( child => {
            if ((child as THREE.Mesh).isMesh) {
                sceneMeshes.push(child as THREE.Mesh) 
            }
        })
        scene.add(object.scene)
    }   
)

const arrowHelper = new THREE.ArrowHelper(
    new THREE.Vector3(),
    new THREE.Vector3(),
    0.25,
    0xffff00
)
scene.add(arrowHelper)

const render = () => {
    renderer.render(scene, camera)
}

const onMouseMove = (event: any) => {
    const mouse = {
        x: (event.clientX / renderer.domElement.width) * 2 - 1,
        y: (event.clientY / renderer.domElement.height) * 2 - 1 
    }

    raycaster.setFromCamera(mouse, camera)
    const intersects = raycaster.intersectObjects(sceneMeshes, false)
    
    if(intersects.length > 0) {
        
        const n = new THREE.Vector3()
        n.copy((intersects[0].face as THREE.Face).normal)

        arrowHelper.setDirection(n)
        arrowHelper.position.copy(intersects[0].point)
    }
}

renderer.domElement.addEventListener('mousemove', onMouseMove)

const resize = () => {
    camera.aspect = window.innerWidth / innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
    render()
}
window.addEventListener('resize', resize, false)

const animate = () => {
    requestAnimationFrame(animate)

    controls.update()

    render()
}

animate()

vanguard.glb (3.3 MB)

Hi!
Try to change this
y: (event.clientY / renderer.domElement.height) * 2 - 1
into this
y: - ( event.clientY / renderer.domElement.height ) * 2 + 1

1 Like

Hi! I just fix that but problem didn’t solved.
intersects array is always empty has not intersected objects with ray

import * as THREE from 'three'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

const renderer = new THREE.WebGL1Renderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.01, 1000)
camera.position.set(0.8, 2.4, 2.0)

const scene = new THREE.Scene()

scene.add(new THREE.AxesHelper(5))

const light = new THREE.PointLight()
light.position.set(3, 5, 5)
scene.add(light)

const controls = new OrbitControls(camera, renderer.domElement)

const loader: GLTFLoader = new GLTFLoader()

const raycaster = new THREE.Raycaster()
const sceneMeshes: THREE.Object3D[] = []

loader.load('models/vanguard.glb', 
    (object) => {
        console.log('object', object)
        object.scene.traverse( child => {
            if ((child as THREE.Mesh).isMesh) {
                sceneMeshes.push(child as THREE.Mesh) 
            }
        })
        scene.add(object.scene)
    }   
)

const arrowHelper = new THREE.ArrowHelper(
    new THREE.Vector3(),
    new THREE.Vector3(),
    0.25,
    0xffff00
)
scene.add(arrowHelper)

const render = () => {
    renderer.render(scene, camera)
}

const onMouseMove = (event: any) => {
    const mouse = {
        x: (event.clientX / renderer.domElement.width) * 2 - 1,
        y: -(event.clientY / renderer.domElement.height) * 2 + 1 
    }

    raycaster.setFromCamera(mouse, camera)
    const intersects = raycaster.intersectObjects(sceneMeshes, false)
    
    if(intersects.length > 0) {
        const n = new THREE.Vector3()
        n.copy((intersects[0].face as THREE.Face).normal)

        arrowHelper.setDirection(n)
        arrowHelper.position.copy(intersects[0].point)
    }
}

renderer.domElement.addEventListener('mousemove', onMouseMove)

const resize = () => {
    camera.aspect = window.innerWidth / innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
    render()
}
window.addEventListener('resize', resize, false)

const animate = () => {
    requestAnimationFrame(animate)

    controls.update()

    render()
}

animate()
 

But now i change this section in code and it is works.
in this case when i log ‘m’ that is THREE.SkinnedMesh and raycasting doesn’t work, but when i create THREE.Mesh from ‘m’ geometry and material raycasting is works. So Problem is in SkinnedMesh. Is anyone know can i do raycasting with THREE.SkinnedMeshes?

loader.load('models/vanguard.glb', 
    (object) => {
        console.log('object', object)
        object.scene.traverse( child => {
            if ((child as THREE.Mesh).isMesh) {
                const m = child as THREE.Mesh
                m.receiveShadow = true
                m.castShadow = true;
                (m.material as THREE.MeshStandardMaterial).flatShading = true
                sceneMeshes.push(new THREE.Mesh(m.geometry, m.material))
            }
        })
        scene.add(object.scene)
    }   
)