/**
* Raycaster
*/
const raycaster = new THREE.Raycaster()
const rayOrigin = new THREE.Vector3(- 3, 0, 0)
const rayDirection = new THREE.Vector3(10, 0, 0)
rayDirection.normalize()
raycaster.set(rayOrigin, rayDirection)
const intersect = raycaster.intersectObject(object2)
console.log(intersect)
const intersects = raycaster.intersectObjects([object1, object2, object3])
console.log(intersects)
distance - ray의 origin과 collision point와의 거리
face - geometry의 어떤 면이 hit되었는지
faceIndex - geometry hit된 면의 index
object - 어떤 object인지
point - collsion point의 vector3
uv - geometry 기준 uv 좌표
매 프레임 마다 racast가 진행되도록 진행
const clock = new THREE.Clock()
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// Animate objects
object1.position.y = Math.sin(elapsedTime * 0.3) * 1.5
object2.position.y = Math.sin(elapsedTime * 0.8) * 1.5
object3.position.y = Math.sin(elapsedTime * 1.4) * 1.5
// ...
}
const clock = new THREE.Clock()
const tick = () =>
{
// ...
// Cast a ray
const rayOrigin = new THREE.Vector3(- 3, 0, 0)
const rayDirection = new THREE.Vector3(1, 0, 0)
rayDirection.normalize()
raycaster.set(rayOrigin, rayDirection)
const objectsToTest = [object1, object2, object3]
const intersects = raycaster.intersectObjects(objectsToTest)
console.log(intersects)
// ...
}
for(const object of objectsToTest)
{
object.material.color.set('#ff0000')
}
for(const intersect of intersects)
{
intersect.object.material.color.set('#0000ff')
}
고정된 raycaster가 아닌 mouseevent를 활용한 raycaster를 만들어보자
/**
* Mouse
*/
const mouse = new THREE.Vector2()
window.addEventListener('mousemove', (event) =>
{
mouse.x = event.clientX / sizes.width * 2 - 1
mouse.y = - (event.clientY / sizes.height) * 2 + 1
})
raycaster.setFromCamera(mouse, camera)
const objectsToTest = [object1, object2, object3]
const intersects = raycaster.intersectObjects(objectsToTest)
for(const intersect of intersects)
{
intersect.object.material.color.set('#0000ff')
}
for(const object of objectsToTest)
{
if(!intersects.find(intersect => intersect.object === object))
{
object.material.color.set('#ff0000')
}
}
let currentIntersect = null
const tick = () =>
{
// ...
raycaster.setFromCamera(mouse, camera)
const objectsToTest = [object1, object2, object3]
const intersects = raycaster.intersectObjects(objectsToTest)
if(intersects.length)
{
if(!currentIntersect)
{
console.log('mouse enter')
}
currentIntersect = intersects[0]
}
else
{
if(currentIntersect)
{
console.log('mouse leave')
}
currentIntersect = null
}
// ...
}
window.addEventListener('click', () =>
{
if(currentIntersect)
{
switch(currentIntersect.object)
{
case object1:
console.log('click on object 1')
break
case object2:
console.log('click on object 2')
break
case object3:
console.log('click on object 3')
break
}
}
})
let model = null
gltfLoader.load(
'./models/Duck/glTF-Binary/Duck.glb',
(gltf) =>
{
model = gltf.scene
model.position.y = - 1.2
scene.add(model)
}
)
const tick = () =>
{
// ...
if(model)
{
const modelIntersects = raycaster.intersectObject(model)
console.log(modelIntersects)
}
// ...
}
원래는 model은 Group이고 raycaster는 mesh를 체크하기 때문에 정상적으로 작동하면 안된다.
그러나 raycaster는 단지 model만 check하는게 아니고 recursive적으로 children을 다 체크한다.
이 옵션은 raycaster.intersectObject(model,false)로 false를 주면서 끌 수도 있다.
const tick = () =>
{
// ...
if(model)
{
const modelIntersects = raycaster.intersectObject(model)
if(modelIntersects.length)
{
model.scale.set(1.2, 1.2, 1.2)
}
else
{
model.scale.set(1, 1, 1)
}
}
// ...
}
https://22-raycaster-and-mouse-events-1veayyu1y-hwangsangjins-projects.vercel.app/