UNPKG

@pmndrs/handle

Version:

framework agnostic expandable handle implementation for threejs

119 lines (118 loc) 6.29 kB
import { Matrix4, Quaternion, Vector3 } from 'three'; import { addSpaceFromTransformOptions, computeHandleTransformState, projectOntoSpace, } from './utils.js'; const vectorHelper1 = new Vector3(); const vectorHelper2 = new Vector3(); const vectorHelper3 = new Vector3(); const deltaHelper1 = new Vector3(); const deltaHelper2 = new Vector3(); const qHelper1 = new Quaternion(); const qHelper2 = new Quaternion(); const matrixHelper = new Matrix4(); const scaleHelper = new Vector3(); const space = []; export function computeTranslateAsHandleTransformState(time, pointerData, storeData, targetWorldMatrix, targetParentWorldMatrix, options) { //compute target parent world quaternion if (targetParentWorldMatrix == null) { qHelper1.identity(); } else { targetParentWorldMatrix.decompose(vectorHelper1, qHelper1, vectorHelper2); } //compute space space.length = 0; if (options.translate === 'as-scale') { addSpaceFromTransformOptions(space, qHelper1, storeData.initialTargetRotation, options.scale ?? true, 'scale'); } if (options.translate != 'as-scale') { addSpaceFromTransformOptions(space, qHelper1, storeData.initialTargetRotation, options.rotate ?? true, 'rotate'); } matrixHelper.makeTranslation(storeData.initialTargetPosition); if (storeData.initialTargetParentWorldMatrix != null) { matrixHelper.premultiply(storeData.initialTargetParentWorldMatrix); } //compute initial delta between point and target projected on space deltaHelper1.setFromMatrixPosition(matrixHelper); projectOntoSpace(options.projectRays, space, pointerData.initialPointerWorldPoint, pointerData.pointerWorldOrigin, deltaHelper1, undefined); deltaHelper1.negate().add(pointerData.initialPointerWorldPoint); //compute current delta between point and target projected on space deltaHelper2.setFromMatrixPosition(targetWorldMatrix); projectOntoSpace(options.projectRays, space, pointerData.initialPointerWorldPoint, pointerData.pointerWorldOrigin, deltaHelper2, undefined); projectOntoSpace(options.projectRays, space, pointerData.initialPointerWorldPoint, pointerData.pointerWorldOrigin, vectorHelper2.copy(pointerData.pointerWorldPoint), pointerData.pointerWorldDirection); deltaHelper2.negate().add(vectorHelper2); //compute delta rotation if (options.translate === 'as-scale') { qHelper1.copy(storeData.initialTargetQuaternion); } else { vectorHelper1.copy(deltaHelper1); if (storeData.prevTranslateAsDeltaRotation != null) { vectorHelper1.applyQuaternion(storeData.prevTranslateAsDeltaRotation); } vectorHelper1.normalize(); vectorHelper2.copy(deltaHelper2).normalize(); qHelper1.setFromUnitVectors(vectorHelper1, vectorHelper2); if (storeData.prevTranslateAsDeltaRotation == null) { storeData.prevTranslateAsDeltaRotation = new Quaternion(); } else { qHelper1.multiply(storeData.prevTranslateAsDeltaRotation); } storeData.prevTranslateAsDeltaRotation.copy(qHelper1); if (storeData.initialTargetParentWorldMatrix != null) { qHelper2.setFromRotationMatrix(storeData.initialTargetParentWorldMatrix); qHelper1.multiply(qHelper2.normalize()); qHelper1.premultiply(qHelper2.invert()); } qHelper1.multiply(storeData.initialTargetQuaternion); } //compute delta scale if (options.translate === 'as-rotate') { scaleHelper.set(1, 1, 1); } else if (typeof options.scale === 'object' && (options.scale.uniform ?? false)) { scaleHelper.setScalar(deltaHelper2.length() / deltaHelper1.length()); } else if (options.translate === 'as-rotate-and-scale') { //compute the initial world quaternion and initial world scale matrixHelper.compose(storeData.initialTargetPosition, storeData.initialTargetQuaternion, storeData.initialTargetScale); if (storeData.initialTargetParentWorldMatrix != null) { matrixHelper.premultiply(storeData.initialTargetParentWorldMatrix); } matrixHelper.decompose(vectorHelper2, qHelper2, vectorHelper3); //compute the initial scale axis vectorHelper1.copy(deltaHelper1).applyQuaternion(qHelper2.invert()).divide(vectorHelper3); vectorHelper1.x = Math.abs(vectorHelper1.x); vectorHelper1.y = Math.abs(vectorHelper1.y); vectorHelper1.z = Math.abs(vectorHelper1.z); const maxCompInitialDelta = Math.max(...vectorHelper1.toArray()); vectorHelper1.divideScalar(maxCompInitialDelta); scaleHelper.set(1, 1, 1); scaleHelper.addScaledVector(vectorHelper1, deltaHelper2.length() / deltaHelper1.length() - 1); } else { //as scale if (storeData.initialTargetParentWorldMatrix != null) { storeData.initialTargetParentWorldMatrix.decompose(vectorHelper1, qHelper2, vectorHelper2); qHelper2.multiply(storeData.initialTargetQuaternion); } else { qHelper2.copy(storeData.initialTargetQuaternion); } vectorHelper1.copy(deltaHelper1).applyQuaternion(qHelper2.invert()); if (targetParentWorldMatrix != null) { targetParentWorldMatrix.decompose(vectorHelper2, qHelper2, vectorHelper3); qHelper2.multiply(storeData.initialTargetQuaternion); } else { qHelper2.copy(storeData.initialTargetQuaternion); } vectorHelper2.copy(deltaHelper2).applyQuaternion(qHelper2.invert()); scaleHelper.x = Math.abs(vectorHelper1.x) < 0.001 ? 1 : Math.abs(vectorHelper2.x / vectorHelper1.x); scaleHelper.y = Math.abs(vectorHelper1.y) < 0.001 ? 1 : Math.abs(vectorHelper2.y / vectorHelper1.y); scaleHelper.z = Math.abs(vectorHelper1.z) < 0.001 ? 1 : Math.abs(vectorHelper2.z / vectorHelper1.z); } scaleHelper.multiply(storeData.initialTargetScale); matrixHelper.compose(storeData.initialTargetPosition, qHelper1, scaleHelper); //we pass targetParentWorldMatrix as undefined, because we calculated matrixHelper1 in local target space return computeHandleTransformState(time, 1, matrixHelper, storeData, undefined, options); }