123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import { Observable } from "../Misc/observable.js";
- import { TransformNode } from "../Meshes/transformNode.js";
- import { Mesh } from "../Meshes/mesh.js";
- import { CreateCylinder } from "../Meshes/Builders/cylinderBuilder.js";
- import { PointerDragBehavior } from "../Behaviors/Meshes/pointerDragBehavior.js";
- import { Gizmo } from "./gizmo.js";
- import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer.js";
- import { StandardMaterial } from "../Materials/standardMaterial.js";
- import { Color3 } from "../Maths/math.color.js";
- import { TmpVectors } from "../Maths/math.vector.js";
- /**
- * Single axis drag gizmo
- */
- export class AxisDragGizmo extends Gizmo {
- /** Default material used to render when gizmo is not disabled or hovered */
- get coloredMaterial() {
- return this._coloredMaterial;
- }
- /** Material used to render when gizmo is hovered with mouse*/
- get hoverMaterial() {
- return this._hoverMaterial;
- }
- /** Material used to render when gizmo is disabled. typically grey.*/
- get disableMaterial() {
- return this._disableMaterial;
- }
- /**
- * @internal
- */
- static _CreateArrow(scene, material, thickness = 1, isCollider = false) {
- const arrow = new TransformNode("arrow", scene);
- const cylinder = CreateCylinder("cylinder", {
- diameterTop: 0,
- height: 0.075,
- diameterBottom: 0.0375 * (1 + (thickness - 1) / 4),
- tessellation: 96,
- }, scene);
- const line = CreateCylinder("cylinder", {
- diameterTop: 0.005 * thickness,
- height: 0.275,
- diameterBottom: 0.005 * thickness,
- tessellation: 96,
- }, scene);
- // Position arrow pointing in its drag axis
- cylinder.parent = arrow;
- cylinder.material = material;
- cylinder.rotation.x = Math.PI / 2;
- cylinder.position.z += 0.3;
- line.parent = arrow;
- line.material = material;
- line.position.z += 0.275 / 2;
- line.rotation.x = Math.PI / 2;
- if (isCollider) {
- line.visibility = 0;
- cylinder.visibility = 0;
- }
- return arrow;
- }
- /**
- * @internal
- */
- static _CreateArrowInstance(scene, arrow) {
- const instance = new TransformNode("arrow", scene);
- for (const mesh of arrow.getChildMeshes()) {
- const childInstance = mesh.createInstance(mesh.name);
- childInstance.parent = instance;
- }
- return instance;
- }
- /**
- * Creates an AxisDragGizmo
- * @param dragAxis The axis which the gizmo will be able to drag on
- * @param color The color of the gizmo
- * @param gizmoLayer The utility layer the gizmo will be added to
- * @param parent
- * @param thickness display gizmo axis thickness
- * @param hoverColor The color of the gizmo when hovering over and dragging
- * @param disableColor The Color of the gizmo when its disabled
- */
- constructor(dragAxis, color = Color3.Gray(), gizmoLayer = UtilityLayerRenderer.DefaultUtilityLayer, parent = null, thickness = 1, hoverColor = Color3.Yellow(), disableColor = Color3.Gray()) {
- super(gizmoLayer);
- this._pointerObserver = null;
- /**
- * Drag distance in babylon units that the gizmo will snap to when dragged (Default: 0)
- */
- this.snapDistance = 0;
- /**
- * Event that fires each time the gizmo snaps to a new location.
- * * snapDistance is the change in distance
- */
- this.onSnapObservable = new Observable();
- this._isEnabled = true;
- this._parent = null;
- this._dragging = false;
- this._parent = parent;
- // Create Material
- this._coloredMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
- this._coloredMaterial.diffuseColor = color;
- this._coloredMaterial.specularColor = color.subtract(new Color3(0.1, 0.1, 0.1));
- this._hoverMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
- this._hoverMaterial.diffuseColor = hoverColor;
- this._disableMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
- this._disableMaterial.diffuseColor = disableColor;
- this._disableMaterial.alpha = 0.4;
- // Build Mesh + Collider
- const arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, this._coloredMaterial, thickness);
- const collider = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, this._coloredMaterial, thickness + 4, true);
- // Add to Root Node
- this._gizmoMesh = new Mesh("", gizmoLayer.utilityLayerScene);
- this._gizmoMesh.addChild(arrow);
- this._gizmoMesh.addChild(collider);
- this._gizmoMesh.lookAt(this._rootMesh.position.add(dragAxis));
- this._gizmoMesh.scaling.scaleInPlace(1 / 3);
- this._gizmoMesh.parent = this._rootMesh;
- let currentSnapDragDistance = 0;
- const tmpSnapEvent = { snapDistance: 0 };
- // Add drag behavior to handle events when the gizmo is dragged
- this.dragBehavior = new PointerDragBehavior({ dragAxis: dragAxis });
- this.dragBehavior.moveAttached = false;
- this.dragBehavior.updateDragPlane = false;
- this._rootMesh.addBehavior(this.dragBehavior);
- this.dragBehavior.onDragObservable.add((event) => {
- if (this.attachedNode) {
- // Keep world translation and use it to update world transform
- // if the node has parent, the local transform properties (position, rotation, scale)
- // will be recomputed in _matrixChanged function
- let matrixChanged = false;
- // Snapping logic
- if (this.snapDistance == 0) {
- this.attachedNode.getWorldMatrix().getTranslationToRef(TmpVectors.Vector3[2]);
- TmpVectors.Vector3[2].addInPlace(event.delta);
- if (this.dragBehavior.validateDrag(TmpVectors.Vector3[2])) {
- if (this.attachedNode.position) {
- // Required for nodes like lights
- this.attachedNode.position.addInPlaceFromFloats(event.delta.x, event.delta.y, event.delta.z);
- }
- // use _worldMatrix to not force a matrix update when calling GetWorldMatrix especially with Cameras
- this.attachedNode.getWorldMatrix().addTranslationFromFloats(event.delta.x, event.delta.y, event.delta.z);
- this.attachedNode.updateCache();
- matrixChanged = true;
- }
- }
- else {
- currentSnapDragDistance += event.dragDistance;
- if (Math.abs(currentSnapDragDistance) > this.snapDistance) {
- const dragSteps = Math.floor(Math.abs(currentSnapDragDistance) / this.snapDistance);
- currentSnapDragDistance = currentSnapDragDistance % this.snapDistance;
- event.delta.normalizeToRef(TmpVectors.Vector3[1]);
- TmpVectors.Vector3[1].scaleInPlace(this.snapDistance * dragSteps);
- this.attachedNode.getWorldMatrix().getTranslationToRef(TmpVectors.Vector3[2]);
- TmpVectors.Vector3[2].addInPlace(TmpVectors.Vector3[1]);
- if (this.dragBehavior.validateDrag(TmpVectors.Vector3[2])) {
- this.attachedNode.getWorldMatrix().addTranslationFromFloats(TmpVectors.Vector3[1].x, TmpVectors.Vector3[1].y, TmpVectors.Vector3[1].z);
- this.attachedNode.updateCache();
- tmpSnapEvent.snapDistance = this.snapDistance * dragSteps * Math.sign(currentSnapDragDistance);
- this.onSnapObservable.notifyObservers(tmpSnapEvent);
- matrixChanged = true;
- }
- }
- }
- if (matrixChanged) {
- this._matrixChanged();
- }
- }
- });
- this.dragBehavior.onDragStartObservable.add(() => {
- this._dragging = true;
- });
- this.dragBehavior.onDragEndObservable.add(() => {
- this._dragging = false;
- });
- const light = gizmoLayer._getSharedGizmoLight();
- light.includedOnlyMeshes = light.includedOnlyMeshes.concat(this._rootMesh.getChildMeshes(false));
- const cache = {
- gizmoMeshes: arrow.getChildMeshes(),
- colliderMeshes: collider.getChildMeshes(),
- material: this._coloredMaterial,
- hoverMaterial: this._hoverMaterial,
- disableMaterial: this._disableMaterial,
- active: false,
- dragBehavior: this.dragBehavior,
- };
- this._parent?.addToAxisCache(collider, cache);
- this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
- if (this._customMeshSet) {
- return;
- }
- this._isHovered = !!(cache.colliderMeshes.indexOf(pointerInfo?.pickInfo?.pickedMesh) != -1);
- if (!this._parent) {
- const material = this.dragBehavior.enabled ? (this._isHovered || this._dragging ? this._hoverMaterial : this._coloredMaterial) : this._disableMaterial;
- this._setGizmoMeshMaterial(cache.gizmoMeshes, material);
- }
- });
- this.dragBehavior.onEnabledObservable.add((newState) => {
- this._setGizmoMeshMaterial(cache.gizmoMeshes, newState ? cache.material : cache.disableMaterial);
- });
- }
- _attachedNodeChanged(value) {
- if (this.dragBehavior) {
- this.dragBehavior.enabled = value ? true : false;
- }
- }
- /**
- * If the gizmo is enabled
- */
- set isEnabled(value) {
- this._isEnabled = value;
- if (!value) {
- this.attachedMesh = null;
- this.attachedNode = null;
- }
- else {
- if (this._parent) {
- this.attachedMesh = this._parent.attachedMesh;
- this.attachedNode = this._parent.attachedNode;
- }
- }
- }
- get isEnabled() {
- return this._isEnabled;
- }
- /**
- * Disposes of the gizmo
- */
- dispose() {
- this.onSnapObservable.clear();
- this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
- this.dragBehavior.detach();
- if (this._gizmoMesh) {
- this._gizmoMesh.dispose();
- }
- [this._coloredMaterial, this._hoverMaterial, this._disableMaterial].forEach((matl) => {
- if (matl) {
- matl.dispose();
- }
- });
- super.dispose();
- }
- }
- //# sourceMappingURL=axisDragGizmo.js.map
|