mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
improve pointer / raycaster (#34)
This commit is contained in:
parent
0a7086398f
commit
acbcd0fb50
40
src/core/Raycaster.js
Normal file
40
src/core/Raycaster.js
Normal file
@ -0,0 +1,40 @@
|
||||
import usePointer from './usePointer';
|
||||
|
||||
export default {
|
||||
name: 'Raycaster',
|
||||
inject: ['three', 'rendererComponent'],
|
||||
props: {
|
||||
onPointerEnter: { type: Function, default: () => {} },
|
||||
onPointerOver: { type: Function, default: () => {} },
|
||||
onPointerMove: { type: Function, default: () => {} },
|
||||
onPointerLeave: { type: Function, default: () => {} },
|
||||
onPointerClick: { type: Function, default: () => {} },
|
||||
},
|
||||
mounted() {
|
||||
this.rendererComponent.onMounted(() => {
|
||||
this.pointer = usePointer({
|
||||
camera: this.three.camera,
|
||||
domElement: this.three.renderer.domElement,
|
||||
intersectObjects: this.getIntersectObjects(),
|
||||
onIntersectEnter: this.onPointerEnter,
|
||||
onIntersectOver: this.onPointerOver,
|
||||
onIntersectMove: this.onPointerMove,
|
||||
onIntersectLeave: this.onPointerLeave,
|
||||
onIntersectClick: this.onPointerClick,
|
||||
});
|
||||
this.pointer.addListeners();
|
||||
});
|
||||
},
|
||||
unmounted() {
|
||||
if (this.pointer) this.pointer.removeListeners();
|
||||
},
|
||||
methods: {
|
||||
getIntersectObjects() {
|
||||
return this.three.scene.children.filter(e => e.type === 'Mesh');
|
||||
},
|
||||
},
|
||||
render() {
|
||||
return [];
|
||||
},
|
||||
__hmrId: 'Raycaster',
|
||||
};
|
@ -8,18 +8,17 @@ export default function usePointer(options) {
|
||||
intersectObjects,
|
||||
touch = true,
|
||||
resetOnEnd = false,
|
||||
resetPosition = new Vector2(),
|
||||
resetPositionV3 = new Vector3(),
|
||||
// onEnter = () => {},
|
||||
// onLeave = () => {},
|
||||
// onMove = () => {},
|
||||
// onDown = () => {},
|
||||
// onUp = () => {},
|
||||
// onClick = () => {},
|
||||
resetPosition = new Vector2(Infinity, Infinity),
|
||||
resetPositionV3 = new Vector3(Infinity, Infinity, Infinity),
|
||||
onIntersectEnter = () => {},
|
||||
onIntersectOver = () => {},
|
||||
onIntersectMove = () => {},
|
||||
onIntersectLeave = () => {},
|
||||
onIntersectClick = () => {},
|
||||
} = options;
|
||||
|
||||
const position = resetPosition.clone();
|
||||
const positionN = new Vector2();
|
||||
const positionN = new Vector2(Infinity, Infinity);
|
||||
|
||||
const raycaster = useRaycaster({ camera });
|
||||
const positionV3 = raycaster.position;
|
||||
@ -28,9 +27,11 @@ export default function usePointer(options) {
|
||||
position,
|
||||
positionN,
|
||||
positionV3,
|
||||
intersectObjects,
|
||||
listeners: false,
|
||||
addListeners,
|
||||
removeListeners,
|
||||
intersect,
|
||||
};
|
||||
|
||||
return obj;
|
||||
@ -58,12 +59,7 @@ export default function usePointer(options) {
|
||||
raycaster.updatePosition(positionN);
|
||||
};
|
||||
|
||||
function pointerEnter(event) {
|
||||
updatePosition(event);
|
||||
// onEnter();
|
||||
};
|
||||
|
||||
function pointerChange() {
|
||||
function intersect() {
|
||||
if (intersectObjects.length) {
|
||||
const intersects = raycaster.intersect(positionN, intersectObjects);
|
||||
const offObjects = [...intersectObjects];
|
||||
@ -81,10 +77,17 @@ export default function usePointer(options) {
|
||||
|
||||
if (!object.over) {
|
||||
object.over = true;
|
||||
if (component.onPointerOver) component.onPointerOver({ over: true, component, intersect });
|
||||
if (component.onPointerEnter) component.onPointerEnter({ component, intersect });
|
||||
const overEvent = { type: 'pointerover', over: true, component, intersect };
|
||||
const enterEvent = { ...overEvent, type: 'pointerenter' };
|
||||
onIntersectOver(overEvent);
|
||||
onIntersectEnter(enterEvent);
|
||||
if (component.onPointerOver) component.onPointerOver(overEvent);
|
||||
if (component.onPointerEnter) component.onPointerEnter(enterEvent);
|
||||
}
|
||||
if (component.onPointerMove) component.onPointerMove({ component, intersect });
|
||||
|
||||
const moveEvent = { type: 'pointermove', component, intersect };
|
||||
onIntersectMove(moveEvent);
|
||||
if (component.onPointerMove) component.onPointerMove(moveEvent);
|
||||
|
||||
offObjects.splice(offObjects.indexOf(object), 1);
|
||||
});
|
||||
@ -93,34 +96,50 @@ export default function usePointer(options) {
|
||||
const { component } = object;
|
||||
if (object.over) {
|
||||
object.over = false;
|
||||
if (component.onPointerOver) component.onPointerOver({ over: false, component });
|
||||
if (component.onPointerLeave) component.onPointerLeave({ component });
|
||||
const overEvent = { type: 'pointerover', over: false, component };
|
||||
const leaveEvent = { ...overEvent, type: 'pointerleave' };
|
||||
onIntersectOver(overEvent);
|
||||
onIntersectLeave(leaveEvent);
|
||||
if (component.onPointerOver) component.onPointerOver(overEvent);
|
||||
if (component.onPointerLeave) component.onPointerLeave(leaveEvent);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function pointerEnter(event) {
|
||||
updatePosition(event);
|
||||
};
|
||||
|
||||
function pointerMove(event) {
|
||||
updatePosition(event);
|
||||
pointerChange();
|
||||
// onMove();
|
||||
intersect();
|
||||
};
|
||||
|
||||
function pointerClick(event) {
|
||||
updatePosition(event);
|
||||
if (intersectObjects.length) {
|
||||
const intersects = raycaster.intersect(positionN, intersectObjects);
|
||||
const iMeshes = [];
|
||||
intersects.forEach(intersect => {
|
||||
const { object } = intersect;
|
||||
const { component } = object;
|
||||
if (component.onClick) component.onClick({ component, intersect });
|
||||
|
||||
// only once for InstancedMesh
|
||||
if (object instanceof InstancedMesh) {
|
||||
if (iMeshes.indexOf(object) !== -1) return;
|
||||
iMeshes.push(object);
|
||||
}
|
||||
|
||||
const event = { type: 'click', component, intersect };
|
||||
onIntersectClick(event);
|
||||
if (component.onClick) component.onClick(event);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function pointerLeave(event) {
|
||||
function pointerLeave() {
|
||||
if (resetOnEnd) reset();
|
||||
// onLeave();
|
||||
};
|
||||
|
||||
function addListeners() {
|
||||
@ -140,6 +159,7 @@ export default function usePointer(options) {
|
||||
domElement.removeEventListener('mouseenter', pointerEnter);
|
||||
domElement.removeEventListener('mousemove', pointerMove);
|
||||
domElement.removeEventListener('mouseleave', pointerLeave);
|
||||
domElement.removeEventListener('click', pointerClick);
|
||||
|
||||
domElement.removeEventListener('touchstart', pointerEnter);
|
||||
domElement.removeEventListener('touchmove', pointerMove);
|
||||
|
@ -1,9 +1,5 @@
|
||||
import {
|
||||
WebGLRenderer,
|
||||
} from 'three';
|
||||
|
||||
import { WebGLRenderer } from 'three';
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
||||
|
||||
import usePointer from './usePointer';
|
||||
|
||||
/**
|
||||
@ -17,7 +13,7 @@ export default function useThree() {
|
||||
alpha: false,
|
||||
autoClear: true,
|
||||
orbit_ctrl: false,
|
||||
use_pointer: false,
|
||||
pointer: false,
|
||||
resize: false,
|
||||
width: 300,
|
||||
height: 150,
|
||||
@ -35,6 +31,8 @@ export default function useThree() {
|
||||
let afterResizeCallbacks = [];
|
||||
let beforeRenderCallbacks = [];
|
||||
|
||||
const intersectObjects = [];
|
||||
|
||||
// returned object
|
||||
const obj = {
|
||||
conf,
|
||||
@ -43,7 +41,6 @@ export default function useThree() {
|
||||
cameraCtrl: null,
|
||||
scene: null,
|
||||
pointer: null,
|
||||
intersectObjects: [],
|
||||
size,
|
||||
init,
|
||||
dispose,
|
||||
@ -103,13 +100,18 @@ export default function useThree() {
|
||||
};
|
||||
|
||||
function initPointer() {
|
||||
obj.pointer = usePointer({
|
||||
let pointerConf = {
|
||||
camera: obj.camera,
|
||||
domElement: obj.renderer.domElement,
|
||||
intersectObjects: obj.intersectObjects,
|
||||
});
|
||||
intersectObjects,
|
||||
};
|
||||
|
||||
if (conf.use_pointer || obj.intersectObjects.length) {
|
||||
if (conf.pointer && conf.pointer instanceof Object) {
|
||||
pointerConf = { ...pointerConf, ...conf.pointer };
|
||||
}
|
||||
|
||||
obj.pointer = usePointer(pointerConf);
|
||||
if (conf.pointer || intersectObjects.length) {
|
||||
obj.pointer.addListeners();
|
||||
}
|
||||
}
|
||||
@ -154,6 +156,7 @@ export default function useThree() {
|
||||
*/
|
||||
function render() {
|
||||
if (obj.orbitCtrl) obj.orbitCtrl.update();
|
||||
// if (obj.pointer) obj.pointer.intersect();
|
||||
beforeRenderCallbacks.forEach(c => c());
|
||||
obj.renderer.render(obj.scene, obj.camera);
|
||||
}
|
||||
@ -163,6 +166,7 @@ export default function useThree() {
|
||||
*/
|
||||
function renderC() {
|
||||
if (obj.orbitCtrl) obj.orbitCtrl.update();
|
||||
// if (obj.pointer) obj.pointer.intersect();
|
||||
beforeRenderCallbacks.forEach(c => c());
|
||||
obj.composer.render();
|
||||
}
|
||||
@ -171,8 +175,8 @@ export default function useThree() {
|
||||
* add intersect object
|
||||
*/
|
||||
function addIntersectObject(o) {
|
||||
if (obj.intersectObjects.indexOf(o) === -1) {
|
||||
obj.intersectObjects.push(o);
|
||||
if (intersectObjects.indexOf(o) === -1) {
|
||||
intersectObjects.push(o);
|
||||
}
|
||||
// add listeners if needed
|
||||
if (obj.pointer && !obj.pointer.listeners) {
|
||||
@ -184,18 +188,18 @@ export default function useThree() {
|
||||
* remove intersect object
|
||||
*/
|
||||
function removeIntersectObject(o) {
|
||||
const i = obj.intersectObjects.indexOf(o);
|
||||
const i = intersectObjects.indexOf(o);
|
||||
if (i !== -1) {
|
||||
obj.intersectObjects.splice(i, 1);
|
||||
intersectObjects.splice(i, 1);
|
||||
}
|
||||
// remove listeners if needed
|
||||
if (obj.pointer && !conf.use_pointer && obj.intersectObjects.length === 0) {
|
||||
if (obj.pointer && !conf.use_pointer && intersectObjects.length === 0) {
|
||||
obj.pointer.removeListeners();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove listeners
|
||||
* remove listeners and dispose
|
||||
*/
|
||||
function dispose() {
|
||||
beforeRenderCallbacks = [];
|
||||
|
Loading…
Reference in New Issue
Block a user