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,
|
intersectObjects,
|
||||||
touch = true,
|
touch = true,
|
||||||
resetOnEnd = false,
|
resetOnEnd = false,
|
||||||
resetPosition = new Vector2(),
|
resetPosition = new Vector2(Infinity, Infinity),
|
||||||
resetPositionV3 = new Vector3(),
|
resetPositionV3 = new Vector3(Infinity, Infinity, Infinity),
|
||||||
// onEnter = () => {},
|
onIntersectEnter = () => {},
|
||||||
// onLeave = () => {},
|
onIntersectOver = () => {},
|
||||||
// onMove = () => {},
|
onIntersectMove = () => {},
|
||||||
// onDown = () => {},
|
onIntersectLeave = () => {},
|
||||||
// onUp = () => {},
|
onIntersectClick = () => {},
|
||||||
// onClick = () => {},
|
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const position = resetPosition.clone();
|
const position = resetPosition.clone();
|
||||||
const positionN = new Vector2();
|
const positionN = new Vector2(Infinity, Infinity);
|
||||||
|
|
||||||
const raycaster = useRaycaster({ camera });
|
const raycaster = useRaycaster({ camera });
|
||||||
const positionV3 = raycaster.position;
|
const positionV3 = raycaster.position;
|
||||||
@ -28,9 +27,11 @@ export default function usePointer(options) {
|
|||||||
position,
|
position,
|
||||||
positionN,
|
positionN,
|
||||||
positionV3,
|
positionV3,
|
||||||
|
intersectObjects,
|
||||||
listeners: false,
|
listeners: false,
|
||||||
addListeners,
|
addListeners,
|
||||||
removeListeners,
|
removeListeners,
|
||||||
|
intersect,
|
||||||
};
|
};
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
@ -58,12 +59,7 @@ export default function usePointer(options) {
|
|||||||
raycaster.updatePosition(positionN);
|
raycaster.updatePosition(positionN);
|
||||||
};
|
};
|
||||||
|
|
||||||
function pointerEnter(event) {
|
function intersect() {
|
||||||
updatePosition(event);
|
|
||||||
// onEnter();
|
|
||||||
};
|
|
||||||
|
|
||||||
function pointerChange() {
|
|
||||||
if (intersectObjects.length) {
|
if (intersectObjects.length) {
|
||||||
const intersects = raycaster.intersect(positionN, intersectObjects);
|
const intersects = raycaster.intersect(positionN, intersectObjects);
|
||||||
const offObjects = [...intersectObjects];
|
const offObjects = [...intersectObjects];
|
||||||
@ -81,10 +77,17 @@ export default function usePointer(options) {
|
|||||||
|
|
||||||
if (!object.over) {
|
if (!object.over) {
|
||||||
object.over = true;
|
object.over = true;
|
||||||
if (component.onPointerOver) component.onPointerOver({ over: true, component, intersect });
|
const overEvent = { type: 'pointerover', over: true, component, intersect };
|
||||||
if (component.onPointerEnter) component.onPointerEnter({ 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);
|
offObjects.splice(offObjects.indexOf(object), 1);
|
||||||
});
|
});
|
||||||
@ -93,34 +96,50 @@ export default function usePointer(options) {
|
|||||||
const { component } = object;
|
const { component } = object;
|
||||||
if (object.over) {
|
if (object.over) {
|
||||||
object.over = false;
|
object.over = false;
|
||||||
if (component.onPointerOver) component.onPointerOver({ over: false, component });
|
const overEvent = { type: 'pointerover', over: false, component };
|
||||||
if (component.onPointerLeave) component.onPointerLeave({ 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) {
|
function pointerMove(event) {
|
||||||
updatePosition(event);
|
updatePosition(event);
|
||||||
pointerChange();
|
intersect();
|
||||||
// onMove();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function pointerClick(event) {
|
function pointerClick(event) {
|
||||||
updatePosition(event);
|
updatePosition(event);
|
||||||
if (intersectObjects.length) {
|
if (intersectObjects.length) {
|
||||||
const intersects = raycaster.intersect(positionN, intersectObjects);
|
const intersects = raycaster.intersect(positionN, intersectObjects);
|
||||||
|
const iMeshes = [];
|
||||||
intersects.forEach(intersect => {
|
intersects.forEach(intersect => {
|
||||||
const { object } = intersect;
|
const { object } = intersect;
|
||||||
const { component } = object;
|
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();
|
if (resetOnEnd) reset();
|
||||||
// onLeave();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function addListeners() {
|
function addListeners() {
|
||||||
@ -140,6 +159,7 @@ export default function usePointer(options) {
|
|||||||
domElement.removeEventListener('mouseenter', pointerEnter);
|
domElement.removeEventListener('mouseenter', pointerEnter);
|
||||||
domElement.removeEventListener('mousemove', pointerMove);
|
domElement.removeEventListener('mousemove', pointerMove);
|
||||||
domElement.removeEventListener('mouseleave', pointerLeave);
|
domElement.removeEventListener('mouseleave', pointerLeave);
|
||||||
|
domElement.removeEventListener('click', pointerClick);
|
||||||
|
|
||||||
domElement.removeEventListener('touchstart', pointerEnter);
|
domElement.removeEventListener('touchstart', pointerEnter);
|
||||||
domElement.removeEventListener('touchmove', pointerMove);
|
domElement.removeEventListener('touchmove', pointerMove);
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import {
|
import { WebGLRenderer } from 'three';
|
||||||
WebGLRenderer,
|
|
||||||
} from 'three';
|
|
||||||
|
|
||||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
||||||
|
|
||||||
import usePointer from './usePointer';
|
import usePointer from './usePointer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,7 +13,7 @@ export default function useThree() {
|
|||||||
alpha: false,
|
alpha: false,
|
||||||
autoClear: true,
|
autoClear: true,
|
||||||
orbit_ctrl: false,
|
orbit_ctrl: false,
|
||||||
use_pointer: false,
|
pointer: false,
|
||||||
resize: false,
|
resize: false,
|
||||||
width: 300,
|
width: 300,
|
||||||
height: 150,
|
height: 150,
|
||||||
@ -35,6 +31,8 @@ export default function useThree() {
|
|||||||
let afterResizeCallbacks = [];
|
let afterResizeCallbacks = [];
|
||||||
let beforeRenderCallbacks = [];
|
let beforeRenderCallbacks = [];
|
||||||
|
|
||||||
|
const intersectObjects = [];
|
||||||
|
|
||||||
// returned object
|
// returned object
|
||||||
const obj = {
|
const obj = {
|
||||||
conf,
|
conf,
|
||||||
@ -43,7 +41,6 @@ export default function useThree() {
|
|||||||
cameraCtrl: null,
|
cameraCtrl: null,
|
||||||
scene: null,
|
scene: null,
|
||||||
pointer: null,
|
pointer: null,
|
||||||
intersectObjects: [],
|
|
||||||
size,
|
size,
|
||||||
init,
|
init,
|
||||||
dispose,
|
dispose,
|
||||||
@ -103,13 +100,18 @@ export default function useThree() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function initPointer() {
|
function initPointer() {
|
||||||
obj.pointer = usePointer({
|
let pointerConf = {
|
||||||
camera: obj.camera,
|
camera: obj.camera,
|
||||||
domElement: obj.renderer.domElement,
|
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();
|
obj.pointer.addListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,6 +156,7 @@ export default function useThree() {
|
|||||||
*/
|
*/
|
||||||
function render() {
|
function render() {
|
||||||
if (obj.orbitCtrl) obj.orbitCtrl.update();
|
if (obj.orbitCtrl) obj.orbitCtrl.update();
|
||||||
|
// if (obj.pointer) obj.pointer.intersect();
|
||||||
beforeRenderCallbacks.forEach(c => c());
|
beforeRenderCallbacks.forEach(c => c());
|
||||||
obj.renderer.render(obj.scene, obj.camera);
|
obj.renderer.render(obj.scene, obj.camera);
|
||||||
}
|
}
|
||||||
@ -163,6 +166,7 @@ export default function useThree() {
|
|||||||
*/
|
*/
|
||||||
function renderC() {
|
function renderC() {
|
||||||
if (obj.orbitCtrl) obj.orbitCtrl.update();
|
if (obj.orbitCtrl) obj.orbitCtrl.update();
|
||||||
|
// if (obj.pointer) obj.pointer.intersect();
|
||||||
beforeRenderCallbacks.forEach(c => c());
|
beforeRenderCallbacks.forEach(c => c());
|
||||||
obj.composer.render();
|
obj.composer.render();
|
||||||
}
|
}
|
||||||
@ -171,8 +175,8 @@ export default function useThree() {
|
|||||||
* add intersect object
|
* add intersect object
|
||||||
*/
|
*/
|
||||||
function addIntersectObject(o) {
|
function addIntersectObject(o) {
|
||||||
if (obj.intersectObjects.indexOf(o) === -1) {
|
if (intersectObjects.indexOf(o) === -1) {
|
||||||
obj.intersectObjects.push(o);
|
intersectObjects.push(o);
|
||||||
}
|
}
|
||||||
// add listeners if needed
|
// add listeners if needed
|
||||||
if (obj.pointer && !obj.pointer.listeners) {
|
if (obj.pointer && !obj.pointer.listeners) {
|
||||||
@ -184,18 +188,18 @@ export default function useThree() {
|
|||||||
* remove intersect object
|
* remove intersect object
|
||||||
*/
|
*/
|
||||||
function removeIntersectObject(o) {
|
function removeIntersectObject(o) {
|
||||||
const i = obj.intersectObjects.indexOf(o);
|
const i = intersectObjects.indexOf(o);
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
obj.intersectObjects.splice(i, 1);
|
intersectObjects.splice(i, 1);
|
||||||
}
|
}
|
||||||
// remove listeners if needed
|
// 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();
|
obj.pointer.removeListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* remove listeners
|
* remove listeners and dispose
|
||||||
*/
|
*/
|
||||||
function dispose() {
|
function dispose() {
|
||||||
beforeRenderCallbacks = [];
|
beforeRenderCallbacks = [];
|
||||||
|
Loading…
Reference in New Issue
Block a user