UNPKG

@pmndrs/handle

Version:

framework agnostic expandable handle implementation for threejs

72 lines (71 loc) 3.08 kB
import { Mesh, MeshBasicMaterial, Quaternion, TorusGeometry, Vector3 } from 'three'; import { handleXRayMaterialProperties, setupHandlesContextHoverMaterial } from '../index.js'; import { RegisteredHandle } from '../registered.js'; import { extractHandleTransformOptions } from '../utils.js'; import { createCircleGeometry } from './index.js'; const vector1Helper = new Vector3(); const vector2Helper = new Vector3(); const zAxis = new Vector3(1, 0, 0); const quaternionHelper = new Quaternion(); export class ScreenSpaceRotateHandle extends RegisteredHandle { direction = new Vector3(1, 0, 0); constructor(context, tagPrefix = '') { super(context, 'e', tagPrefix, () => ({ scale: false, translate: 'as-rotate', rotate: [this.direction], multitouch: false, })); } update(camera) { camera.getWorldPosition(vector1Helper); this.getWorldPosition(this.direction).sub(vector1Helper).normalize(); this.quaternion.setFromUnitVectors(zAxis, this.direction); const target = this.context.getTarget(); if (target?.parent != null) { target.parent.matrixWorld.decompose(vector1Helper, quaternionHelper, vector2Helper); quaternionHelper.invert(); this.quaternion.premultiply(quaternionHelper); this.direction.applyQuaternion(quaternionHelper); } if (target != null) { quaternionHelper.copy(target.quaternion).invert(); this.quaternion.premultiply(quaternionHelper); } this.direction.negate(); } bind(config) { const { options, disabled } = extractHandleTransformOptions(this.axis, config); if (options === false) { return undefined; } this.options = options; //visualization const material = new MeshBasicMaterial(handleXRayMaterialProperties); const cleanupHover = setupHandlesContextHoverMaterial(this.context, material, this.tag, { color: 0xffff00, hoverColor: 0xffff00, opacity: 0.5, disabled, }); const visualizationMesh = new Mesh(createCircleGeometry(0.75, 1), material); visualizationMesh.renderOrder = Infinity; this.add(visualizationMesh); //interaction const interactionMesh = new Mesh(new TorusGeometry(0.75, 0.1, 2, 24), new MeshBasicMaterial({ color: 'white' })); interactionMesh.visible = false; interactionMesh.rotation.y = Math.PI / 2; interactionMesh.pointerEventsOrder = Infinity; this.add(interactionMesh); const unregister = disabled ? undefined : this.context.registerHandle(this.store, interactionMesh, this.tag); return () => { material.dispose(); interactionMesh.geometry.dispose(); visualizationMesh.geometry.dispose(); unregister?.(); cleanupHover?.(); this.remove(interactionMesh); this.remove(visualizationMesh); }; } }