planeDragGizmo.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { Observable } from "../Misc/observable.js";
  2. import { TmpVectors, Vector3 } from "../Maths/math.vector.js";
  3. import { Color3 } from "../Maths/math.color.js";
  4. import { TransformNode } from "../Meshes/transformNode.js";
  5. import { CreatePlane } from "../Meshes/Builders/planeBuilder.js";
  6. import { PointerDragBehavior } from "../Behaviors/Meshes/pointerDragBehavior.js";
  7. import { Gizmo } from "./gizmo.js";
  8. import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer.js";
  9. import { StandardMaterial } from "../Materials/standardMaterial.js";
  10. /**
  11. * Single plane drag gizmo
  12. */
  13. export class PlaneDragGizmo extends Gizmo {
  14. /** Default material used to render when gizmo is not disabled or hovered */
  15. get coloredMaterial() {
  16. return this._coloredMaterial;
  17. }
  18. /** Material used to render when gizmo is hovered with mouse*/
  19. get hoverMaterial() {
  20. return this._hoverMaterial;
  21. }
  22. /** Material used to render when gizmo is disabled. typically grey.*/
  23. get disableMaterial() {
  24. return this._disableMaterial;
  25. }
  26. /**
  27. * @internal
  28. */
  29. static _CreatePlane(scene, material) {
  30. const plane = new TransformNode("plane", scene);
  31. //make sure plane is double sided
  32. const dragPlane = CreatePlane("dragPlane", { width: 0.1375, height: 0.1375, sideOrientation: 2 }, scene);
  33. dragPlane.material = material;
  34. dragPlane.parent = plane;
  35. return plane;
  36. }
  37. /**
  38. * Creates a PlaneDragGizmo
  39. * @param dragPlaneNormal The axis normal to which the gizmo will be able to drag on
  40. * @param color The color of the gizmo
  41. * @param gizmoLayer The utility layer the gizmo will be added to
  42. * @param parent
  43. * @param hoverColor The color of the gizmo when hovering over and dragging
  44. * @param disableColor The Color of the gizmo when its disabled
  45. */
  46. constructor(dragPlaneNormal, color = Color3.Gray(), gizmoLayer = UtilityLayerRenderer.DefaultUtilityLayer, parent = null, hoverColor = Color3.Yellow(), disableColor = Color3.Gray()) {
  47. super(gizmoLayer);
  48. this._pointerObserver = null;
  49. /**
  50. * Drag distance in babylon units that the gizmo will snap to when dragged (Default: 0)
  51. */
  52. this.snapDistance = 0;
  53. /**
  54. * Event that fires each time the gizmo snaps to a new location.
  55. * * snapDistance is the change in distance
  56. */
  57. this.onSnapObservable = new Observable();
  58. this._isEnabled = false;
  59. this._parent = null;
  60. this._dragging = false;
  61. this._parent = parent;
  62. // Create Material
  63. this._coloredMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
  64. this._coloredMaterial.diffuseColor = color;
  65. this._coloredMaterial.specularColor = color.subtract(new Color3(0.1, 0.1, 0.1));
  66. this._hoverMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
  67. this._hoverMaterial.diffuseColor = hoverColor;
  68. this._disableMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
  69. this._disableMaterial.diffuseColor = disableColor;
  70. this._disableMaterial.alpha = 0.4;
  71. // Build plane mesh on root node
  72. this._gizmoMesh = PlaneDragGizmo._CreatePlane(gizmoLayer.utilityLayerScene, this._coloredMaterial);
  73. this._gizmoMesh.lookAt(this._rootMesh.position.add(dragPlaneNormal));
  74. this._gizmoMesh.scaling.scaleInPlace(1 / 3);
  75. this._gizmoMesh.parent = this._rootMesh;
  76. let currentSnapDragDistance = 0;
  77. const tmpVector = new Vector3();
  78. const tmpSnapEvent = { snapDistance: 0 };
  79. // Add dragPlaneNormal drag behavior to handle events when the gizmo is dragged
  80. this.dragBehavior = new PointerDragBehavior({ dragPlaneNormal: dragPlaneNormal });
  81. this.dragBehavior.moveAttached = false;
  82. this._rootMesh.addBehavior(this.dragBehavior);
  83. this.dragBehavior.onDragObservable.add((event) => {
  84. if (this.attachedNode) {
  85. // Keep world translation and use it to update world transform
  86. // if the node has parent, the local transform properties (position, rotation, scale)
  87. // will be recomputed in _matrixChanged function
  88. // Snapping logic
  89. if (this.snapDistance == 0) {
  90. this.attachedNode.getWorldMatrix().getTranslationToRef(TmpVectors.Vector3[0]);
  91. TmpVectors.Vector3[0].addToRef(event.delta, TmpVectors.Vector3[0]);
  92. if (this.dragBehavior.validateDrag(TmpVectors.Vector3[0])) {
  93. this.attachedNode.getWorldMatrix().addTranslationFromFloats(event.delta.x, event.delta.y, event.delta.z);
  94. }
  95. }
  96. else {
  97. currentSnapDragDistance += event.dragDistance;
  98. if (Math.abs(currentSnapDragDistance) > this.snapDistance) {
  99. const dragSteps = Math.floor(Math.abs(currentSnapDragDistance) / this.snapDistance);
  100. currentSnapDragDistance = currentSnapDragDistance % this.snapDistance;
  101. event.delta.normalizeToRef(tmpVector);
  102. tmpVector.scaleInPlace(this.snapDistance * dragSteps);
  103. this.attachedNode.getWorldMatrix().getTranslationToRef(TmpVectors.Vector3[0]);
  104. TmpVectors.Vector3[0].addToRef(tmpVector, TmpVectors.Vector3[0]);
  105. if (this.dragBehavior.validateDrag(TmpVectors.Vector3[0])) {
  106. this.attachedNode.getWorldMatrix().addTranslationFromFloats(tmpVector.x, tmpVector.y, tmpVector.z);
  107. tmpSnapEvent.snapDistance = this.snapDistance * dragSteps;
  108. this.onSnapObservable.notifyObservers(tmpSnapEvent);
  109. }
  110. }
  111. }
  112. this._matrixChanged();
  113. }
  114. });
  115. this.dragBehavior.onDragStartObservable.add(() => {
  116. this._dragging = true;
  117. });
  118. this.dragBehavior.onDragEndObservable.add(() => {
  119. this._dragging = false;
  120. });
  121. const light = gizmoLayer._getSharedGizmoLight();
  122. light.includedOnlyMeshes = light.includedOnlyMeshes.concat(this._rootMesh.getChildMeshes(false));
  123. const cache = {
  124. gizmoMeshes: this._gizmoMesh.getChildMeshes(),
  125. colliderMeshes: this._gizmoMesh.getChildMeshes(),
  126. material: this._coloredMaterial,
  127. hoverMaterial: this._hoverMaterial,
  128. disableMaterial: this._disableMaterial,
  129. active: false,
  130. dragBehavior: this.dragBehavior,
  131. };
  132. this._parent?.addToAxisCache(this._gizmoMesh, cache);
  133. this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
  134. if (this._customMeshSet) {
  135. return;
  136. }
  137. this._isHovered = !!(cache.colliderMeshes.indexOf(pointerInfo?.pickInfo?.pickedMesh) != -1);
  138. if (!this._parent) {
  139. const material = cache.dragBehavior.enabled ? (this._isHovered || this._dragging ? this._hoverMaterial : this._coloredMaterial) : this._disableMaterial;
  140. this._setGizmoMeshMaterial(cache.gizmoMeshes, material);
  141. }
  142. });
  143. this.dragBehavior.onEnabledObservable.add((newState) => {
  144. this._setGizmoMeshMaterial(cache.gizmoMeshes, newState ? this._coloredMaterial : this._disableMaterial);
  145. });
  146. }
  147. _attachedNodeChanged(value) {
  148. if (this.dragBehavior) {
  149. this.dragBehavior.enabled = value ? true : false;
  150. }
  151. }
  152. /**
  153. * If the gizmo is enabled
  154. */
  155. set isEnabled(value) {
  156. this._isEnabled = value;
  157. if (!value) {
  158. this.attachedNode = null;
  159. }
  160. else {
  161. if (this._parent) {
  162. this.attachedNode = this._parent.attachedNode;
  163. }
  164. }
  165. }
  166. get isEnabled() {
  167. return this._isEnabled;
  168. }
  169. /**
  170. * Disposes of the gizmo
  171. */
  172. dispose() {
  173. this.onSnapObservable.clear();
  174. this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
  175. this.dragBehavior.detach();
  176. super.dispose();
  177. if (this._gizmoMesh) {
  178. this._gizmoMesh.dispose();
  179. }
  180. [this._coloredMaterial, this._hoverMaterial, this._disableMaterial].forEach((matl) => {
  181. if (matl) {
  182. matl.dispose();
  183. }
  184. });
  185. }
  186. }
  187. //# sourceMappingURL=planeDragGizmo.js.map