mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
refactore mesh events (wip) #34
This commit is contained in:
parent
9cf540b0b7
commit
afcf13b873
@ -1,38 +1,20 @@
|
|||||||
import { Vector2 } from 'three';
|
|
||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
import { bindProp } from '../tools/index.js';
|
import { bindProp } from '../tools/index.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Object3D',
|
name: 'Object3D',
|
||||||
inject: ['three', 'scene', 'rendererComponent'],
|
inject: ['three', 'scene', 'rendererComponent'],
|
||||||
emits: ['created', 'ready', 'pointerEnter', 'pointerOver', 'pointerLeave', 'click'],
|
emits: ['created', 'ready'],
|
||||||
props: {
|
props: {
|
||||||
position: { type: Object, default: { x: 0, y: 0, z: 0 } },
|
position: { type: Object, default: { x: 0, y: 0, z: 0 } },
|
||||||
rotation: { type: Object, default: { x: 0, y: 0, z: 0 } },
|
rotation: { type: Object, default: { x: 0, y: 0, z: 0 } },
|
||||||
scale: { type: Object, default: { x: 1, y: 1, z: 1 } },
|
scale: { type: Object, default: { x: 1, y: 1, z: 1 } },
|
||||||
lookAt: { type: Object, default: null },
|
lookAt: { type: Object, default: null },
|
||||||
onPointerEnter: { type: Function, default: null },
|
|
||||||
onPointerOver: { type: Function, default: null },
|
|
||||||
onPointerLeave: { type: Function, default: null },
|
|
||||||
onClick: { type: Function, default: null },
|
|
||||||
usePointerEvents: { type: Boolean, default: false },
|
|
||||||
pointerObjects: { type: [Boolean, Array], default: null }
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
pointerOver: null
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
// can't use setup because it will not be used in sub components
|
// can't use setup because it will not be used in sub components
|
||||||
// setup() {},
|
// setup() {},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
if (this._parent) this._parent.remove(this.o3d);
|
if (this._parent) this._parent.remove(this.o3d);
|
||||||
|
|
||||||
// teardown listeners
|
|
||||||
this.three.offBeforeRender(this.pointerHandler);
|
|
||||||
if (this.three.mouse_move_element) {
|
|
||||||
this.three.mouse_move_element.removeEventListener('mouseleave', this.renderElementLeaveHandler)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initObject3D(o3d) {
|
initObject3D(o3d) {
|
||||||
@ -47,23 +29,6 @@ export default {
|
|||||||
if (this.lookAt) this.o3d.lookAt(this.lookAt.x, this.lookAt.y, this.lookAt.z);
|
if (this.lookAt) this.o3d.lookAt(this.lookAt.x, this.lookAt.y, this.lookAt.z);
|
||||||
watch(() => this.lookAt, (v) => { this.o3d.lookAt(v.x, v.y, v.z); }, { deep: true });
|
watch(() => this.lookAt, (v) => { this.o3d.lookAt(v.x, v.y, v.z); }, { deep: true });
|
||||||
|
|
||||||
if (this.usePointerEvents
|
|
||||||
|| this.onPointerEnter
|
|
||||||
|| this.onPointerOver
|
|
||||||
|| this.onPointerLeave
|
|
||||||
|| this.onClick) {
|
|
||||||
this.three.onBeforeRender(this.pointerHandler);
|
|
||||||
}
|
|
||||||
if (this.onPointerLeave) {
|
|
||||||
// we need to wait a tick so the mouse_move_element is created
|
|
||||||
// TODO: more robust fix
|
|
||||||
this.$nextTick(() => this.three.mouse_move_element.addEventListener('mouseleave', this.renderElementLeaveHandler));
|
|
||||||
}
|
|
||||||
if (this.onClick) {
|
|
||||||
window.addEventListener('click', this.clickHandler);
|
|
||||||
// TODO: touch
|
|
||||||
}
|
|
||||||
|
|
||||||
// find first viable parent
|
// find first viable parent
|
||||||
let parent = this.$parent;
|
let parent = this.$parent;
|
||||||
while (parent) {
|
while (parent) {
|
||||||
@ -79,103 +44,6 @@ export default {
|
|||||||
},
|
},
|
||||||
add(o) { this.o3d.add(o); },
|
add(o) { this.o3d.add(o); },
|
||||||
remove(o) { this.o3d.remove(o); },
|
remove(o) { this.o3d.remove(o); },
|
||||||
pointerHandler() {
|
|
||||||
this.three.raycaster.setFromCamera(this.three.mouse, this.three.camera);
|
|
||||||
|
|
||||||
// determine what we're raycasting against
|
|
||||||
let objectsToCastAgainst = this.pointerObjects;
|
|
||||||
if (objectsToCastAgainst) {
|
|
||||||
// cast against all objects in scene if prop is `true`
|
|
||||||
if (objectsToCastAgainst === true) {
|
|
||||||
objectsToCastAgainst = this.three.scene.children;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// default: just cast against this object
|
|
||||||
objectsToCastAgainst = [this.o3d];
|
|
||||||
}
|
|
||||||
|
|
||||||
// find all intersects
|
|
||||||
const intersects = this.three.raycaster.intersectObjects(objectsToCastAgainst);
|
|
||||||
// determine if the first intersect is this object
|
|
||||||
const match = intersects.length &&
|
|
||||||
intersects[0].object.uuid === this.o3d.uuid
|
|
||||||
? intersects[0]
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// if so, let's start the callback process
|
|
||||||
if (match) {
|
|
||||||
// pointer is newly over o3d
|
|
||||||
if (!this.pointerOver) {
|
|
||||||
this.pointerOver = true;
|
|
||||||
|
|
||||||
if (this.onPointerEnter) {
|
|
||||||
|
|
||||||
this.onPointerEnter({
|
|
||||||
object: this.o3d,
|
|
||||||
intersect: match
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.usePointerEvents) {
|
|
||||||
this.$emit('pointerEnter', {
|
|
||||||
object: this.o3d,
|
|
||||||
intersect: match
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// pointer is still over o3d
|
|
||||||
else if (this.onPointerOver) {
|
|
||||||
this.onPointerOver({
|
|
||||||
object: this.o3d,
|
|
||||||
intersect: match
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.usePointerEvents) {
|
|
||||||
this.$emit('pointerOver', {
|
|
||||||
object: this.o3d,
|
|
||||||
intersect: match
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// pointer is not over o3d
|
|
||||||
|
|
||||||
// pointer has just left o3d
|
|
||||||
if (this.pointerOver) {
|
|
||||||
this.pointerOver = false;
|
|
||||||
if (this.onPointerLeave) {
|
|
||||||
this.onPointerLeave({ object: this.o3d });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.usePointerEvents) {
|
|
||||||
this.$emit('pointerLeave', {
|
|
||||||
object: this.o3d
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clickHandler(evt) {
|
|
||||||
if (this.pointerOver) {
|
|
||||||
// cast a ray so we can provide hit info
|
|
||||||
this.three.raycaster.setFromCamera(this.three.mouse, this.three.camera);
|
|
||||||
const [intersect] = this.three.raycaster.intersectObjects([this.o3d]);
|
|
||||||
|
|
||||||
// callbacks and events
|
|
||||||
if (this.onClick) {
|
|
||||||
this.onClick({ object: this.o3d, intersect });
|
|
||||||
}
|
|
||||||
if (this.usePointerEvents) {
|
|
||||||
this.$emit('click', { object: this.o3d, intersect });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
renderElementLeaveHandler() {
|
|
||||||
// since the mouse is off the renderer, we'll set its values to an unreachable number
|
|
||||||
this.three.mouse.x = this.three.mouse.y = Infinity;
|
|
||||||
// then run the normal pointer handler with these updated mouse values
|
|
||||||
this.pointerHandler();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
return this.$slots.default ? this.$slots.default() : [];
|
return this.$slots.default ? this.$slots.default() : [];
|
||||||
|
@ -7,11 +7,7 @@ export default {
|
|||||||
antialias: Boolean,
|
antialias: Boolean,
|
||||||
alpha: Boolean,
|
alpha: Boolean,
|
||||||
autoClear: { type: Boolean, default: true },
|
autoClear: { type: Boolean, default: true },
|
||||||
// mouseMove: { type: [Boolean, String], default: false },
|
usePointer: { type: Boolean, default: false },
|
||||||
// mouseRaycast: { type: Boolean, default: false },
|
|
||||||
// mouseOver: { type: Boolean, default: false },
|
|
||||||
usePointer: { type: Boolean, default: true },
|
|
||||||
// click: { type: Boolean, default: false },
|
|
||||||
orbitCtrl: { type: [Boolean, Object], default: false },
|
orbitCtrl: { type: [Boolean, Object], default: false },
|
||||||
resize: { type: [Boolean, String], default: false },
|
resize: { type: [Boolean, String], default: false },
|
||||||
shadow: Boolean,
|
shadow: Boolean,
|
||||||
@ -39,11 +35,7 @@ export default {
|
|||||||
alpha: this.alpha,
|
alpha: this.alpha,
|
||||||
autoClear: this.autoClear,
|
autoClear: this.autoClear,
|
||||||
orbit_ctrl: this.orbitCtrl,
|
orbit_ctrl: this.orbitCtrl,
|
||||||
// mouse_move: this.mouseMove,
|
|
||||||
// mouse_raycast: this.mouseRaycast,
|
|
||||||
// mouse_over: this.mouseOver,
|
|
||||||
use_pointer: this.usePointer,
|
use_pointer: this.usePointer,
|
||||||
// click: this.click,
|
|
||||||
resize: this.resize,
|
resize: this.resize,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
|
139
src/core/usePointer.js
Normal file
139
src/core/usePointer.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import { Vector2, Vector3 } from 'three';
|
||||||
|
import useRaycaster from './useRaycaster';
|
||||||
|
|
||||||
|
export default function usePointer(options) {
|
||||||
|
const {
|
||||||
|
camera,
|
||||||
|
domElement,
|
||||||
|
intersectObjects,
|
||||||
|
touch = true,
|
||||||
|
resetOnEnd = false,
|
||||||
|
resetPosition = new Vector2(),
|
||||||
|
resetPositionV3 = new Vector3(),
|
||||||
|
// onEnter = () => {},
|
||||||
|
// onLeave = () => {},
|
||||||
|
// onMove = () => {},
|
||||||
|
// onDown = () => {},
|
||||||
|
// onUp = () => {},
|
||||||
|
// onClick = () => {},
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const position = resetPosition.clone();
|
||||||
|
const positionN = new Vector2();
|
||||||
|
|
||||||
|
const raycaster = useRaycaster({ camera });
|
||||||
|
const positionV3 = raycaster.position;
|
||||||
|
|
||||||
|
const obj = {
|
||||||
|
position,
|
||||||
|
positionN,
|
||||||
|
positionV3,
|
||||||
|
listeners: false,
|
||||||
|
addListeners,
|
||||||
|
removeListeners,
|
||||||
|
};
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
position.copy(resetPosition);
|
||||||
|
positionV3.copy(resetPositionV3);
|
||||||
|
};
|
||||||
|
|
||||||
|
function updatePosition(event) {
|
||||||
|
let x, y;
|
||||||
|
if (event.touches && event.touches.length > 0) {
|
||||||
|
x = event.touches[0].clientX;
|
||||||
|
y = event.touches[0].clientY;
|
||||||
|
} else {
|
||||||
|
x = event.clientX;
|
||||||
|
y = event.clientY;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = domElement.getBoundingClientRect();
|
||||||
|
position.x = x - rect.left;
|
||||||
|
position.y = y - rect.top;
|
||||||
|
positionN.x = (position.x / rect.width) * 2 - 1;
|
||||||
|
positionN.y = (position.y / rect.height) * 2 - 1;
|
||||||
|
raycaster.updatePosition(positionN);
|
||||||
|
};
|
||||||
|
|
||||||
|
function pointerEnter(event) {
|
||||||
|
updatePosition(event);
|
||||||
|
// onEnter();
|
||||||
|
};
|
||||||
|
|
||||||
|
function pointerChange() {
|
||||||
|
if (intersectObjects.length) {
|
||||||
|
const intersects = raycaster.intersect(positionN, intersectObjects);
|
||||||
|
const offObjects = [...intersectObjects];
|
||||||
|
|
||||||
|
intersects.forEach(intersect => {
|
||||||
|
const { object } = intersect;
|
||||||
|
const { component } = object;
|
||||||
|
if (!object.over) {
|
||||||
|
object.over = true;
|
||||||
|
if (component.onPointerOver) component.onPointerOver({ over: true, component, intersect });
|
||||||
|
if (component.onPointerEnter) component.onPointerEnter({ component, intersect });
|
||||||
|
}
|
||||||
|
offObjects.splice(offObjects.indexOf(object), 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
offObjects.forEach(object => {
|
||||||
|
const { component } = object;
|
||||||
|
if (object.over && component.onPointerOver) {
|
||||||
|
object.over = false;
|
||||||
|
if (component.onPointerOver) component.onPointerOver({ over: false, component });
|
||||||
|
if (component.onPointerLeave) component.onPointerLeave({ component });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function pointerMove(event) {
|
||||||
|
updatePosition(event);
|
||||||
|
pointerChange();
|
||||||
|
// onMove();
|
||||||
|
};
|
||||||
|
|
||||||
|
function pointerClick(event) {
|
||||||
|
updatePosition(event);
|
||||||
|
if (intersectObjects.length) {
|
||||||
|
const intersects = raycaster.intersect(positionN, intersectObjects);
|
||||||
|
intersects.forEach(intersect => {
|
||||||
|
const { object } = intersect;
|
||||||
|
const { component } = object;
|
||||||
|
if (component.onClick) component.onClick({ component, intersect });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function pointerLeave(event) {
|
||||||
|
if (resetOnEnd) reset();
|
||||||
|
// onLeave();
|
||||||
|
};
|
||||||
|
|
||||||
|
function addListeners() {
|
||||||
|
domElement.addEventListener('mouseenter', pointerEnter);
|
||||||
|
domElement.addEventListener('mousemove', pointerMove);
|
||||||
|
domElement.addEventListener('mouseleave', pointerLeave);
|
||||||
|
domElement.addEventListener('click', pointerClick);
|
||||||
|
if (touch) {
|
||||||
|
domElement.addEventListener('touchstart', pointerEnter);
|
||||||
|
domElement.addEventListener('touchmove', pointerMove);
|
||||||
|
domElement.addEventListener('touchend', pointerLeave);
|
||||||
|
}
|
||||||
|
obj.listeners = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
function removeListeners() {
|
||||||
|
domElement.removeEventListener('mouseenter', pointerEnter);
|
||||||
|
domElement.removeEventListener('mousemove', pointerMove);
|
||||||
|
domElement.removeEventListener('mouseleave', pointerLeave);
|
||||||
|
|
||||||
|
domElement.removeEventListener('touchstart', pointerEnter);
|
||||||
|
domElement.removeEventListener('touchmove', pointerMove);
|
||||||
|
domElement.removeEventListener('touchend', pointerLeave);
|
||||||
|
obj.listeners = false;
|
||||||
|
};
|
||||||
|
};
|
29
src/core/useRaycaster.js
Normal file
29
src/core/useRaycaster.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Plane, Raycaster, Vector3 } from 'three';
|
||||||
|
|
||||||
|
export default function useRaycaster(options) {
|
||||||
|
const {
|
||||||
|
camera,
|
||||||
|
resetPosition = new Vector3(0, 0, 0),
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const raycaster = new Raycaster();
|
||||||
|
const position = resetPosition.clone();
|
||||||
|
const plane = new Plane(new Vector3(0, 0, 1), 0);
|
||||||
|
|
||||||
|
const updatePosition = (coords) => {
|
||||||
|
raycaster.setFromCamera(coords, camera);
|
||||||
|
camera.getWorldDirection(plane.normal);
|
||||||
|
raycaster.ray.intersectPlane(plane, position);
|
||||||
|
};
|
||||||
|
|
||||||
|
const intersect = (coords, objects) => {
|
||||||
|
raycaster.setFromCamera(coords, camera);
|
||||||
|
return raycaster.intersectObjects(objects);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
position,
|
||||||
|
updatePosition,
|
||||||
|
intersect,
|
||||||
|
};
|
||||||
|
};
|
@ -1,13 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
Plane,
|
|
||||||
Raycaster,
|
|
||||||
Vector2,
|
|
||||||
Vector3,
|
|
||||||
WebGLRenderer,
|
WebGLRenderer,
|
||||||
} from 'three';
|
} from 'three';
|
||||||
|
|
||||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
||||||
|
|
||||||
|
import usePointer from './usePointer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Three.js helper
|
* Three.js helper
|
||||||
*/
|
*/
|
||||||
@ -19,14 +17,10 @@ export default function useThree() {
|
|||||||
alpha: false,
|
alpha: false,
|
||||||
autoClear: true,
|
autoClear: true,
|
||||||
orbit_ctrl: false,
|
orbit_ctrl: false,
|
||||||
// mouse_move: false,
|
use_pointer: false,
|
||||||
// mouse_raycast: false,
|
resize: false,
|
||||||
// mouse_over: false,
|
width: 300,
|
||||||
use_pointer: true,
|
height: 150,
|
||||||
// click: false,
|
|
||||||
resize: true,
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// size
|
// size
|
||||||
@ -41,26 +35,16 @@ export default function useThree() {
|
|||||||
let afterResizeCallbacks = [];
|
let afterResizeCallbacks = [];
|
||||||
let beforeRenderCallbacks = [];
|
let beforeRenderCallbacks = [];
|
||||||
|
|
||||||
// mouse tracking
|
|
||||||
const mouse = new Vector2(Infinity, Infinity);
|
|
||||||
const mouseV3 = new Vector3();
|
|
||||||
const mousePlane = new Plane(new Vector3(0, 0, 1), 0);
|
|
||||||
const raycaster = new Raycaster();
|
|
||||||
|
|
||||||
// raycast objects
|
|
||||||
const intersectObjects = [];
|
|
||||||
|
|
||||||
// returned object
|
// returned object
|
||||||
const obj = {
|
const obj = {
|
||||||
conf,
|
conf,
|
||||||
renderer: null,
|
renderer: null,
|
||||||
camera: null,
|
camera: null,
|
||||||
cameraCtrl: null,
|
cameraCtrl: null,
|
||||||
materials: {},
|
|
||||||
scene: null,
|
scene: null,
|
||||||
|
pointer: null,
|
||||||
|
intersectObjects: [],
|
||||||
size,
|
size,
|
||||||
mouse, mouseV3,
|
|
||||||
raycaster,
|
|
||||||
init,
|
init,
|
||||||
dispose,
|
dispose,
|
||||||
render,
|
render,
|
||||||
@ -95,6 +79,15 @@ export default function useThree() {
|
|||||||
obj.renderer = new WebGLRenderer({ canvas: conf.canvas, antialias: conf.antialias, alpha: conf.alpha });
|
obj.renderer = new WebGLRenderer({ canvas: conf.canvas, antialias: conf.antialias, alpha: conf.alpha });
|
||||||
obj.renderer.autoClear = conf.autoClear;
|
obj.renderer.autoClear = conf.autoClear;
|
||||||
|
|
||||||
|
if (conf.resize) {
|
||||||
|
onResize();
|
||||||
|
window.addEventListener('resize', onResize);
|
||||||
|
} else {
|
||||||
|
setSize(conf.width, conf.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
initPointer();
|
||||||
|
|
||||||
if (conf.orbit_ctrl) {
|
if (conf.orbit_ctrl) {
|
||||||
obj.orbitCtrl = new OrbitControls(obj.camera, obj.renderer.domElement);
|
obj.orbitCtrl = new OrbitControls(obj.camera, obj.renderer.domElement);
|
||||||
if (conf.orbit_ctrl instanceof Object) {
|
if (conf.orbit_ctrl instanceof Object) {
|
||||||
@ -104,36 +97,23 @@ export default function useThree() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf.resize) {
|
|
||||||
onResize();
|
|
||||||
window.addEventListener('resize', onResize);
|
|
||||||
} else {
|
|
||||||
setSize(conf.width | 300, conf.height | 150);
|
|
||||||
}
|
|
||||||
|
|
||||||
// conf.mouse_move = conf.mouse_move || conf.mouse_over;
|
|
||||||
if (conf.use_pointer) {
|
|
||||||
if (conf.use_pointer === true) {
|
|
||||||
// use renderer element as mousemove by default
|
|
||||||
obj.mouse_move_element = obj.renderer.domElement;
|
|
||||||
} else {
|
|
||||||
// use custom element as mousemove element
|
|
||||||
obj.mouse_move_element = conf.use_pointer;
|
|
||||||
}
|
|
||||||
obj.mouse_move_element.addEventListener('mousemove', onMousemove);
|
|
||||||
obj.mouse_move_element.addEventListener('mouseleave', onMouseleave);
|
|
||||||
// TODO: touch
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (conf.click) {
|
|
||||||
// obj.renderer.domElement.addEventListener('click', onClick);
|
|
||||||
// }
|
|
||||||
|
|
||||||
afterInitCallbacks.forEach(c => c());
|
afterInitCallbacks.forEach(c => c());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function initPointer() {
|
||||||
|
obj.pointer = usePointer({
|
||||||
|
camera: obj.camera,
|
||||||
|
domElement: obj.renderer.domElement,
|
||||||
|
intersectObjects: obj.intersectObjects,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (conf.use_pointer || obj.intersectObjects.length) {
|
||||||
|
obj.pointer.addListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add after init callback
|
* add after init callback
|
||||||
*/
|
*/
|
||||||
@ -191,8 +171,12 @@ export default function useThree() {
|
|||||||
* add intersect object
|
* add intersect object
|
||||||
*/
|
*/
|
||||||
function addIntersectObject(o) {
|
function addIntersectObject(o) {
|
||||||
if (intersectObjects.indexOf(o) === -1) {
|
if (obj.intersectObjects.indexOf(o) === -1) {
|
||||||
intersectObjects.push(o);
|
obj.intersectObjects.push(o);
|
||||||
|
}
|
||||||
|
// add listeners if needed
|
||||||
|
if (obj.pointer && !obj.pointer.listeners) {
|
||||||
|
obj.pointer.addListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,9 +184,13 @@ export default function useThree() {
|
|||||||
* remove intersect object
|
* remove intersect object
|
||||||
*/
|
*/
|
||||||
function removeIntersectObject(o) {
|
function removeIntersectObject(o) {
|
||||||
const i = intersectObjects.indexOf(o);
|
const i = obj.intersectObjects.indexOf(o);
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
intersectObjects.splice(i, 1);
|
obj.intersectObjects.splice(i, 1);
|
||||||
|
}
|
||||||
|
// remove listeners if needed
|
||||||
|
if (obj.pointer && !conf.use_pointer && obj.intersectObjects.length === 0) {
|
||||||
|
obj.pointer.removeListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,50 +200,9 @@ export default function useThree() {
|
|||||||
function dispose() {
|
function dispose() {
|
||||||
beforeRenderCallbacks = [];
|
beforeRenderCallbacks = [];
|
||||||
window.removeEventListener('resize', onResize);
|
window.removeEventListener('resize', onResize);
|
||||||
if (obj.mouse_move_element) {
|
if (obj.pointer) obj.pointer.removeListeners();
|
||||||
obj.mouse_move_element.removeEventListener('mousemove', onMousemove);
|
|
||||||
obj.mouse_move_element.removeEventListener('mouseleave', onMouseleave);
|
|
||||||
}
|
|
||||||
// obj.renderer.domElement.removeEventListener('click', onClick);
|
|
||||||
// TODO: touch
|
|
||||||
if (obj.orbitCtrl) obj.orbitCtrl.dispose();
|
if (obj.orbitCtrl) obj.orbitCtrl.dispose();
|
||||||
this.renderer.dispose();
|
obj.renderer.dispose();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function updateMouse(e) {
|
|
||||||
const rect = obj.mouse_move_element.getBoundingClientRect();
|
|
||||||
mouse.x = ((e.x - rect.left) / size.width) * 2 - 1;
|
|
||||||
mouse.y = -((e.y - rect.top) / size.height) * 2 + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* click listener
|
|
||||||
*/
|
|
||||||
// function onClick(e) {
|
|
||||||
// updateMouse(e);
|
|
||||||
// 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) {
|
|
||||||
updateMouse(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mouseleave listener
|
|
||||||
*/
|
|
||||||
function onMouseleave(e) {
|
|
||||||
mouse.x = Infinity;
|
|
||||||
mouse.y = Infinity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
import { Mesh } from 'three';
|
import { Mesh } from 'three';
|
||||||
import Object3D from '../core/Object3D.js';
|
import Object3D from '../core/Object3D.js';
|
||||||
|
import { bindProp } from '../tools';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
extends: Object3D,
|
|
||||||
name: 'Mesh',
|
name: 'Mesh',
|
||||||
|
extends: Object3D,
|
||||||
props: {
|
props: {
|
||||||
castShadow: Boolean,
|
castShadow: Boolean,
|
||||||
receiveShadow: Boolean,
|
receiveShadow: Boolean,
|
||||||
onHover: Function,
|
onPointerEnter: Function,
|
||||||
|
onPointerOver: Function,
|
||||||
|
onPointerLeave: Function,
|
||||||
|
onPointerDown: Function,
|
||||||
|
onPointerUp: Function,
|
||||||
onClick: Function,
|
onClick: Function,
|
||||||
},
|
},
|
||||||
// can't use setup because it will not be used in sub components
|
// can't use setup because it will not be used in sub components
|
||||||
@ -24,19 +29,17 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
initMesh() {
|
initMesh() {
|
||||||
this.mesh = new Mesh(this.geometry, this.material);
|
this.mesh = new Mesh(this.geometry, this.material);
|
||||||
|
this.mesh.component = this;
|
||||||
|
|
||||||
['castShadow', 'receiveShadow'].forEach(p => {
|
bindProp(this, 'castShadow', this.mesh);
|
||||||
this.mesh[p] = this[p];
|
bindProp(this, 'receiveShadow', this.mesh);
|
||||||
watch(() => this[p], () => { this.mesh[p] = this[p]; });
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.onHover) {
|
if (this.onPointerEnter ||
|
||||||
this.mesh.onHover = (over) => { this.onHover({ component: this, over }); };
|
this.onPointerOver ||
|
||||||
this.three.addIntersectObject(this.mesh);
|
this.onPointerLeave ||
|
||||||
}
|
this.onPointerDown ||
|
||||||
|
this.onPointerUp ||
|
||||||
if (this.onClick) {
|
this.onClick) {
|
||||||
this.mesh.onClick = (e) => { this.onClick({ component: this, event: e }); };
|
|
||||||
this.three.addIntersectObject(this.mesh);
|
this.three.addIntersectObject(this.mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user