1
0
mirror of https://github.com/troisjs/trois.git synced 2024-11-24 04:12:02 +08:00

Mesh events : mouseover, click (close #1)

This commit is contained in:
Kevin Levron 2021-02-22 00:44:29 +01:00
parent adf64ecb6f
commit 9fbe5696be
4 changed files with 120 additions and 15 deletions

View File

@ -1,17 +1,24 @@
<template>
<Renderer ref="renderer">
<Renderer ref="renderer" mouse-over click>
<Camera :position="{ z: 10 }" />
<Scene>
<PointLight :position="{ y: 50, z: 50 }" />
<Box ref="box" :size="1" :rotation="{ y: Math.PI / 4, z: Math.PI / 4 }">
<LambertMaterial />
</Box>
<Group>
<Box ref="box" @hover="boxHover" @click="boxClick" :size="1" :rotation="{ y: Math.PI / 4, z: Math.PI / 4 }">
<LambertMaterial :color="boxColor" />
</Box>
</Group>
</Scene>
</Renderer>
</template>
<script>
export default {
data() {
return {
boxColor: '#ffffff',
};
},
mounted() {
const renderer = this.$refs.renderer;
const box = this.$refs.box.mesh;
@ -19,5 +26,14 @@ export default {
box.rotation.x += 0.01;
});
},
methods: {
boxHover({ over }) {
if (over) this.boxColor = '#ff0000';
else this.boxColor = '#ffffff';
},
boxClick() {
console.log(arguments, 'click');
},
},
};
</script>

View File

@ -8,6 +8,8 @@ export default {
autoClear: { type: Boolean, default: true },
mouseMove: { type: [Boolean, String], default: false },
mouseRaycast: { type: Boolean, default: false },
mouseOver: { type: Boolean, default: false },
click: { type: Boolean, default: false },
orbitCtrl: { type: [Boolean, Object], default: false },
resize: { type: [Boolean, String], default: true },
shadow: Boolean,
@ -37,6 +39,8 @@ export default {
orbit_ctrl: this.orbitCtrl,
mouse_move: this.mouseMove,
mouse_raycast: this.mouseRaycast,
mouse_over: this.mouseOver,
click: this.click,
resize: this.resize,
width: this.width,
height: this.height,

View File

@ -21,6 +21,8 @@ export default function useThree() {
orbit_ctrl: false,
mouse_move: false,
mouse_raycast: false,
mouse_over: false,
click: false,
resize: true,
width: 0,
height: 0,
@ -44,6 +46,9 @@ export default function useThree() {
const mousePlane = new Plane(new Vector3(0, 0, 1), 0);
const raycaster = new Raycaster();
// raycast objects
const intersectObjects = [];
// returned object
const obj = {
conf,
@ -62,6 +67,7 @@ export default function useThree() {
onAfterInit,
onAfterResize, offAfterResize,
onBeforeRender, offBeforeRender,
addIntersectObject, removeIntersectObject,
};
/**
@ -103,6 +109,7 @@ export default function useThree() {
window.addEventListener('resize', onResize);
}
conf.mouse_move = conf.mouse_move || conf.mouse_over;
if (conf.mouse_move) {
if (conf.mouse_move === 'body') {
obj.mouse_move_element = document.body;
@ -113,6 +120,10 @@ export default function useThree() {
obj.mouse_move_element.addEventListener('mouseleave', onMouseleave);
}
if (conf.click) {
obj.renderer.domElement.addEventListener('click', onClick);
}
afterInitCallbacks.forEach(c => c());
return true;
@ -171,6 +182,25 @@ export default function useThree() {
obj.composer.render();
}
/**
* add intersect object
*/
function addIntersectObject(o) {
if (intersectObjects.indexOf(o) === -1) {
intersectObjects.push(o);
}
}
/**
* remove intersect object
*/
function removeIntersectObject(o) {
const i = intersectObjects.indexOf(o);
if (i !== -1) {
intersectObjects.splice(i, 1);
}
}
/**
* remove listeners
*/
@ -181,37 +211,76 @@ export default function useThree() {
obj.mouse_move_element.removeEventListener('mousemove', onMousemove);
obj.mouse_move_element.removeEventListener('mouseleave', onMouseleave);
}
obj.renderer.domElement.removeEventListener('click', onClick);
if (obj.orbitCtrl) obj.orbitCtrl.dispose();
this.renderer.dispose();
}
/**
* click listener
*/
function onClick(e) {
mouse.x = (e.clientX / size.width) * 2 - 1;
mouse.y = -(e.clientY / size.height) * 2 + 1;
raycaster.setFromCamera(mouse, obj.camera);
const objects = raycaster.intersectObjects(intersectObjects);
for (let i = 0; i < objects.length; i++) {
const o = objects[i].object;
if (o.onClick) o.onClick(e);
}
}
/**
* mousemove listener
*/
function onMousemove(e) {
mouse.x = (e.clientX / size.width) * 2 - 1;
mouse.y = -(e.clientY / size.height) * 2 + 1;
updateMouseV3();
onMousechange(e);
}
/**
* mouseleave listener
*/
function onMouseleave(e) {
mouse.x = 0;
mouse.y = 0;
updateMouseV3();
// mouse.x = 0;
// mouse.y = 0;
onMousechange(e);
}
/**
* get 3d mouse position
* mouse change
*/
function updateMouseV3() {
if (conf.mouse_raycast) {
obj.camera.getWorldDirection(mousePlane.normal);
mousePlane.normal.normalize();
function onMousechange(e) {
if (conf.mouse_over || conf.mouse_raycast) {
raycaster.setFromCamera(mouse, obj.camera);
raycaster.ray.intersectPlane(mousePlane, mouseV3);
if (conf.mouse_raycast) {
// get mouse 3d position
obj.camera.getWorldDirection(mousePlane.normal);
mousePlane.normal.normalize();
raycaster.ray.intersectPlane(mousePlane, mouseV3);
}
if (conf.mouse_over) {
const onObjects = raycaster.intersectObjects(intersectObjects);
const offObjects = [...intersectObjects];
for (let i = 0; i < onObjects.length; i++) {
const o = onObjects[i].object;
if (!o.hover && o.onHover) {
o.hover = true;
o.onHover(true);
}
offObjects.splice(offObjects.indexOf(o), 1);
}
for (let i = 0; i < offObjects.length; i++) {
const o = offObjects[i];
if (o.hover && o.onHover) {
o.hover = false;
o.onHover(false);
}
}
}
}
}

View File

@ -12,6 +12,8 @@ export default {
scale: Object,
castShadow: Boolean,
receiveShadow: Boolean,
onHover: Function,
onClick: Function,
},
// can't use setup because it will not be used in sub components
// setup() {},
@ -29,7 +31,10 @@ export default {
},
unmounted() {
// console.log('Mesh unmounted');
if (this.mesh) this.parent.remove(this.mesh);
if (this.mesh) {
this.three.removeIntersectObject(this.mesh);
this.parent.remove(this.mesh);
}
if (this.geometry) this.geometry.dispose();
if (this.material && !this.materialId) this.material.dispose();
},
@ -39,6 +44,17 @@ export default {
this.material = this.three.materials[this.materialId];
}
this.mesh = new Mesh(this.geometry, this.material);
if (this.onHover) {
this.mesh.onHover = (over) => { this.onHover({ component: this, over }); };
this.three.addIntersectObject(this.mesh);
}
if (this.onClick) {
this.mesh.onClick = (e) => { this.onClick({ component: this, event: e }); };
this.three.addIntersectObject(this.mesh);
}
this.bindProps();
this.parent.add(this.mesh);
this.$emit('ready');