mirror of
https://github.com/troisjs/trois.git
synced 2024-11-23 20:02:32 +08:00
improve raycasting #67
This commit is contained in:
parent
995cdf7c49
commit
bea23d4d4d
@ -26,6 +26,16 @@ export interface Object3DPublicInterface extends ComponentPublicInstance, Object
|
||||
// return { scene, renderer }
|
||||
// }
|
||||
|
||||
export const pointerProps = {
|
||||
onPointerEnter: Function,
|
||||
onPointerOver: Function,
|
||||
onPointerMove: Function,
|
||||
onPointerLeave: Function,
|
||||
onPointerDown: Function,
|
||||
onPointerUp: Function,
|
||||
onClick: Function,
|
||||
}
|
||||
|
||||
export interface Vector2PropInterface {
|
||||
x?: number
|
||||
y?: number
|
||||
@ -59,6 +69,7 @@ export default defineComponent({
|
||||
props: { type: Object, default: () => ({}) },
|
||||
disableAdd: { type: Boolean, default: false },
|
||||
disableRemove: { type: Boolean, default: false },
|
||||
...pointerProps,
|
||||
},
|
||||
setup(): Object3DSetupInterface {
|
||||
// return object3DSetup()
|
||||
@ -74,10 +85,24 @@ export default defineComponent({
|
||||
},
|
||||
unmounted() {
|
||||
if (!this.disableRemove) this.removeFromParent()
|
||||
if (this.o3d) {
|
||||
if (this.renderer) this.renderer.three.removeIntersectObject(this.o3d)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initObject3D(o3d: Object3D) {
|
||||
this.o3d = o3d
|
||||
o3d.userData.component = this
|
||||
|
||||
if (this.onPointerEnter ||
|
||||
this.onPointerOver ||
|
||||
this.onPointerMove ||
|
||||
this.onPointerLeave ||
|
||||
this.onPointerDown ||
|
||||
this.onPointerUp ||
|
||||
this.onClick) {
|
||||
if (this.renderer) this.renderer.three.addIntersectObject(o3d)
|
||||
}
|
||||
|
||||
bindProp(this, 'position', o3d)
|
||||
bindProp(this, 'rotation', o3d)
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Object3D } from 'three'
|
||||
import { defineComponent, inject, PropType } from 'vue'
|
||||
import usePointer, { IntersectObject, PointerInterface, PointerIntersectCallbackType } from './usePointer'
|
||||
import usePointer, { PointerInterface, PointerIntersectCallbackType } from './usePointer'
|
||||
import { RendererInjectionKey, RendererInterface } from './Renderer'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
@ -39,7 +38,7 @@ export default defineComponent({
|
||||
this.pointer = usePointer({
|
||||
camera: renderer.camera,
|
||||
domElement: renderer.canvas,
|
||||
intersectObjects: this.getIntersectObjects(),
|
||||
intersectObjects: () => renderer.scene ? renderer.scene.children : [],
|
||||
intersectRecursive: this.intersectRecursive,
|
||||
onIntersectEnter: this.onPointerEnter,
|
||||
onIntersectOver: this.onPointerOver,
|
||||
@ -60,15 +59,6 @@ export default defineComponent({
|
||||
this.renderer?.offBeforeRender(this.pointer.intersect)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getIntersectObjects() {
|
||||
if (this.renderer && this.renderer.scene) {
|
||||
const children = this.renderer.scene.children.filter((c: Object3D) => ['Mesh', 'InstancedMesh'].includes(c.type))
|
||||
return children as IntersectObject[]
|
||||
}
|
||||
return []
|
||||
},
|
||||
},
|
||||
render() {
|
||||
return []
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
import { Camera, InstancedMesh, Intersection, Mesh, Vector2, Vector3 } from 'three'
|
||||
import { Camera, InstancedMesh, Intersection, Object3D, Vector2, Vector3 } from 'three'
|
||||
import useRaycaster from './useRaycaster'
|
||||
|
||||
export interface PointerEventInterface {
|
||||
@ -18,7 +18,6 @@ export interface PointerIntersectEventInterface {
|
||||
|
||||
export type PointerCallbackType = (e: PointerEventInterface) => void
|
||||
export type PointerIntersectCallbackType = (e: PointerIntersectEventInterface) => void
|
||||
export type IntersectObject = Mesh | InstancedMesh
|
||||
|
||||
export interface PointerPublicConfigInterface {
|
||||
intersectMode?: 'frame'
|
||||
@ -39,14 +38,14 @@ export interface PointerPublicConfigInterface {
|
||||
export interface PointerConfigInterface extends PointerPublicConfigInterface {
|
||||
camera: Camera
|
||||
domElement: HTMLCanvasElement
|
||||
intersectObjects: IntersectObject[]
|
||||
intersectObjects: Object3D[] | (() => Object3D[])
|
||||
}
|
||||
|
||||
export interface PointerInterface {
|
||||
position: Vector2
|
||||
positionN: Vector2
|
||||
positionV3: Vector3
|
||||
intersectObjects: IntersectObject[]
|
||||
intersectObjects: Object3D[] | (() => Object3D[])
|
||||
listeners: boolean
|
||||
addListeners(cb: void): void
|
||||
removeListeners(cb: void): void
|
||||
@ -117,14 +116,15 @@ export default function usePointer(options: PointerConfigInterface): PointerInte
|
||||
}
|
||||
|
||||
function intersect() {
|
||||
if (intersectObjects.length) {
|
||||
const intersects = raycaster.intersect(positionN, intersectObjects, intersectRecursive)
|
||||
const offObjects: IntersectObject[] = [...intersectObjects]
|
||||
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 } = object.userData
|
||||
const component = getComponent(object)
|
||||
|
||||
// only once for InstancedMesh
|
||||
if (object instanceof InstancedMesh) {
|
||||
@ -138,27 +138,27 @@ export default function usePointer(options: PointerConfigInterface): PointerInte
|
||||
const enterEvent: PointerIntersectEventInterface = { ...overEvent, type: 'pointerenter' }
|
||||
onIntersectOver(overEvent)
|
||||
onIntersectEnter(enterEvent)
|
||||
component.onPointerOver?.(overEvent)
|
||||
component.onPointerEnter?.(enterEvent)
|
||||
component?.onPointerOver?.(overEvent)
|
||||
component?.onPointerEnter?.(enterEvent)
|
||||
}
|
||||
|
||||
const moveEvent: PointerIntersectEventInterface = { type: 'pointermove', component, intersect }
|
||||
onIntersectMove(moveEvent)
|
||||
component.onPointerMove?.(moveEvent)
|
||||
component?.onPointerMove?.(moveEvent)
|
||||
|
||||
offObjects.splice(offObjects.indexOf((<IntersectObject>object)), 1)
|
||||
offObjects.splice(offObjects.indexOf((<Object3D>object)), 1)
|
||||
})
|
||||
|
||||
offObjects.forEach(object => {
|
||||
const { component } = object.userData
|
||||
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)
|
||||
component?.onPointerOver?.(overEvent)
|
||||
component?.onPointerLeave?.(leaveEvent)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -177,12 +177,13 @@ export default function usePointer(options: PointerConfigInterface): PointerInte
|
||||
|
||||
function pointerClick(event: TouchEvent | MouseEvent) {
|
||||
updatePosition(event)
|
||||
if (intersectObjects.length) {
|
||||
const intersects = raycaster.intersect(positionN, intersectObjects, intersectRecursive)
|
||||
const _intersectObjects = getIntersectObjects()
|
||||
if (_intersectObjects.length) {
|
||||
const intersects = raycaster.intersect(positionN, _intersectObjects, intersectRecursive)
|
||||
const iMeshes: InstancedMesh[] = []
|
||||
intersects.forEach(intersect => {
|
||||
const { object } = intersect
|
||||
const { component } = object.userData
|
||||
const component = getComponent(object)
|
||||
|
||||
// only once for InstancedMesh
|
||||
if (object instanceof InstancedMesh) {
|
||||
@ -192,7 +193,7 @@ export default function usePointer(options: PointerConfigInterface): PointerInte
|
||||
|
||||
const event: PointerIntersectEventInterface = { type: 'click', component, intersect }
|
||||
onIntersectClick(event)
|
||||
component.onClick?.(event)
|
||||
component?.onClick?.(event)
|
||||
})
|
||||
}
|
||||
onClick({ type: 'click', position, positionN, positionV3 })
|
||||
@ -203,6 +204,26 @@ export default function usePointer(options: PointerConfigInterface): PointerInte
|
||||
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)
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { Camera, Intersection, Plane, Raycaster, Vector2, Vector3 } from 'three'
|
||||
import { IntersectObject } from './usePointer'
|
||||
import { Camera, Intersection, Object3D, Plane, Raycaster, Vector2, Vector3 } from 'three'
|
||||
|
||||
export interface RaycasterInterface {
|
||||
position: Vector3
|
||||
updatePosition(coords: Vector2): void
|
||||
intersect(coords: Vector2, objects: IntersectObject[], recursive?: boolean): Intersection[],
|
||||
intersect(coords: Vector2, objects: Object3D[], recursive?: boolean): Intersection[],
|
||||
}
|
||||
|
||||
export interface RaycasterConfigInterface {
|
||||
@ -28,7 +27,7 @@ export default function useRaycaster(options: RaycasterConfigInterface): Raycast
|
||||
raycaster.ray.intersectPlane(plane, position)
|
||||
}
|
||||
|
||||
const intersect = (coords: Vector2, objects: IntersectObject[], recursive = false) => {
|
||||
const intersect = (coords: Vector2, objects: Object3D[], recursive = false) => {
|
||||
raycaster.setFromCamera(coords, camera)
|
||||
return raycaster.intersectObjects(objects, recursive)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Camera, OrthographicCamera, PerspectiveCamera, Scene, WebGLRenderer } from 'three'
|
||||
import { Camera, Object3D, OrthographicCamera, PerspectiveCamera, Scene, WebGLRenderer } from 'three'
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
|
||||
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'
|
||||
import usePointer, { IntersectObject, PointerConfigInterface, PointerPublicConfigInterface, PointerInterface } from './usePointer'
|
||||
import usePointer, { PointerConfigInterface, PointerPublicConfigInterface, PointerInterface } from './usePointer'
|
||||
|
||||
export interface SizeInterface {
|
||||
width: number
|
||||
@ -39,8 +39,8 @@ export interface ThreeInterface {
|
||||
render(): void
|
||||
renderC(): void
|
||||
setSize(width: number, height: number): void
|
||||
addIntersectObject(o: IntersectObject): void
|
||||
removeIntersectObject(o: IntersectObject): void
|
||||
addIntersectObject(o: Object3D): void
|
||||
removeIntersectObject(o: Object3D): void
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,7 +74,7 @@ export default function useThree(params: ThreeConfigInterface): ThreeInterface {
|
||||
|
||||
const beforeRenderCallbacks: {(): void}[] = []
|
||||
|
||||
const intersectObjects: IntersectObject[] = []
|
||||
const intersectObjects: Object3D[] = []
|
||||
|
||||
const renderer = createRenderer()
|
||||
|
||||
@ -191,7 +191,7 @@ export default function useThree(params: ThreeConfigInterface): ThreeInterface {
|
||||
/**
|
||||
* add intersect object
|
||||
*/
|
||||
function addIntersectObject(o: IntersectObject) {
|
||||
function addIntersectObject(o: Object3D) {
|
||||
if (intersectObjects.indexOf(o) === -1) {
|
||||
intersectObjects.push(o)
|
||||
}
|
||||
@ -204,7 +204,7 @@ export default function useThree(params: ThreeConfigInterface): ThreeInterface {
|
||||
/**
|
||||
* remove intersect object
|
||||
*/
|
||||
function removeIntersectObject(o: IntersectObject) {
|
||||
function removeIntersectObject(o: Object3D) {
|
||||
const i = intersectObjects.indexOf(o)
|
||||
if (i !== -1) {
|
||||
intersectObjects.splice(i, 1)
|
||||
|
@ -3,16 +3,6 @@ import { BufferGeometry, Material, Mesh as TMesh } from 'three'
|
||||
import Object3D, { Object3DSetupInterface } from '../core/Object3D'
|
||||
import { bindProp } from '../tools'
|
||||
|
||||
export const pointerProps = {
|
||||
onPointerEnter: Function,
|
||||
onPointerOver: Function,
|
||||
onPointerMove: Function,
|
||||
onPointerLeave: Function,
|
||||
onPointerDown: Function,
|
||||
onPointerUp: Function,
|
||||
onClick: Function,
|
||||
}
|
||||
|
||||
export interface MeshSetupInterface extends Object3DSetupInterface {
|
||||
mesh?: TMesh
|
||||
geometry?: BufferGeometry
|
||||
@ -35,7 +25,6 @@ const Mesh = defineComponent({
|
||||
props: {
|
||||
castShadow: Boolean,
|
||||
receiveShadow: Boolean,
|
||||
...pointerProps,
|
||||
},
|
||||
setup(): MeshSetupInterface {
|
||||
return {}
|
||||
@ -52,21 +41,10 @@ const Mesh = defineComponent({
|
||||
methods: {
|
||||
initMesh() {
|
||||
const mesh = new TMesh(this.geometry, this.material)
|
||||
mesh.userData.component = this
|
||||
|
||||
bindProp(this, 'castShadow', mesh)
|
||||
bindProp(this, 'receiveShadow', mesh)
|
||||
|
||||
if (this.onPointerEnter ||
|
||||
this.onPointerOver ||
|
||||
this.onPointerMove ||
|
||||
this.onPointerLeave ||
|
||||
this.onPointerDown ||
|
||||
this.onPointerUp ||
|
||||
this.onClick) {
|
||||
if (this.renderer) this.renderer.three.addIntersectObject(mesh)
|
||||
}
|
||||
|
||||
this.mesh = mesh
|
||||
this.initObject3D(mesh)
|
||||
},
|
||||
@ -95,9 +73,6 @@ const Mesh = defineComponent({
|
||||
},
|
||||
},
|
||||
unmounted() {
|
||||
if (this.mesh) {
|
||||
if (this.renderer) this.renderer.three.removeIntersectObject(this.mesh)
|
||||
}
|
||||
// for predefined mesh (geometry/material are not unmounted)
|
||||
if (this.geometry) this.geometry.dispose()
|
||||
if (this.material) this.material.dispose()
|
||||
|
Loading…
Reference in New Issue
Block a user