MarkPointsOnMesh.js 2.83 KB
import { Raycaster, Mesh, Vector2, Vector3, MeshBasicMaterial, SphereGeometry } from 'three';
import { acceleratedRaycast } from 'three-mesh-bvh';

Mesh.prototype.raycast = acceleratedRaycast;

const getMousePosition = (event, container) => {
    const rect = container.getBoundingClientRect();
    const mouse = { x: 0, y: 0 };
    mouse.x = ((event.clientX - rect.left) / (rect.right - rect.left)) * 2 - 1;
    mouse.y = -((event.clientY - rect.top) / (rect.bottom - rect.top)) * 2 + 1;
    return mouse;
};

export const drawPoint = (point, color = 0x000000, radius = 0.1) => {
    const geometry = new SphereGeometry(radius, 32, 16);
    const material = new MeshBasicMaterial({ color, depthTest: false, transparent: true });
    const sphere = new Mesh(geometry, material);
    sphere.position.set(point.x, point.y, point.z);
    return sphere;
};

class MarkPointsOnMesh {
    constructor({ camera, scene, domElement }) {
        this._camera = camera;
        this._scene = scene;
        this._domElement = domElement;
        this.activeMesh = null;

        this.raycaster = new Raycaster();
        this.raycaster.firstHitOnly = true;

        this.pointName = 'markPoint';
        this.markPoint = null;
        this.markPointPosition = null;
        this.initDrawPoint();
        this.addEvents();
    }

    initDrawPoint = () => {
        const point = drawPoint(new Vector3(0, 0, 0), 0x000, 1.5);
        point.name = this.pointName;
        point.visible = false;
        this.markPoint = point;
        this._scene.add(point);
    };

    addEvents = () => {
        this._domElement.addEventListener('pointerdown', this.onPointerdown);
        // this._domElement.addEventListener('pointermove', this.onPointermove);
    };

    dispose = () => {
        this.removeEvents();
        const object = this._scene.getObjectByName(this.pointName);
        if (object) {
            this._scene.remove(object);
        }
    };

    removeEvents = () => {
        this._domElement.removeEventListener('pointerdown', this.onPointerdown);
        // this._domElement.removeEventListener('pointermove', this.onPointermove);
    };

    setActiveMesh = (mesh) => {
        this.activeMesh = mesh;
    };

    onPointerdown = (e) => {
        if (e.button !== 0) return;
        const vec2d = getMousePosition(e, this._domElement);
        const mouse = new Vector2(vec2d.x, vec2d.y);

        this._camera.near = 1;
        this.raycaster.setFromCamera(mouse, this._camera);

        const res = this.raycaster.intersectObjects([this.activeMesh]);
        if (res.length > 0) {
            if (this.markPoint) {
                this.markPoint.position.copy(res[0].point);
                this.markPointPosition = res[0].point.clone();
                this.markPoint.visible = true;
            }
        }
        this._camera.near = -10000;
    };
}

export default MarkPointsOnMesh;