three#InstancedMesh TypeScript Examples

The following examples show how to use three#InstancedMesh. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: usePointer.ts    From trois with MIT License 4 votes vote down vote up
export default function usePointer(options: PointerConfigInterface): PointerInterface {
  const {
    camera,
    domElement,
    intersectObjects,
    intersectRecursive = false,
    touch = true,
    resetOnEnd = false,
    onEnter = () => {},
    onMove = () => {},
    onLeave = () => {},
    onClick = () => {},
    onIntersectEnter = () => {},
    onIntersectOver = () => {},
    onIntersectMove = () => {},
    onIntersectLeave = () => {},
    onIntersectClick = () => {},
  } = options

  const position = new Vector2(0, 0)
  const positionN = new Vector2(0, 0)

  const raycaster = useRaycaster({ camera })
  const positionV3 = raycaster.position

  const obj: PointerInterface = {
    position,
    positionN,
    positionV3,
    intersectObjects,
    listeners: false,
    addListeners,
    removeListeners,
    intersect,
  }

  return obj

  function reset() {
    position.set(0, 0)
    positionN.set(0, 0)
    positionV3.set(0, 0, 0)
  }

  function updatePosition(event: TouchEvent | MouseEvent) {
    let x, y
    // @ts-ignore
    if (event.touches && event.touches.length > 0) {
      x = (<TouchEvent>event).touches[0].clientX
      y = (<TouchEvent>event).touches[0].clientY
    } else {
      x = (<MouseEvent>event).clientX
      y = (<MouseEvent>event).clientY
    }

    const rect = domElement.getBoundingClientRect()
    position.x = x - rect.left
    position.y = y - rect.top
    positionN.x = (position.x / rect.width) * 2 - 1
    positionN.y = -(position.y / rect.height) * 2 + 1
    raycaster.updatePosition(positionN)
  }

  function intersect() {
    const _intersectObjects = getIntersectObjects()
    if (_intersectObjects.length) {
      const intersects = raycaster.intersect(positionN, _intersectObjects, intersectRecursive)
      const offObjects: Object3D[] = [..._intersectObjects]
      const iMeshes: InstancedMesh[] = []

      intersects.forEach(intersect => {
        const { object } = intersect
        const component = getComponent(object)

        // only once for InstancedMesh
        if (object instanceof InstancedMesh) {
          if (iMeshes.indexOf(object) !== -1) return
          iMeshes.push(object)
        }

        if (!object.userData.over) {
          object.userData.over = true
          const overEvent: PointerIntersectEventInterface = { type: 'pointerover', over: true, component, intersect }
          const enterEvent: PointerIntersectEventInterface = { ...overEvent, type: 'pointerenter' }
          onIntersectOver(overEvent)
          onIntersectEnter(enterEvent)
          component?.onPointerOver?.(overEvent)
          component?.onPointerEnter?.(enterEvent)
        }

        const moveEvent: PointerIntersectEventInterface = { type: 'pointermove', component, intersect }
        onIntersectMove(moveEvent)
        component?.onPointerMove?.(moveEvent)

        offObjects.splice(offObjects.indexOf((<Object3D>object)), 1)
      })

      offObjects.forEach(object => {
        const component = getComponent(object)
        if (object.userData.over) {
          object.userData.over = false
          const overEvent: PointerIntersectEventInterface = { type: 'pointerover', over: false, component }
          const leaveEvent: PointerIntersectEventInterface = { ...overEvent, type: 'pointerleave' }
          onIntersectOver(overEvent)
          onIntersectLeave(leaveEvent)
          component?.onPointerOver?.(overEvent)
          component?.onPointerLeave?.(leaveEvent)
        }
      })
    }
  }

  function pointerEnter(event: TouchEvent | MouseEvent) {
    updatePosition(event)
    onEnter({ type: 'pointerenter', position, positionN, positionV3 })
  }

  function pointerMove(event: TouchEvent | MouseEvent) {
    updatePosition(event)
    onMove({ type: 'pointermove', position, positionN, positionV3 })
    intersect()
  }

  function pointerClick(event: TouchEvent | MouseEvent) {
    updatePosition(event)
    const _intersectObjects = getIntersectObjects()
    if (_intersectObjects.length) {
      const intersects = raycaster.intersect(positionN, _intersectObjects, intersectRecursive)
      const iMeshes: InstancedMesh[] = []
      intersects.forEach(intersect => {
        const { object } = intersect
        const component = getComponent(object)

        // only once for InstancedMesh
        if (object instanceof InstancedMesh) {
          if (iMeshes.indexOf(object) !== -1) return
          iMeshes.push(object)
        }

        const event: PointerIntersectEventInterface = { type: 'click', component, intersect }
        onIntersectClick(event)
        component?.onClick?.(event)
      })
    }
    onClick({ type: 'click', position, positionN, positionV3 })
  }

  function pointerLeave() {
    if (resetOnEnd) reset()
    onLeave({ type: 'pointerleave' })
  }

  function getComponent(object: Object3D) {
    if (object.userData.component) return object.userData.component

    let parent = object.parent
    while (parent) {
      if (parent.userData.component) {
        return parent.userData.component
      }
      parent = parent.parent
    }

    return undefined
  }

  function getIntersectObjects() {
    if (typeof intersectObjects === 'function') {
      return intersectObjects()
    } else return intersectObjects
  }

  function addListeners() {
    domElement.addEventListener('mouseenter', pointerEnter)
    domElement.addEventListener('mousemove', pointerMove)
    domElement.addEventListener('mouseleave', pointerLeave)
    domElement.addEventListener('click', pointerClick)
    if (touch) {
      domElement.addEventListener('touchstart', pointerEnter)
      domElement.addEventListener('touchmove', pointerMove)
      domElement.addEventListener('touchend', pointerLeave)
    }
    obj.listeners = true
  }

  function removeListeners() {
    domElement.removeEventListener('mouseenter', pointerEnter)
    domElement.removeEventListener('mousemove', pointerMove)
    domElement.removeEventListener('mouseleave', pointerLeave)
    domElement.removeEventListener('click', pointerClick)

    domElement.removeEventListener('touchstart', pointerEnter)
    domElement.removeEventListener('touchmove', pointerMove)
    domElement.removeEventListener('touchend', pointerLeave)
    obj.listeners = false
  }
}