planeDragGizmo.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import { Observer, Observable } from "../Misc/observable";
  2. import { Nullable } from "../types";
  3. import { PointerInfo } from "../Events/pointerEvents";
  4. import { Vector3, Matrix } from "../Maths/math.vector";
  5. import { Color3 } from '../Maths/math.color';
  6. import { TransformNode } from "../Meshes/transformNode";
  7. import { AbstractMesh } from "../Meshes/abstractMesh";
  8. import { Mesh } from "../Meshes/mesh";
  9. import { PlaneBuilder } from "../Meshes/Builders/planeBuilder";
  10. import { PointerDragBehavior } from "../Behaviors/Meshes/pointerDragBehavior";
  11. import { Gizmo } from "./gizmo";
  12. import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
  13. import { StandardMaterial } from "../Materials/standardMaterial";
  14. import { Scene } from "../scene";
  15. import { PositionGizmo } from "./positionGizmo";
  16. /**
  17. * Single plane drag gizmo
  18. */
  19. export class PlaneDragGizmo extends Gizmo {
  20. /**
  21. * Drag behavior responsible for the gizmos dragging interactions
  22. */
  23. public dragBehavior: PointerDragBehavior;
  24. private _pointerObserver: Nullable<Observer<PointerInfo>> = null;
  25. /**
  26. * Drag distance in babylon units that the gizmo will snap to when dragged (Default: 0)
  27. */
  28. public snapDistance = 0;
  29. /**
  30. * Event that fires each time the gizmo snaps to a new location.
  31. * * snapDistance is the the change in distance
  32. */
  33. public onSnapObservable = new Observable<{ snapDistance: number }>();
  34. private _plane: TransformNode;
  35. private _coloredMaterial: StandardMaterial;
  36. private _hoverMaterial: StandardMaterial;
  37. private _isEnabled: boolean = false;
  38. private _parent: Nullable<PositionGizmo> = null;
  39. /** @hidden */
  40. public static _CreatePlane(scene: Scene, material: StandardMaterial): TransformNode {
  41. var plane = new TransformNode("plane", scene);
  42. //make sure plane is double sided
  43. var dragPlane = PlaneBuilder.CreatePlane("dragPlane", { width: .1375, height: .1375, sideOrientation: 2 }, scene);
  44. dragPlane.material = material;
  45. dragPlane.parent = plane;
  46. // Position plane pointing normal to dragPlane normal
  47. dragPlane.material = material;
  48. return plane;
  49. }
  50. /** @hidden */
  51. public static _CreateArrowInstance(scene: Scene, arrow: TransformNode): TransformNode {
  52. const instance = new TransformNode("arrow", scene);
  53. for (const mesh of arrow.getChildMeshes()) {
  54. const childInstance = (mesh as Mesh).createInstance(mesh.name);
  55. childInstance.parent = instance;
  56. }
  57. return instance;
  58. }
  59. /**
  60. * Creates a PlaneDragGizmo
  61. * @param gizmoLayer The utility layer the gizmo will be added to
  62. * @param dragPlaneNormal The axis normal to which the gizmo will be able to drag on
  63. * @param color The color of the gizmo
  64. */
  65. constructor(dragPlaneNormal: Vector3, color: Color3 = Color3.Gray(), gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, parent: Nullable<PositionGizmo> = null) {
  66. super(gizmoLayer);
  67. this._parent = parent;
  68. // Create Material
  69. this._coloredMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
  70. this._coloredMaterial.diffuseColor = color;
  71. this._coloredMaterial.specularColor = color.subtract(new Color3(0.1, 0.1, 0.1));
  72. this._hoverMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
  73. this._hoverMaterial.diffuseColor = color.add(new Color3(0.3, 0.3, 0.3));
  74. // Build plane mesh on root node
  75. this._plane = PlaneDragGizmo._CreatePlane(gizmoLayer.utilityLayerScene, this._coloredMaterial);
  76. this._plane.lookAt(this._rootMesh.position.add(dragPlaneNormal));
  77. this._plane.scaling.scaleInPlace(1 / 3);
  78. this._plane.parent = this._rootMesh;
  79. var currentSnapDragDistance = 0;
  80. var tmpVector = new Vector3();
  81. var tmpSnapEvent = { snapDistance: 0 };
  82. // Add dragPlaneNormal drag behavior to handle events when the gizmo is dragged
  83. this.dragBehavior = new PointerDragBehavior({ dragPlaneNormal: dragPlaneNormal });
  84. this.dragBehavior.moveAttached = false;
  85. this._rootMesh.addBehavior(this.dragBehavior);
  86. var localDelta = new Vector3();
  87. var tmpMatrix = new Matrix();
  88. this.dragBehavior.onDragObservable.add((event) => {
  89. if (this.attachedMesh) {
  90. // Convert delta to local translation if it has a parent
  91. if (this.attachedMesh.parent) {
  92. this.attachedMesh.parent.computeWorldMatrix().invertToRef(tmpMatrix);
  93. tmpMatrix.setTranslationFromFloats(0, 0, 0);
  94. Vector3.TransformCoordinatesToRef(event.delta, tmpMatrix, localDelta);
  95. } else {
  96. localDelta.copyFrom(event.delta);
  97. }
  98. // Snapping logic
  99. if (this.snapDistance == 0) {
  100. this.attachedMesh.position.addInPlace(localDelta);
  101. } else {
  102. currentSnapDragDistance += event.dragDistance;
  103. if (Math.abs(currentSnapDragDistance) > this.snapDistance) {
  104. var dragSteps = Math.floor(Math.abs(currentSnapDragDistance) / this.snapDistance);
  105. currentSnapDragDistance = currentSnapDragDistance % this.snapDistance;
  106. localDelta.normalizeToRef(tmpVector);
  107. tmpVector.scaleInPlace(this.snapDistance * dragSteps);
  108. this.attachedMesh.position.addInPlace(tmpVector);
  109. tmpSnapEvent.snapDistance = this.snapDistance * dragSteps;
  110. this.onSnapObservable.notifyObservers(tmpSnapEvent);
  111. }
  112. }
  113. }
  114. });
  115. this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
  116. if (this._customMeshSet) {
  117. return;
  118. }
  119. var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
  120. var material = isHovered ? this._hoverMaterial : this._coloredMaterial;
  121. this._rootMesh.getChildMeshes().forEach((m) => {
  122. m.material = material;
  123. });
  124. });
  125. var light = gizmoLayer._getSharedGizmoLight();
  126. light.includedOnlyMeshes = light.includedOnlyMeshes.concat(this._rootMesh.getChildMeshes(false));
  127. }
  128. protected _attachedMeshChanged(value: Nullable<AbstractMesh>) {
  129. if (this.dragBehavior) {
  130. this.dragBehavior.enabled = value ? true : false;
  131. }
  132. }
  133. /**
  134. * If the gizmo is enabled
  135. */
  136. public set isEnabled(value: boolean) {
  137. this._isEnabled = value;
  138. if (!value) {
  139. this.attachedMesh = null;
  140. }
  141. else {
  142. if (this._parent) {
  143. this.attachedMesh = this._parent.attachedMesh;
  144. }
  145. }
  146. }
  147. public get isEnabled(): boolean {
  148. return this._isEnabled;
  149. }
  150. /**
  151. * Disposes of the gizmo
  152. */
  153. public dispose() {
  154. this.onSnapObservable.clear();
  155. this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
  156. this.dragBehavior.detach();
  157. super.dispose();
  158. if (this._plane) {
  159. this._plane.dispose();
  160. }
  161. [this._coloredMaterial, this._hoverMaterial].forEach((matl) => {
  162. if (matl) {
  163. matl.dispose();
  164. }
  165. });
  166. }
  167. }