three-stdlib
Version:
stand-alone library of threejs examples
1,047 lines (1,046 loc) • 51.5 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
class TransformControls extends THREE.Object3D {
constructor(camera, domElement) {
super();
__publicField(this, "isTransformControls", true);
__publicField(this, "visible", false);
__publicField(this, "domElement");
__publicField(this, "raycaster", new THREE.Raycaster());
__publicField(this, "gizmo");
__publicField(this, "plane");
__publicField(this, "tempVector", new THREE.Vector3());
__publicField(this, "tempVector2", new THREE.Vector3());
__publicField(this, "tempQuaternion", new THREE.Quaternion());
__publicField(this, "unit", {
X: new THREE.Vector3(1, 0, 0),
Y: new THREE.Vector3(0, 1, 0),
Z: new THREE.Vector3(0, 0, 1)
});
__publicField(this, "pointStart", new THREE.Vector3());
__publicField(this, "pointEnd", new THREE.Vector3());
__publicField(this, "offset", new THREE.Vector3());
__publicField(this, "rotationAxis", new THREE.Vector3());
__publicField(this, "startNorm", new THREE.Vector3());
__publicField(this, "endNorm", new THREE.Vector3());
__publicField(this, "rotationAngle", 0);
__publicField(this, "cameraPosition", new THREE.Vector3());
__publicField(this, "cameraQuaternion", new THREE.Quaternion());
__publicField(this, "cameraScale", new THREE.Vector3());
__publicField(this, "parentPosition", new THREE.Vector3());
__publicField(this, "parentQuaternion", new THREE.Quaternion());
__publicField(this, "parentQuaternionInv", new THREE.Quaternion());
__publicField(this, "parentScale", new THREE.Vector3());
__publicField(this, "worldPositionStart", new THREE.Vector3());
__publicField(this, "worldQuaternionStart", new THREE.Quaternion());
__publicField(this, "worldScaleStart", new THREE.Vector3());
__publicField(this, "worldPosition", new THREE.Vector3());
__publicField(this, "worldQuaternion", new THREE.Quaternion());
__publicField(this, "worldQuaternionInv", new THREE.Quaternion());
__publicField(this, "worldScale", new THREE.Vector3());
__publicField(this, "eye", new THREE.Vector3());
__publicField(this, "positionStart", new THREE.Vector3());
__publicField(this, "quaternionStart", new THREE.Quaternion());
__publicField(this, "scaleStart", new THREE.Vector3());
__publicField(this, "camera");
__publicField(this, "object");
__publicField(this, "enabled", true);
__publicField(this, "axis", null);
__publicField(this, "mode", "translate");
__publicField(this, "translationSnap", null);
__publicField(this, "rotationSnap", null);
__publicField(this, "scaleSnap", null);
__publicField(this, "space", "world");
__publicField(this, "size", 1);
__publicField(this, "dragging", false);
__publicField(this, "showX", true);
__publicField(this, "showY", true);
__publicField(this, "showZ", true);
// events
__publicField(this, "changeEvent", { type: "change" });
__publicField(this, "mouseDownEvent", { type: "mouseDown", mode: this.mode });
__publicField(this, "mouseUpEvent", { type: "mouseUp", mode: this.mode });
__publicField(this, "objectChangeEvent", { type: "objectChange" });
__publicField(this, "intersectObjectWithRay", (object, raycaster, includeInvisible) => {
const allIntersections = raycaster.intersectObject(object, true);
for (let i = 0; i < allIntersections.length; i++) {
if (allIntersections[i].object.visible || includeInvisible) {
return allIntersections[i];
}
}
return false;
});
// Set current object
__publicField(this, "attach", (object) => {
this.object = object;
this.visible = true;
return this;
});
// Detatch from object
__publicField(this, "detach", () => {
this.object = void 0;
this.visible = false;
this.axis = null;
return this;
});
// Reset
__publicField(this, "reset", () => {
if (!this.enabled)
return this;
if (this.dragging) {
if (this.object !== void 0) {
this.object.position.copy(this.positionStart);
this.object.quaternion.copy(this.quaternionStart);
this.object.scale.copy(this.scaleStart);
this.dispatchEvent(this.changeEvent);
this.dispatchEvent(this.objectChangeEvent);
this.pointStart.copy(this.pointEnd);
}
}
return this;
});
__publicField(this, "updateMatrixWorld", () => {
if (this.object !== void 0) {
this.object.updateMatrixWorld();
if (this.object.parent === null) {
console.error("TransformControls: The attached 3D object must be a part of the scene graph.");
} else {
this.object.parent.matrixWorld.decompose(this.parentPosition, this.parentQuaternion, this.parentScale);
}
this.object.matrixWorld.decompose(this.worldPosition, this.worldQuaternion, this.worldScale);
this.parentQuaternionInv.copy(this.parentQuaternion).invert();
this.worldQuaternionInv.copy(this.worldQuaternion).invert();
}
this.camera.updateMatrixWorld();
this.camera.matrixWorld.decompose(this.cameraPosition, this.cameraQuaternion, this.cameraScale);
this.eye.copy(this.cameraPosition).sub(this.worldPosition).normalize();
super.updateMatrixWorld();
});
__publicField(this, "pointerHover", (pointer) => {
if (this.object === void 0 || this.dragging === true)
return;
this.raycaster.setFromCamera(pointer, this.camera);
const intersect = this.intersectObjectWithRay(this.gizmo.picker[this.mode], this.raycaster);
if (intersect) {
this.axis = intersect.object.name;
} else {
this.axis = null;
}
});
__publicField(this, "pointerDown", (pointer) => {
if (this.object === void 0 || this.dragging === true || pointer.button !== 0)
return;
if (this.axis !== null) {
this.raycaster.setFromCamera(pointer, this.camera);
const planeIntersect = this.intersectObjectWithRay(this.plane, this.raycaster, true);
if (planeIntersect) {
let space = this.space;
if (this.mode === "scale") {
space = "local";
} else if (this.axis === "E" || this.axis === "XYZE" || this.axis === "XYZ") {
space = "world";
}
if (space === "local" && this.mode === "rotate") {
const snap = this.rotationSnap;
if (this.axis === "X" && snap)
this.object.rotation.x = Math.round(this.object.rotation.x / snap) * snap;
if (this.axis === "Y" && snap)
this.object.rotation.y = Math.round(this.object.rotation.y / snap) * snap;
if (this.axis === "Z" && snap)
this.object.rotation.z = Math.round(this.object.rotation.z / snap) * snap;
}
this.object.updateMatrixWorld();
if (this.object.parent) {
this.object.parent.updateMatrixWorld();
}
this.positionStart.copy(this.object.position);
this.quaternionStart.copy(this.object.quaternion);
this.scaleStart.copy(this.object.scale);
this.object.matrixWorld.decompose(this.worldPositionStart, this.worldQuaternionStart, this.worldScaleStart);
this.pointStart.copy(planeIntersect.point).sub(this.worldPositionStart);
}
this.dragging = true;
this.mouseDownEvent.mode = this.mode;
this.dispatchEvent(this.mouseDownEvent);
}
});
__publicField(this, "pointerMove", (pointer) => {
const axis = this.axis;
const mode = this.mode;
const object = this.object;
let space = this.space;
if (mode === "scale") {
space = "local";
} else if (axis === "E" || axis === "XYZE" || axis === "XYZ") {
space = "world";
}
if (object === void 0 || axis === null || this.dragging === false || pointer.button !== -1)
return;
this.raycaster.setFromCamera(pointer, this.camera);
const planeIntersect = this.intersectObjectWithRay(this.plane, this.raycaster, true);
if (!planeIntersect)
return;
this.pointEnd.copy(planeIntersect.point).sub(this.worldPositionStart);
if (mode === "translate") {
this.offset.copy(this.pointEnd).sub(this.pointStart);
if (space === "local" && axis !== "XYZ") {
this.offset.applyQuaternion(this.worldQuaternionInv);
}
if (axis.indexOf("X") === -1)
this.offset.x = 0;
if (axis.indexOf("Y") === -1)
this.offset.y = 0;
if (axis.indexOf("Z") === -1)
this.offset.z = 0;
if (space === "local" && axis !== "XYZ") {
this.offset.applyQuaternion(this.quaternionStart).divide(this.parentScale);
} else {
this.offset.applyQuaternion(this.parentQuaternionInv).divide(this.parentScale);
}
object.position.copy(this.offset).add(this.positionStart);
if (this.translationSnap) {
if (space === "local") {
object.position.applyQuaternion(this.tempQuaternion.copy(this.quaternionStart).invert());
if (axis.search("X") !== -1) {
object.position.x = Math.round(object.position.x / this.translationSnap) * this.translationSnap;
}
if (axis.search("Y") !== -1) {
object.position.y = Math.round(object.position.y / this.translationSnap) * this.translationSnap;
}
if (axis.search("Z") !== -1) {
object.position.z = Math.round(object.position.z / this.translationSnap) * this.translationSnap;
}
object.position.applyQuaternion(this.quaternionStart);
}
if (space === "world") {
if (object.parent) {
object.position.add(this.tempVector.setFromMatrixPosition(object.parent.matrixWorld));
}
if (axis.search("X") !== -1) {
object.position.x = Math.round(object.position.x / this.translationSnap) * this.translationSnap;
}
if (axis.search("Y") !== -1) {
object.position.y = Math.round(object.position.y / this.translationSnap) * this.translationSnap;
}
if (axis.search("Z") !== -1) {
object.position.z = Math.round(object.position.z / this.translationSnap) * this.translationSnap;
}
if (object.parent) {
object.position.sub(this.tempVector.setFromMatrixPosition(object.parent.matrixWorld));
}
}
}
} else if (mode === "scale") {
if (axis.search("XYZ") !== -1) {
let d = this.pointEnd.length() / this.pointStart.length();
if (this.pointEnd.dot(this.pointStart) < 0)
d *= -1;
this.tempVector2.set(d, d, d);
} else {
this.tempVector.copy(this.pointStart);
this.tempVector2.copy(this.pointEnd);
this.tempVector.applyQuaternion(this.worldQuaternionInv);
this.tempVector2.applyQuaternion(this.worldQuaternionInv);
this.tempVector2.divide(this.tempVector);
if (axis.search("X") === -1) {
this.tempVector2.x = 1;
}
if (axis.search("Y") === -1) {
this.tempVector2.y = 1;
}
if (axis.search("Z") === -1) {
this.tempVector2.z = 1;
}
}
object.scale.copy(this.scaleStart).multiply(this.tempVector2);
if (this.scaleSnap && this.object) {
if (axis.search("X") !== -1) {
this.object.scale.x = Math.round(object.scale.x / this.scaleSnap) * this.scaleSnap || this.scaleSnap;
}
if (axis.search("Y") !== -1) {
object.scale.y = Math.round(object.scale.y / this.scaleSnap) * this.scaleSnap || this.scaleSnap;
}
if (axis.search("Z") !== -1) {
object.scale.z = Math.round(object.scale.z / this.scaleSnap) * this.scaleSnap || this.scaleSnap;
}
}
} else if (mode === "rotate") {
this.offset.copy(this.pointEnd).sub(this.pointStart);
const ROTATION_SPEED = 20 / this.worldPosition.distanceTo(this.tempVector.setFromMatrixPosition(this.camera.matrixWorld));
if (axis === "E") {
this.rotationAxis.copy(this.eye);
this.rotationAngle = this.pointEnd.angleTo(this.pointStart);
this.startNorm.copy(this.pointStart).normalize();
this.endNorm.copy(this.pointEnd).normalize();
this.rotationAngle *= this.endNorm.cross(this.startNorm).dot(this.eye) < 0 ? 1 : -1;
} else if (axis === "XYZE") {
this.rotationAxis.copy(this.offset).cross(this.eye).normalize();
this.rotationAngle = this.offset.dot(this.tempVector.copy(this.rotationAxis).cross(this.eye)) * ROTATION_SPEED;
} else if (axis === "X" || axis === "Y" || axis === "Z") {
this.rotationAxis.copy(this.unit[axis]);
this.tempVector.copy(this.unit[axis]);
if (space === "local") {
this.tempVector.applyQuaternion(this.worldQuaternion);
}
this.rotationAngle = this.offset.dot(this.tempVector.cross(this.eye).normalize()) * ROTATION_SPEED;
}
if (this.rotationSnap) {
this.rotationAngle = Math.round(this.rotationAngle / this.rotationSnap) * this.rotationSnap;
}
if (space === "local" && axis !== "E" && axis !== "XYZE") {
object.quaternion.copy(this.quaternionStart);
object.quaternion.multiply(this.tempQuaternion.setFromAxisAngle(this.rotationAxis, this.rotationAngle)).normalize();
} else {
this.rotationAxis.applyQuaternion(this.parentQuaternionInv);
object.quaternion.copy(this.tempQuaternion.setFromAxisAngle(this.rotationAxis, this.rotationAngle));
object.quaternion.multiply(this.quaternionStart).normalize();
}
}
this.dispatchEvent(this.changeEvent);
this.dispatchEvent(this.objectChangeEvent);
});
__publicField(this, "pointerUp", (pointer) => {
if (pointer.button !== 0)
return;
if (this.dragging && this.axis !== null) {
this.mouseUpEvent.mode = this.mode;
this.dispatchEvent(this.mouseUpEvent);
}
this.dragging = false;
this.axis = null;
});
__publicField(this, "getPointer", (event) => {
var _a;
if (this.domElement && ((_a = this.domElement.ownerDocument) == null ? void 0 : _a.pointerLockElement)) {
return {
x: 0,
y: 0,
button: event.button
};
} else {
const pointer = event.changedTouches ? event.changedTouches[0] : event;
const rect = this.domElement.getBoundingClientRect();
return {
x: (pointer.clientX - rect.left) / rect.width * 2 - 1,
y: -(pointer.clientY - rect.top) / rect.height * 2 + 1,
button: event.button
};
}
});
__publicField(this, "onPointerHover", (event) => {
if (!this.enabled)
return;
switch (event.pointerType) {
case "mouse":
case "pen":
this.pointerHover(this.getPointer(event));
break;
}
});
__publicField(this, "onPointerDown", (event) => {
if (!this.enabled || !this.domElement)
return;
this.domElement.style.touchAction = "none";
this.domElement.ownerDocument.addEventListener("pointermove", this.onPointerMove);
this.pointerHover(this.getPointer(event));
this.pointerDown(this.getPointer(event));
});
__publicField(this, "onPointerMove", (event) => {
if (!this.enabled)
return;
this.pointerMove(this.getPointer(event));
});
__publicField(this, "onPointerUp", (event) => {
if (!this.enabled || !this.domElement)
return;
this.domElement.style.touchAction = "";
this.domElement.ownerDocument.removeEventListener("pointermove", this.onPointerMove);
this.pointerUp(this.getPointer(event));
});
__publicField(this, "getMode", () => this.mode);
__publicField(this, "setMode", (mode) => {
this.mode = mode;
});
__publicField(this, "setTranslationSnap", (translationSnap) => {
this.translationSnap = translationSnap;
});
__publicField(this, "setRotationSnap", (rotationSnap) => {
this.rotationSnap = rotationSnap;
});
__publicField(this, "setScaleSnap", (scaleSnap) => {
this.scaleSnap = scaleSnap;
});
__publicField(this, "setSize", (size) => {
this.size = size;
});
__publicField(this, "setSpace", (space) => {
this.space = space;
});
__publicField(this, "update", () => {
console.warn(
"THREE.TransformControls: update function has no more functionality and therefore has been deprecated."
);
});
__publicField(this, "connect", (domElement) => {
if (domElement === document) {
console.error(
'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.'
);
}
this.domElement = domElement;
this.domElement.addEventListener("pointerdown", this.onPointerDown);
this.domElement.addEventListener("pointermove", this.onPointerHover);
this.domElement.ownerDocument.addEventListener("pointerup", this.onPointerUp);
});
__publicField(this, "dispose", () => {
var _a, _b, _c, _d, _e, _f;
(_a = this.domElement) == null ? void 0 : _a.removeEventListener("pointerdown", this.onPointerDown);
(_b = this.domElement) == null ? void 0 : _b.removeEventListener("pointermove", this.onPointerHover);
(_d = (_c = this.domElement) == null ? void 0 : _c.ownerDocument) == null ? void 0 : _d.removeEventListener("pointermove", this.onPointerMove);
(_f = (_e = this.domElement) == null ? void 0 : _e.ownerDocument) == null ? void 0 : _f.removeEventListener("pointerup", this.onPointerUp);
this.traverse((child) => {
const mesh = child;
if (mesh.geometry) {
mesh.geometry.dispose();
}
if (mesh.material) {
mesh.material.dispose();
}
});
});
this.domElement = domElement;
this.camera = camera;
this.gizmo = new TransformControlsGizmo();
this.add(this.gizmo);
this.plane = new TransformControlsPlane();
this.add(this.plane);
const defineProperty = (propName, defaultValue) => {
let propValue = defaultValue;
Object.defineProperty(this, propName, {
get: function() {
return propValue !== void 0 ? propValue : defaultValue;
},
set: function(value) {
if (propValue !== value) {
propValue = value;
this.plane[propName] = value;
this.gizmo[propName] = value;
this.dispatchEvent({ type: propName + "-changed", value });
this.dispatchEvent(this.changeEvent);
}
}
});
this[propName] = defaultValue;
this.plane[propName] = defaultValue;
this.gizmo[propName] = defaultValue;
};
defineProperty("camera", this.camera);
defineProperty("object", this.object);
defineProperty("enabled", this.enabled);
defineProperty("axis", this.axis);
defineProperty("mode", this.mode);
defineProperty("translationSnap", this.translationSnap);
defineProperty("rotationSnap", this.rotationSnap);
defineProperty("scaleSnap", this.scaleSnap);
defineProperty("space", this.space);
defineProperty("size", this.size);
defineProperty("dragging", this.dragging);
defineProperty("showX", this.showX);
defineProperty("showY", this.showY);
defineProperty("showZ", this.showZ);
defineProperty("worldPosition", this.worldPosition);
defineProperty("worldPositionStart", this.worldPositionStart);
defineProperty("worldQuaternion", this.worldQuaternion);
defineProperty("worldQuaternionStart", this.worldQuaternionStart);
defineProperty("cameraPosition", this.cameraPosition);
defineProperty("cameraQuaternion", this.cameraQuaternion);
defineProperty("pointStart", this.pointStart);
defineProperty("pointEnd", this.pointEnd);
defineProperty("rotationAxis", this.rotationAxis);
defineProperty("rotationAngle", this.rotationAngle);
defineProperty("eye", this.eye);
if (domElement !== void 0)
this.connect(domElement);
}
}
class TransformControlsGizmo extends THREE.Object3D {
constructor() {
super();
__publicField(this, "isTransformControlsGizmo", true);
__publicField(this, "type", "TransformControlsGizmo");
__publicField(this, "tempVector", new THREE.Vector3(0, 0, 0));
__publicField(this, "tempEuler", new THREE.Euler());
__publicField(this, "alignVector", new THREE.Vector3(0, 1, 0));
__publicField(this, "zeroVector", new THREE.Vector3(0, 0, 0));
__publicField(this, "lookAtMatrix", new THREE.Matrix4());
__publicField(this, "tempQuaternion", new THREE.Quaternion());
__publicField(this, "tempQuaternion2", new THREE.Quaternion());
__publicField(this, "identityQuaternion", new THREE.Quaternion());
__publicField(this, "unitX", new THREE.Vector3(1, 0, 0));
__publicField(this, "unitY", new THREE.Vector3(0, 1, 0));
__publicField(this, "unitZ", new THREE.Vector3(0, 0, 1));
__publicField(this, "gizmo");
__publicField(this, "picker");
__publicField(this, "helper");
// these are set from parent class TransformControls
__publicField(this, "rotationAxis", new THREE.Vector3());
__publicField(this, "cameraPosition", new THREE.Vector3());
__publicField(this, "worldPositionStart", new THREE.Vector3());
__publicField(this, "worldQuaternionStart", new THREE.Quaternion());
__publicField(this, "worldPosition", new THREE.Vector3());
__publicField(this, "worldQuaternion", new THREE.Quaternion());
__publicField(this, "eye", new THREE.Vector3());
__publicField(this, "camera", null);
__publicField(this, "enabled", true);
__publicField(this, "axis", null);
__publicField(this, "mode", "translate");
__publicField(this, "space", "world");
__publicField(this, "size", 1);
__publicField(this, "dragging", false);
__publicField(this, "showX", true);
__publicField(this, "showY", true);
__publicField(this, "showZ", true);
// updateMatrixWorld will update transformations and appearance of individual handles
__publicField(this, "updateMatrixWorld", () => {
let space = this.space;
if (this.mode === "scale") {
space = "local";
}
const quaternion = space === "local" ? this.worldQuaternion : this.identityQuaternion;
this.gizmo["translate"].visible = this.mode === "translate";
this.gizmo["rotate"].visible = this.mode === "rotate";
this.gizmo["scale"].visible = this.mode === "scale";
this.helper["translate"].visible = this.mode === "translate";
this.helper["rotate"].visible = this.mode === "rotate";
this.helper["scale"].visible = this.mode === "scale";
let handles = [];
handles = handles.concat(this.picker[this.mode].children);
handles = handles.concat(this.gizmo[this.mode].children);
handles = handles.concat(this.helper[this.mode].children);
for (let i = 0; i < handles.length; i++) {
const handle = handles[i];
handle.visible = true;
handle.rotation.set(0, 0, 0);
handle.position.copy(this.worldPosition);
let factor;
if (this.camera.isOrthographicCamera) {
factor = (this.camera.top - this.camera.bottom) / this.camera.zoom;
} else {
factor = this.worldPosition.distanceTo(this.cameraPosition) * Math.min(1.9 * Math.tan(Math.PI * this.camera.fov / 360) / this.camera.zoom, 7);
}
handle.scale.set(1, 1, 1).multiplyScalar(factor * this.size / 7);
if (handle.tag === "helper") {
handle.visible = false;
if (handle.name === "AXIS") {
handle.position.copy(this.worldPositionStart);
handle.visible = !!this.axis;
if (this.axis === "X") {
this.tempQuaternion.setFromEuler(this.tempEuler.set(0, 0, 0));
handle.quaternion.copy(quaternion).multiply(this.tempQuaternion);
if (Math.abs(this.alignVector.copy(this.unitX).applyQuaternion(quaternion).dot(this.eye)) > 0.9) {
handle.visible = false;
}
}
if (this.axis === "Y") {
this.tempQuaternion.setFromEuler(this.tempEuler.set(0, 0, Math.PI / 2));
handle.quaternion.copy(quaternion).multiply(this.tempQuaternion);
if (Math.abs(this.alignVector.copy(this.unitY).applyQuaternion(quaternion).dot(this.eye)) > 0.9) {
handle.visible = false;
}
}
if (this.axis === "Z") {
this.tempQuaternion.setFromEuler(this.tempEuler.set(0, Math.PI / 2, 0));
handle.quaternion.copy(quaternion).multiply(this.tempQuaternion);
if (Math.abs(this.alignVector.copy(this.unitZ).applyQuaternion(quaternion).dot(this.eye)) > 0.9) {
handle.visible = false;
}
}
if (this.axis === "XYZE") {
this.tempQuaternion.setFromEuler(this.tempEuler.set(0, Math.PI / 2, 0));
this.alignVector.copy(this.rotationAxis);
handle.quaternion.setFromRotationMatrix(
this.lookAtMatrix.lookAt(this.zeroVector, this.alignVector, this.unitY)
);
handle.quaternion.multiply(this.tempQuaternion);
handle.visible = this.dragging;
}
if (this.axis === "E") {
handle.visible = false;
}
} else if (handle.name === "START") {
handle.position.copy(this.worldPositionStart);
handle.visible = this.dragging;
} else if (handle.name === "END") {
handle.position.copy(this.worldPosition);
handle.visible = this.dragging;
} else if (handle.name === "DELTA") {
handle.position.copy(this.worldPositionStart);
handle.quaternion.copy(this.worldQuaternionStart);
this.tempVector.set(1e-10, 1e-10, 1e-10).add(this.worldPositionStart).sub(this.worldPosition).multiplyScalar(-1);
this.tempVector.applyQuaternion(this.worldQuaternionStart.clone().invert());
handle.scale.copy(this.tempVector);
handle.visible = this.dragging;
} else {
handle.quaternion.copy(quaternion);
if (this.dragging) {
handle.position.copy(this.worldPositionStart);
} else {
handle.position.copy(this.worldPosition);
}
if (this.axis) {
handle.visible = this.axis.search(handle.name) !== -1;
}
}
continue;
}
handle.quaternion.copy(quaternion);
if (this.mode === "translate" || this.mode === "scale") {
const AXIS_HIDE_TRESHOLD = 0.99;
const PLANE_HIDE_TRESHOLD = 0.2;
const AXIS_FLIP_TRESHOLD = 0;
if (handle.name === "X" || handle.name === "XYZX") {
if (Math.abs(this.alignVector.copy(this.unitX).applyQuaternion(quaternion).dot(this.eye)) > AXIS_HIDE_TRESHOLD) {
handle.scale.set(1e-10, 1e-10, 1e-10);
handle.visible = false;
}
}
if (handle.name === "Y" || handle.name === "XYZY") {
if (Math.abs(this.alignVector.copy(this.unitY).applyQuaternion(quaternion).dot(this.eye)) > AXIS_HIDE_TRESHOLD) {
handle.scale.set(1e-10, 1e-10, 1e-10);
handle.visible = false;
}
}
if (handle.name === "Z" || handle.name === "XYZZ") {
if (Math.abs(this.alignVector.copy(this.unitZ).applyQuaternion(quaternion).dot(this.eye)) > AXIS_HIDE_TRESHOLD) {
handle.scale.set(1e-10, 1e-10, 1e-10);
handle.visible = false;
}
}
if (handle.name === "XY") {
if (Math.abs(this.alignVector.copy(this.unitZ).applyQuaternion(quaternion).dot(this.eye)) < PLANE_HIDE_TRESHOLD) {
handle.scale.set(1e-10, 1e-10, 1e-10);
handle.visible = false;
}
}
if (handle.name === "YZ") {
if (Math.abs(this.alignVector.copy(this.unitX).applyQuaternion(quaternion).dot(this.eye)) < PLANE_HIDE_TRESHOLD) {
handle.scale.set(1e-10, 1e-10, 1e-10);
handle.visible = false;
}
}
if (handle.name === "XZ") {
if (Math.abs(this.alignVector.copy(this.unitY).applyQuaternion(quaternion).dot(this.eye)) < PLANE_HIDE_TRESHOLD) {
handle.scale.set(1e-10, 1e-10, 1e-10);
handle.visible = false;
}
}
if (handle.name.search("X") !== -1) {
if (this.alignVector.copy(this.unitX).applyQuaternion(quaternion).dot(this.eye) < AXIS_FLIP_TRESHOLD) {
if (handle.tag === "fwd") {
handle.visible = false;
} else {
handle.scale.x *= -1;
}
} else if (handle.tag === "bwd") {
handle.visible = false;
}
}
if (handle.name.search("Y") !== -1) {
if (this.alignVector.copy(this.unitY).applyQuaternion(quaternion).dot(this.eye) < AXIS_FLIP_TRESHOLD) {
if (handle.tag === "fwd") {
handle.visible = false;
} else {
handle.scale.y *= -1;
}
} else if (handle.tag === "bwd") {
handle.visible = false;
}
}
if (handle.name.search("Z") !== -1) {
if (this.alignVector.copy(this.unitZ).applyQuaternion(quaternion).dot(this.eye) < AXIS_FLIP_TRESHOLD) {
if (handle.tag === "fwd") {
handle.visible = false;
} else {
handle.scale.z *= -1;
}
} else if (handle.tag === "bwd") {
handle.visible = false;
}
}
} else if (this.mode === "rotate") {
this.tempQuaternion2.copy(quaternion);
this.alignVector.copy(this.eye).applyQuaternion(this.tempQuaternion.copy(quaternion).invert());
if (handle.name.search("E") !== -1) {
handle.quaternion.setFromRotationMatrix(this.lookAtMatrix.lookAt(this.eye, this.zeroVector, this.unitY));
}
if (handle.name === "X") {
this.tempQuaternion.setFromAxisAngle(this.unitX, Math.atan2(-this.alignVector.y, this.alignVector.z));
this.tempQuaternion.multiplyQuaternions(this.tempQuaternion2, this.tempQuaternion);
handle.quaternion.copy(this.tempQuaternion);
}
if (handle.name === "Y") {
this.tempQuaternion.setFromAxisAngle(this.unitY, Math.atan2(this.alignVector.x, this.alignVector.z));
this.tempQuaternion.multiplyQuaternions(this.tempQuaternion2, this.tempQuaternion);
handle.quaternion.copy(this.tempQuaternion);
}
if (handle.name === "Z") {
this.tempQuaternion.setFromAxisAngle(this.unitZ, Math.atan2(this.alignVector.y, this.alignVector.x));
this.tempQuaternion.multiplyQuaternions(this.tempQuaternion2, this.tempQuaternion);
handle.quaternion.copy(this.tempQuaternion);
}
}
handle.visible = handle.visible && (handle.name.indexOf("X") === -1 || this.showX);
handle.visible = handle.visible && (handle.name.indexOf("Y") === -1 || this.showY);
handle.visible = handle.visible && (handle.name.indexOf("Z") === -1 || this.showZ);
handle.visible = handle.visible && (handle.name.indexOf("E") === -1 || this.showX && this.showY && this.showZ);
handle.material.tempOpacity = handle.material.tempOpacity || handle.material.opacity;
handle.material.tempColor = handle.material.tempColor || handle.material.color.clone();
handle.material.color.copy(handle.material.tempColor);
handle.material.opacity = handle.material.tempOpacity;
if (!this.enabled) {
handle.material.opacity *= 0.5;
handle.material.color.lerp(new THREE.Color(1, 1, 1), 0.5);
} else if (this.axis) {
if (handle.name === this.axis) {
handle.material.opacity = 1;
handle.material.color.lerp(new THREE.Color(1, 1, 1), 0.5);
} else if (this.axis.split("").some(function(a) {
return handle.name === a;
})) {
handle.material.opacity = 1;
handle.material.color.lerp(new THREE.Color(1, 1, 1), 0.5);
} else {
handle.material.opacity *= 0.25;
handle.material.color.lerp(new THREE.Color(1, 1, 1), 0.5);
}
}
}
super.updateMatrixWorld();
});
const gizmoMaterial = new THREE.MeshBasicMaterial({
depthTest: false,
depthWrite: false,
transparent: true,
side: THREE.DoubleSide,
fog: false,
toneMapped: false
});
const gizmoLineMaterial = new THREE.LineBasicMaterial({
depthTest: false,
depthWrite: false,
transparent: true,
linewidth: 1,
fog: false,
toneMapped: false
});
const matInvisible = gizmoMaterial.clone();
matInvisible.opacity = 0.15;
const matHelper = gizmoMaterial.clone();
matHelper.opacity = 0.33;
const matRed = gizmoMaterial.clone();
matRed.color.set(16711680);
const matGreen = gizmoMaterial.clone();
matGreen.color.set(65280);
const matBlue = gizmoMaterial.clone();
matBlue.color.set(255);
const matWhiteTransparent = gizmoMaterial.clone();
matWhiteTransparent.opacity = 0.25;
const matYellowTransparent = matWhiteTransparent.clone();
matYellowTransparent.color.set(16776960);
const matCyanTransparent = matWhiteTransparent.clone();
matCyanTransparent.color.set(65535);
const matMagentaTransparent = matWhiteTransparent.clone();
matMagentaTransparent.color.set(16711935);
const matYellow = gizmoMaterial.clone();
matYellow.color.set(16776960);
const matLineRed = gizmoLineMaterial.clone();
matLineRed.color.set(16711680);
const matLineGreen = gizmoLineMaterial.clone();
matLineGreen.color.set(65280);
const matLineBlue = gizmoLineMaterial.clone();
matLineBlue.color.set(255);
const matLineCyan = gizmoLineMaterial.clone();
matLineCyan.color.set(65535);
const matLineMagenta = gizmoLineMaterial.clone();
matLineMagenta.color.set(16711935);
const matLineYellow = gizmoLineMaterial.clone();
matLineYellow.color.set(16776960);
const matLineGray = gizmoLineMaterial.clone();
matLineGray.color.set(7895160);
const matLineYellowTransparent = matLineYellow.clone();
matLineYellowTransparent.opacity = 0.25;
const arrowGeometry = new THREE.CylinderGeometry(0, 0.05, 0.2, 12, 1, false);
const scaleHandleGeometry = new THREE.BoxGeometry(0.125, 0.125, 0.125);
const lineGeometry = new THREE.BufferGeometry();
lineGeometry.setAttribute("position", new THREE.Float32BufferAttribute([0, 0, 0, 1, 0, 0], 3));
const CircleGeometry = (radius, arc) => {
const geometry = new THREE.BufferGeometry();
const vertices = [];
for (let i = 0; i <= 64 * arc; ++i) {
vertices.push(0, Math.cos(i / 32 * Math.PI) * radius, Math.sin(i / 32 * Math.PI) * radius);
}
geometry.setAttribute("position", new THREE.Float32BufferAttribute(vertices, 3));
return geometry;
};
const TranslateHelperGeometry = () => {
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.Float32BufferAttribute([0, 0, 0, 1, 1, 1], 3));
return geometry;
};
const gizmoTranslate = {
X: [
[new THREE.Mesh(arrowGeometry, matRed), [1, 0, 0], [0, 0, -Math.PI / 2], null, "fwd"],
[new THREE.Mesh(arrowGeometry, matRed), [1, 0, 0], [0, 0, Math.PI / 2], null, "bwd"],
[new THREE.Line(lineGeometry, matLineRed)]
],
Y: [
[new THREE.Mesh(arrowGeometry, matGreen), [0, 1, 0], null, null, "fwd"],
[new THREE.Mesh(arrowGeometry, matGreen), [0, 1, 0], [Math.PI, 0, 0], null, "bwd"],
[new THREE.Line(lineGeometry, matLineGreen), null, [0, 0, Math.PI / 2]]
],
Z: [
[new THREE.Mesh(arrowGeometry, matBlue), [0, 0, 1], [Math.PI / 2, 0, 0], null, "fwd"],
[new THREE.Mesh(arrowGeometry, matBlue), [0, 0, 1], [-Math.PI / 2, 0, 0], null, "bwd"],
[new THREE.Line(lineGeometry, matLineBlue), null, [0, -Math.PI / 2, 0]]
],
XYZ: [[new THREE.Mesh(new THREE.OctahedronGeometry(0.1, 0), matWhiteTransparent.clone()), [0, 0, 0], [0, 0, 0]]],
XY: [
[new THREE.Mesh(new THREE.PlaneGeometry(0.295, 0.295), matYellowTransparent.clone()), [0.15, 0.15, 0]],
[new THREE.Line(lineGeometry, matLineYellow), [0.18, 0.3, 0], null, [0.125, 1, 1]],
[new THREE.Line(lineGeometry, matLineYellow), [0.3, 0.18, 0], [0, 0, Math.PI / 2], [0.125, 1, 1]]
],
YZ: [
[new THREE.Mesh(new THREE.PlaneGeometry(0.295, 0.295), matCyanTransparent.clone()), [0, 0.15, 0.15], [0, Math.PI / 2, 0]],
[new THREE.Line(lineGeometry, matLineCyan), [0, 0.18, 0.3], [0, 0, Math.PI / 2], [0.125, 1, 1]],
[new THREE.Line(lineGeometry, matLineCyan), [0, 0.3, 0.18], [0, -Math.PI / 2, 0], [0.125, 1, 1]]
],
XZ: [
[
new THREE.Mesh(new THREE.PlaneGeometry(0.295, 0.295), matMagentaTransparent.clone()),
[0.15, 0, 0.15],
[-Math.PI / 2, 0, 0]
],
[new THREE.Line(lineGeometry, matLineMagenta), [0.18, 0, 0.3], null, [0.125, 1, 1]],
[new THREE.Line(lineGeometry, matLineMagenta), [0.3, 0, 0.18], [0, -Math.PI / 2, 0], [0.125, 1, 1]]
]
};
const pickerTranslate = {
X: [[new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0, 1, 4, 1, false), matInvisible), [0.6, 0, 0], [0, 0, -Math.PI / 2]]],
Y: [[new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0, 1, 4, 1, false), matInvisible), [0, 0.6, 0]]],
Z: [[new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0, 1, 4, 1, false), matInvisible), [0, 0, 0.6], [Math.PI / 2, 0, 0]]],
XYZ: [[new THREE.Mesh(new THREE.OctahedronGeometry(0.2, 0), matInvisible)]],
XY: [[new THREE.Mesh(new THREE.PlaneGeometry(0.4, 0.4), matInvisible), [0.2, 0.2, 0]]],
YZ: [[new THREE.Mesh(new THREE.PlaneGeometry(0.4, 0.4), matInvisible), [0, 0.2, 0.2], [0, Math.PI / 2, 0]]],
XZ: [[new THREE.Mesh(new THREE.PlaneGeometry(0.4, 0.4), matInvisible), [0.2, 0, 0.2], [-Math.PI / 2, 0, 0]]]
};
const helperTranslate = {
START: [[new THREE.Mesh(new THREE.OctahedronGeometry(0.01, 2), matHelper), null, null, null, "helper"]],
END: [[new THREE.Mesh(new THREE.OctahedronGeometry(0.01, 2), matHelper), null, null, null, "helper"]],
DELTA: [[new THREE.Line(TranslateHelperGeometry(), matHelper), null, null, null, "helper"]],
X: [[new THREE.Line(lineGeometry, matHelper.clone()), [-1e3, 0, 0], null, [1e6, 1, 1], "helper"]],
Y: [[new THREE.Line(lineGeometry, matHelper.clone()), [0, -1e3, 0], [0, 0, Math.PI / 2], [1e6, 1, 1], "helper"]],
Z: [[new THREE.Line(lineGeometry, matHelper.clone()), [0, 0, -1e3], [0, -Math.PI / 2, 0], [1e6, 1, 1], "helper"]]
};
const gizmoRotate = {
X: [
[new THREE.Line(CircleGeometry(1, 0.5), matLineRed)],
[new THREE.Mesh(new THREE.OctahedronGeometry(0.04, 0), matRed), [0, 0, 0.99], null, [1, 3, 1]]
],
Y: [
[new THREE.Line(CircleGeometry(1, 0.5), matLineGreen), null, [0, 0, -Math.PI / 2]],
[new THREE.Mesh(new THREE.OctahedronGeometry(0.04, 0), matGreen), [0, 0, 0.99], null, [3, 1, 1]]
],
Z: [
[new THREE.Line(CircleGeometry(1, 0.5), matLineBlue), null, [0, Math.PI / 2, 0]],
[new THREE.Mesh(new THREE.OctahedronGeometry(0.04, 0), matBlue), [0.99, 0, 0], null, [1, 3, 1]]
],
E: [
[new THREE.Line(CircleGeometry(1.25, 1), matLineYellowTransparent), null, [0, Math.PI / 2, 0]],
[
new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0, 0.15, 4, 1, false), matLineYellowTransparent),
[1.17, 0, 0],
[0, 0, -Math.PI / 2],
[1, 1, 1e-3]
],
[
new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0, 0.15, 4, 1, false), matLineYellowTransparent),
[-1.17, 0, 0],
[0, 0, Math.PI / 2],
[1, 1, 1e-3]
],
[
new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0, 0.15, 4, 1, false), matLineYellowTransparent),
[0, -1.17, 0],
[Math.PI, 0, 0],
[1, 1, 1e-3]
],
[
new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0, 0.15, 4, 1, false), matLineYellowTransparent),
[0, 1.17, 0],
[0, 0, 0],
[1, 1, 1e-3]
]
],
XYZE: [[new THREE.Line(CircleGeometry(1, 1), matLineGray), null, [0, Math.PI / 2, 0]]]
};
const helperRotate = {
AXIS: [[new THREE.Line(lineGeometry, matHelper.clone()), [-1e3, 0, 0], null, [1e6, 1, 1], "helper"]]
};
const pickerRotate = {
X: [[new THREE.Mesh(new THREE.TorusGeometry(1, 0.1, 4, 24), matInvisible), [0, 0, 0], [0, -Math.PI / 2, -Math.PI / 2]]],
Y: [[new THREE.Mesh(new THREE.TorusGeometry(1, 0.1, 4, 24), matInvisible), [0, 0, 0], [Math.PI / 2, 0, 0]]],
Z: [[new THREE.Mesh(new THREE.TorusGeometry(1, 0.1, 4, 24), matInvisible), [0, 0, 0], [0, 0, -Math.PI / 2]]],
E: [[new THREE.Mesh(new THREE.TorusGeometry(1.25, 0.1, 2, 24), matInvisible)]],
XYZE: [[new THREE.Mesh(new THREE.SphereGeometry(0.7, 10, 8), matInvisible)]]
};
const gizmoScale = {
X: [
[new THREE.Mesh(scaleHandleGeometry, matRed), [0.8, 0, 0], [0, 0, -Math.PI / 2]],
[new THREE.Line(lineGeometry, matLineRed), null, null, [0.8, 1, 1]]
],
Y: [
[new THREE.Mesh(scaleHandleGeometry, matGreen), [0, 0.8, 0]],
[new THREE.Line(lineGeometry, matLineGreen), null, [0, 0, Math.PI / 2], [0.8, 1, 1]]
],
Z: [
[new THREE.Mesh(scaleHandleGeometry, matBlue), [0, 0, 0.8], [Math.PI / 2, 0, 0]],
[new THREE.Line(lineGeometry, matLineBlue), null, [0, -Math.PI / 2, 0], [0.8, 1, 1]]
],
XY: [
[new THREE.Mesh(scaleHandleGeometry, matYellowTransparent), [0.85, 0.85, 0], null, [2, 2, 0.2]],
[new THREE.Line(lineGeometry, matLineYellow), [0.855, 0.98, 0], null, [0.125, 1, 1]],
[new THREE.Line(lineGeometry, matLineYellow), [0.98, 0.855, 0], [0, 0, Math.PI / 2], [0.125, 1, 1]]
],
YZ: [
[new THREE.Mesh(scaleHandleGeometry, matCyanTransparent), [0, 0.85, 0.85], null, [0.2, 2, 2]],
[new THREE.Line(lineGeometry, matLineCyan), [0, 0.855, 0.98], [0, 0, Math.PI / 2], [0.125, 1, 1]],
[new THREE.Line(lineGeometry, matLineCyan), [0, 0.98, 0.855], [0, -Math.PI / 2, 0], [0.125, 1, 1]]
],
XZ: [
[new THREE.Mesh(scaleHandleGeometry, matMagentaTransparent), [0.85, 0, 0.85], null, [2, 0.2, 2]],
[new THREE.Line(lineGeometry, matLineMagenta), [0.855, 0, 0.98], null, [0.125, 1, 1]],
[new THREE.Line(lineGeometry, matLineMagenta), [0.98, 0, 0.855], [0, -Math.PI / 2, 0], [0.125, 1, 1]]
],
XYZX: [[new THREE.Mesh(new THREE.BoxGeometry(0.125, 0.125, 0.125), matWhiteTransparent.clone()), [1.1, 0, 0]]],
XYZY: [[new THREE.Mesh(new THREE.BoxGeometry(0.125, 0.125, 0.125), matWhiteTransparent.clone()), [0, 1.1, 0]]],
XYZZ: [[new THREE.Mesh(new THREE.BoxGeometry(0.125, 0.125, 0.125), matWhiteTransparent.clone()), [0, 0, 1.1]]]
};
const pickerScale = {
X: [[new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0, 0.8, 4, 1, false), matInvisible), [0.5, 0, 0], [0, 0, -Math.PI / 2]]],
Y: [[new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0, 0.8, 4, 1, false), matInvisible), [0, 0.5, 0]]],
Z: [[new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0, 0.8, 4, 1, false), matInvisible), [0, 0, 0.5], [Math.PI / 2, 0, 0]]],
XY: [[new THREE.Mesh(scaleHandleGeometry, matInvisible), [0.85, 0.85, 0], null, [3, 3, 0.2]]],
YZ: [[new THREE.Mesh(scaleHandleGeometry, matInvisible), [0, 0.85, 0.85], null, [0.2, 3, 3]]],
XZ: [[new THREE.Mesh(scaleHandleGeometry, matInvisible), [0.85, 0, 0.85], null, [3, 0.2, 3]]],
XYZX: [[new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.2, 0.2), matInvisible), [1.1, 0, 0]]],
XYZY: [[new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.2, 0.2), matInvisible), [0, 1.1, 0]]],
XYZZ: [[new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.2, 0.2), matInvisible), [0, 0, 1.1]]]
};
const helperScale = {
X: [[new THREE.Line(lineGeometry, matHelper.clone()), [-1e3, 0, 0], null, [1e6, 1, 1], "helper"]],
Y: [[new THREE.Line(lineGeometry, matHelper.clone()), [0, -1e3, 0], [0, 0, Math.PI / 2], [1e6, 1, 1], "helper"]],
Z: [[new THREE.Line(lineGeometry, matHelper.clone()), [0, 0, -1e3], [0, -Math.PI / 2, 0], [1e6, 1, 1], "helper"]]
};
const setupGizmo = (gizmoMap) => {
const gizmo = new THREE.Object3D();
for (let name in gizmoMap) {
for (let i = gizmoMap[name].length; i--; ) {
const object = gizmoMap[name][i][0].clone();
const position = gizmoMap[name][i][1];
const rotation = gizmoMap[name][i][2];
const scale = gizmoMap[name][i][3];
const tag = gizmoMap[name][i][4];
object.name = name;
object.tag = tag;
if (position) {
object.position.set(position[0], position[1], position[2]);
}
if (rotation) {
object.rotation.set(rotation[0], rotation[1], rotation[2]);
}
if (scale) {
object.scale.set(scale[0], scale[1], scale[2]);
}
object.updateMatrix();
const tempGeometry = object.geometry.clone();
tempGeometry.applyMatrix4(object.matrix);
object.geometry = tempGeometry;
object.renderOrder = Infinity;
object.position.set(0, 0, 0);
object.rotation.set(0, 0, 0);
object.scale.set(1, 1, 1);
gizmo.add(object);
}
}
return gizmo;
};
this.gizmo = {};
this.picker = {};
this.helper = {};
this.add(this.gizmo["translate"] = setupGizmo(gizmoTranslate));
this.add(this.gizmo["rotate"] = setupGizmo(gizmoRotate));
this.add(this.gizmo["scale"] = setupGizmo(gizmoScale));
this.add(this.picker["translate"] = setupGizmo(pickerTranslate));
this.add(this.picker["rotate"] = setupGizmo(pickerRotate));
this.add(this.picker["scale"] = setupGizmo(pickerScale));
this.add(this.helper["translate"] = setupGizmo(helperTranslate));
this.add(this.helper["rotate"] = setupGizmo(helperRotate));
this.add(this.helper["scale"] = setupGizmo(helperScale));
this.picker["translate"].visible = false;
this.picker["rotate"].visible = false;
this.picker["scale"].visible = false;
}
}
class TransformControlsPlane extends THREE.Mesh {
constructor() {
super(
new THREE.PlaneGeometry(1e5, 1e5, 2, 2),
new THREE.MeshBasicMaterial({
visible: false,
wireframe: true,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.1,
toneMapped: false
})
);
__publicField(this, "isTransformControlsPlane", true);
__publicField(this, "type", "TransformControlsPlane");
__publicField(this, "unitX", new THREE.Vector3(1, 0, 0));
__publicField(this, "unitY", new THREE.Vector3(0, 1, 0));
__publicField(this, "unitZ", new THREE.Vector3(0, 0, 1));
__publicField(this, "tempVector", new THREE.Vector3());
__publicField(this, "dirVector", new THREE.Vector3());
__publicField(this, "alignVector", new THREE.Vector3());
__publicField(this, "tempMatrix", new THREE.Matrix4());
__publicField(this, "identityQuaternion", new THREE.Quaternion());
// these are set from parent class TransformControls
__publicField(this, "cameraQuaternion", new THREE.Quaternion());
__publicField(this, "worldPosition", new THREE.Vector3());
__publicField(this, "worldQuaternion", new THREE.Quaternion());
__publicField(this, "eye", new THREE.Vector3());
__publicField(this, "axis", null);
__publicField(this, "mode", "translate");
__publicField(this, "space", "world");
__publicField(this, "updateMatrixWorld", () => {
let space = this.space;
this.position.copy(this.worldPosition);
if (this.mode === "scale")
space = "local";
this.unitX.set(1, 0, 0).applyQuaternion(space === "local" ? this.worldQuaternion : this.identityQuaternion);
this.unitY.set(0, 1, 0).applyQuaternion(space === "local" ? this.worldQuaternion : this.identityQuaternion);
this.unitZ.set(0, 0, 1).applyQuaternion(space === "local" ? this.worldQuaternion : this.identityQuaternion);
this.alignVector.copy(this.unitY);
switch (this.mode) {
case "translate":
case "scale":
switch (this.axis) {
case "X":
this.alignVector.copy(this.eye).cross(this.unitX);