1
0
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:
Kevin Levron 2021-04-02 22:38:37 +02:00
parent 0a7086398f
commit acbcd0fb50
3 changed files with 106 additions and 42 deletions

40
src/core/Raycaster.js Normal file
View 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',
};

View File

@ -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);

View File

@ -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 = [];