axisScaleGizmo.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { Observer, Observable } from "../Misc/observable";
  2. import { Nullable } from "../types";
  3. import { PointerInfo } from "../Events/pointerEvents";
  4. import { Vector3, Color3 } from "../Maths/math";
  5. import { AbstractMesh } from "../Meshes/abstractMesh";
  6. import { Mesh } from "../Meshes/mesh";
  7. import { LinesMesh } from "../Meshes/linesMesh";
  8. import { BoxBuilder } from "../Meshes/Builders/boxBuilder";
  9. import { CylinderBuilder } from "../Meshes/Builders/cylinderBuilder";
  10. import { StandardMaterial } from "../Materials/standardMaterial";
  11. import { PointerDragBehavior } from "../Behaviors/Meshes/pointerDragBehavior";
  12. import { _TimeToken } from "../Instrumentation/timeToken";
  13. import { _DepthCullingState, _StencilState, _AlphaState } from "../States/index";
  14. import { Gizmo } from "./gizmo";
  15. import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
  16. /**
  17. * Single axis scale gizmo
  18. */
  19. export class AxisScaleGizmo extends Gizmo {
  20. private _coloredMaterial: StandardMaterial;
  21. /**
  22. * Drag behavior responsible for the gizmos dragging interactions
  23. */
  24. public dragBehavior: PointerDragBehavior;
  25. private _pointerObserver: Nullable<Observer<PointerInfo>> = null;
  26. /**
  27. * Scale distance in babylon units that the gizmo will snap to when dragged (Default: 0)
  28. */
  29. public snapDistance = 0;
  30. /**
  31. * Event that fires each time the gizmo snaps to a new location.
  32. * * snapDistance is the the change in distance
  33. */
  34. public onSnapObservable = new Observable<{ snapDistance: number }>();
  35. /**
  36. * If the scaling operation should be done on all axis (default: false)
  37. */
  38. public uniformScaling = false;
  39. /**
  40. * Creates an AxisScaleGizmo
  41. * @param gizmoLayer The utility layer the gizmo will be added to
  42. * @param dragAxis The axis which the gizmo will be able to scale on
  43. * @param color The color of the gizmo
  44. */
  45. constructor(dragAxis: Vector3, color: Color3 = Color3.Gray(), gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultGizmoUtilityLayer) {
  46. super(gizmoLayer);
  47. // Create Material
  48. this._coloredMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
  49. this._coloredMaterial.diffuseColor = color;
  50. this._coloredMaterial.specularColor = color.subtract(new Color3(0.1, 0.1, 0.1));
  51. var hoverMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
  52. hoverMaterial.diffuseColor = color.add(new Color3(0.3, 0.3, 0.3));
  53. // Build mesh on root node
  54. var arrow = new AbstractMesh("", gizmoLayer.utilityLayerScene);
  55. var arrowMesh = BoxBuilder.CreateBox("yPosMesh", { size: 0.4 }, gizmoLayer.utilityLayerScene);
  56. var arrowTail = CylinderBuilder.CreateCylinder("cylinder", { diameterTop: 0.005, height: 0.275, diameterBottom: 0.005, tessellation: 96 }, gizmoLayer.utilityLayerScene);
  57. arrow.addChild(arrowMesh);
  58. arrow.addChild(arrowTail);
  59. // Position arrow pointing in its drag axis
  60. arrowMesh.scaling.scaleInPlace(0.1);
  61. arrowMesh.material = this._coloredMaterial;
  62. arrowMesh.rotation.x = Math.PI / 2;
  63. arrowMesh.position.z += 0.3;
  64. arrowTail.position.z += 0.275 / 2;
  65. arrowTail.rotation.x = Math.PI / 2;
  66. arrow.lookAt(this._rootMesh.position.add(dragAxis));
  67. this._rootMesh.addChild(arrow);
  68. arrow.scaling.scaleInPlace(1 / 3);
  69. // Add drag behavior to handle events when the gizmo is dragged
  70. this.dragBehavior = new PointerDragBehavior({ dragAxis: dragAxis });
  71. this.dragBehavior.moveAttached = false;
  72. this._rootMesh.addBehavior(this.dragBehavior);
  73. var currentSnapDragDistance = 0;
  74. var tmpVector = new Vector3();
  75. var tmpSnapEvent = { snapDistance: 0 };
  76. this.dragBehavior.onDragObservable.add((event) => {
  77. if (this.attachedMesh) {
  78. // Snapping logic
  79. var snapped = false;
  80. var dragSteps = 0;
  81. if (this.uniformScaling) {
  82. this.attachedMesh.scaling.normalizeToRef(tmpVector);
  83. if (tmpVector.y < 0) {
  84. tmpVector.scaleInPlace(-1);
  85. }
  86. } else {
  87. tmpVector.copyFrom(dragAxis);
  88. }
  89. if (this.snapDistance == 0) {
  90. tmpVector.scaleToRef(event.dragDistance, tmpVector);
  91. } else {
  92. currentSnapDragDistance += event.dragDistance;
  93. if (Math.abs(currentSnapDragDistance) > this.snapDistance) {
  94. dragSteps = Math.floor(Math.abs(currentSnapDragDistance) / this.snapDistance);
  95. if (currentSnapDragDistance < 0) {
  96. dragSteps *= -1;
  97. }
  98. currentSnapDragDistance = currentSnapDragDistance % this.snapDistance;
  99. tmpVector.scaleToRef(this.snapDistance * dragSteps, tmpVector);
  100. snapped = true;
  101. } else {
  102. tmpVector.scaleInPlace(0);
  103. }
  104. }
  105. this.attachedMesh.scaling.addInPlace(tmpVector);
  106. if (snapped) {
  107. tmpSnapEvent.snapDistance = this.snapDistance * dragSteps;
  108. this.onSnapObservable.notifyObservers(tmpSnapEvent);
  109. }
  110. }
  111. });
  112. this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
  113. if (this._customMeshSet) {
  114. return;
  115. }
  116. var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
  117. var material = isHovered ? hoverMaterial : this._coloredMaterial;
  118. this._rootMesh.getChildMeshes().forEach((m) => {
  119. m.material = material;
  120. if ((<LinesMesh>m).color) {
  121. (<LinesMesh>m).color = material.diffuseColor;
  122. }
  123. });
  124. });
  125. }
  126. protected _attachedMeshChanged(value: Nullable<AbstractMesh>) {
  127. if (this.dragBehavior) {
  128. this.dragBehavior.enabled = value ? true : false;
  129. }
  130. }
  131. /**
  132. * Disposes of the gizmo
  133. */
  134. public dispose() {
  135. this.onSnapObservable.clear();
  136. this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
  137. this.dragBehavior.detach();
  138. super.dispose();
  139. }
  140. /**
  141. * Disposes and replaces the current meshes in the gizmo with the specified mesh
  142. * @param mesh The mesh to replace the default mesh of the gizmo
  143. * @param useGizmoMaterial If the gizmo's default material should be used (default: false)
  144. */
  145. public setCustomMesh(mesh: Mesh, useGizmoMaterial: boolean = false) {
  146. super.setCustomMesh(mesh);
  147. if (useGizmoMaterial) {
  148. this._rootMesh.getChildMeshes().forEach((m) => {
  149. m.material = this._coloredMaterial;
  150. if ((<LinesMesh>m).color) {
  151. (<LinesMesh>m).color = this._coloredMaterial.diffuseColor;
  152. }
  153. });
  154. this._customMeshSet = false;
  155. }
  156. }
  157. }