scaleGizmo.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. import { Logger } from "../Misc/logger.js";
  2. import { Observable } from "../Misc/observable.js";
  3. import { Vector3 } from "../Maths/math.vector.js";
  4. import { Color3 } from "../Maths/math.color.js";
  5. import { CreatePolyhedron } from "../Meshes/Builders/polyhedronBuilder.js";
  6. import { GizmoCoordinatesMode, Gizmo } from "./gizmo.js";
  7. import { AxisScaleGizmo } from "./axisScaleGizmo.js";
  8. import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer.js";
  9. import { StandardMaterial } from "../Materials/standardMaterial.js";
  10. /**
  11. * Gizmo that enables scaling a mesh along 3 axis
  12. */
  13. export class ScaleGizmo 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. get attachedMesh() {
  27. return this._meshAttached;
  28. }
  29. set attachedMesh(mesh) {
  30. this._meshAttached = mesh;
  31. this._nodeAttached = mesh;
  32. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  33. if (gizmo.isEnabled) {
  34. gizmo.attachedMesh = mesh;
  35. }
  36. else {
  37. gizmo.attachedMesh = null;
  38. }
  39. });
  40. }
  41. get attachedNode() {
  42. return this._nodeAttached;
  43. }
  44. set attachedNode(node) {
  45. this._meshAttached = null;
  46. this._nodeAttached = node;
  47. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  48. if (gizmo.isEnabled) {
  49. gizmo.attachedNode = node;
  50. }
  51. else {
  52. gizmo.attachedNode = null;
  53. }
  54. });
  55. }
  56. set updateScale(value) {
  57. if (this.xGizmo) {
  58. this.xGizmo.updateScale = value;
  59. this.yGizmo.updateScale = value;
  60. this.zGizmo.updateScale = value;
  61. }
  62. }
  63. get updateScale() {
  64. return this.xGizmo.updateScale;
  65. }
  66. /**
  67. * True when the mouse pointer is hovering a gizmo mesh
  68. */
  69. get isHovered() {
  70. return this.xGizmo.isHovered || this.yGizmo.isHovered || this.zGizmo.isHovered || this.uniformScaleGizmo.isHovered;
  71. }
  72. /**
  73. * True when the mouse pointer is dragging a gizmo mesh
  74. */
  75. get isDragging() {
  76. return this.xGizmo.dragBehavior.dragging || this.yGizmo.dragBehavior.dragging || this.zGizmo.dragBehavior.dragging || this.uniformScaleGizmo.dragBehavior.dragging;
  77. }
  78. get additionalTransformNode() {
  79. return this._additionalTransformNode;
  80. }
  81. set additionalTransformNode(transformNode) {
  82. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  83. gizmo.additionalTransformNode = transformNode;
  84. });
  85. }
  86. /**
  87. * Creates a ScaleGizmo
  88. * @param gizmoLayer The utility layer the gizmo will be added to
  89. * @param thickness display gizmo axis thickness
  90. * @param gizmoManager
  91. * @param options More options
  92. */
  93. constructor(gizmoLayer = UtilityLayerRenderer.DefaultUtilityLayer, thickness = 1, gizmoManager, options) {
  94. super(gizmoLayer);
  95. this._meshAttached = null;
  96. this._nodeAttached = null;
  97. this._incrementalSnap = false;
  98. this._sensitivity = 1;
  99. this._observables = [];
  100. /** Node Caching for quick lookup */
  101. this._gizmoAxisCache = new Map();
  102. /** Fires an event when any of it's sub gizmos are dragged */
  103. this.onDragStartObservable = new Observable();
  104. /** Fires an event when any of it's sub gizmos are being dragged */
  105. this.onDragObservable = new Observable();
  106. /** Fires an event when any of it's sub gizmos are released from dragging */
  107. this.onDragEndObservable = new Observable();
  108. this.uniformScaleGizmo = this._createUniformScaleMesh();
  109. this.xGizmo = new AxisScaleGizmo(new Vector3(1, 0, 0), Color3.Red().scale(0.5), gizmoLayer, this, thickness);
  110. this.yGizmo = new AxisScaleGizmo(new Vector3(0, 1, 0), Color3.Green().scale(0.5), gizmoLayer, this, thickness);
  111. this.zGizmo = new AxisScaleGizmo(new Vector3(0, 0, 1), Color3.Blue().scale(0.5), gizmoLayer, this, thickness);
  112. this.additionalTransformNode = options?.additionalTransformNode;
  113. // Relay drag events
  114. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  115. gizmo.dragBehavior.onDragStartObservable.add(() => {
  116. this.onDragStartObservable.notifyObservers({});
  117. });
  118. gizmo.dragBehavior.onDragObservable.add(() => {
  119. this.onDragObservable.notifyObservers({});
  120. });
  121. gizmo.dragBehavior.onDragEndObservable.add(() => {
  122. this.onDragEndObservable.notifyObservers({});
  123. });
  124. });
  125. this.attachedMesh = null;
  126. this.attachedNode = null;
  127. if (gizmoManager) {
  128. gizmoManager.addToAxisCache(this._gizmoAxisCache);
  129. }
  130. else {
  131. // Only subscribe to pointer event if gizmoManager isnt
  132. Gizmo.GizmoAxisPointerObserver(gizmoLayer, this._gizmoAxisCache);
  133. }
  134. }
  135. /**
  136. * @internal
  137. * Create Geometry for Gizmo
  138. */
  139. _createUniformScaleMesh() {
  140. this._coloredMaterial = new StandardMaterial("", this.gizmoLayer.utilityLayerScene);
  141. this._coloredMaterial.diffuseColor = Color3.Gray();
  142. this._hoverMaterial = new StandardMaterial("", this.gizmoLayer.utilityLayerScene);
  143. this._hoverMaterial.diffuseColor = Color3.Yellow();
  144. this._disableMaterial = new StandardMaterial("", this.gizmoLayer.utilityLayerScene);
  145. this._disableMaterial.diffuseColor = Color3.Gray();
  146. this._disableMaterial.alpha = 0.4;
  147. const uniformScaleGizmo = new AxisScaleGizmo(new Vector3(0, 1, 0), Color3.Gray().scale(0.5), this.gizmoLayer, this);
  148. uniformScaleGizmo.updateGizmoRotationToMatchAttachedMesh = false;
  149. uniformScaleGizmo.uniformScaling = true;
  150. this._uniformScalingMesh = CreatePolyhedron("uniform", { type: 1 }, uniformScaleGizmo.gizmoLayer.utilityLayerScene);
  151. this._uniformScalingMesh.scaling.scaleInPlace(0.01);
  152. this._uniformScalingMesh.visibility = 0;
  153. this._octahedron = CreatePolyhedron("", { type: 1 }, uniformScaleGizmo.gizmoLayer.utilityLayerScene);
  154. this._octahedron.scaling.scaleInPlace(0.007);
  155. this._uniformScalingMesh.addChild(this._octahedron);
  156. uniformScaleGizmo.setCustomMesh(this._uniformScalingMesh, true);
  157. const light = this.gizmoLayer._getSharedGizmoLight();
  158. light.includedOnlyMeshes = light.includedOnlyMeshes.concat(this._octahedron);
  159. const cache = {
  160. gizmoMeshes: [this._octahedron, this._uniformScalingMesh],
  161. colliderMeshes: [this._octahedron, this._uniformScalingMesh],
  162. material: this._coloredMaterial,
  163. hoverMaterial: this._hoverMaterial,
  164. disableMaterial: this._disableMaterial,
  165. active: false,
  166. dragBehavior: uniformScaleGizmo.dragBehavior,
  167. };
  168. this.addToAxisCache(uniformScaleGizmo._rootMesh, cache);
  169. return uniformScaleGizmo;
  170. }
  171. set updateGizmoRotationToMatchAttachedMesh(value) {
  172. if (!value) {
  173. Logger.Warn("Setting updateGizmoRotationToMatchAttachedMesh = false on scaling gizmo is not supported.");
  174. }
  175. else {
  176. this._updateGizmoRotationToMatchAttachedMesh = value;
  177. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  178. if (gizmo) {
  179. gizmo.updateGizmoRotationToMatchAttachedMesh = value;
  180. }
  181. });
  182. }
  183. }
  184. get updateGizmoRotationToMatchAttachedMesh() {
  185. return this._updateGizmoRotationToMatchAttachedMesh;
  186. }
  187. set anchorPoint(value) {
  188. this._anchorPoint = value;
  189. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  190. if (gizmo) {
  191. gizmo.anchorPoint = value;
  192. }
  193. });
  194. }
  195. get anchorPoint() {
  196. return this._anchorPoint;
  197. }
  198. /**
  199. * posture that the gizmo will be display
  200. * When set null, default value will be used (Quaternion(0, 0, 0, 1))
  201. */
  202. get customRotationQuaternion() {
  203. return this._customRotationQuaternion;
  204. }
  205. set customRotationQuaternion(customRotationQuaternion) {
  206. this._customRotationQuaternion = customRotationQuaternion;
  207. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  208. if (gizmo) {
  209. gizmo.customRotationQuaternion = customRotationQuaternion;
  210. }
  211. });
  212. }
  213. /**
  214. * Set the coordinate system to use. By default it's local.
  215. * But it's possible for a user to tweak so its local for translation and world for rotation.
  216. * In that case, setting the coordinate system will change `updateGizmoRotationToMatchAttachedMesh` and `updateGizmoPositionToMatchAttachedMesh`
  217. */
  218. set coordinatesMode(coordinatesMode) {
  219. if (coordinatesMode == GizmoCoordinatesMode.World) {
  220. Logger.Warn("Setting coordinates Mode to world on scaling gizmo is not supported.");
  221. }
  222. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  223. gizmo.coordinatesMode = GizmoCoordinatesMode.Local;
  224. });
  225. }
  226. /**
  227. * Drag distance in babylon units that the gizmo will snap to when dragged (Default: 0)
  228. */
  229. set snapDistance(value) {
  230. this._snapDistance = value;
  231. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  232. if (gizmo) {
  233. gizmo.snapDistance = value;
  234. }
  235. });
  236. }
  237. get snapDistance() {
  238. return this._snapDistance;
  239. }
  240. /**
  241. * Incremental snap scaling (default is false). When true, with a snapDistance of 0.1, scaling will be 1.1,1.2,1.3 instead of, when false: 1.1,1.21,1.33,...
  242. */
  243. set incrementalSnap(value) {
  244. this._incrementalSnap = value;
  245. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  246. if (gizmo) {
  247. gizmo.incrementalSnap = value;
  248. }
  249. });
  250. }
  251. get incrementalSnap() {
  252. return this._incrementalSnap;
  253. }
  254. /**
  255. * Ratio for the scale of the gizmo (Default: 1)
  256. */
  257. set scaleRatio(value) {
  258. this._scaleRatio = value;
  259. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  260. if (gizmo) {
  261. gizmo.scaleRatio = value;
  262. }
  263. });
  264. }
  265. get scaleRatio() {
  266. return this._scaleRatio;
  267. }
  268. /**
  269. * Sensitivity factor for dragging (Default: 1)
  270. */
  271. set sensitivity(value) {
  272. this._sensitivity = value;
  273. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  274. if (gizmo) {
  275. gizmo.sensitivity = value;
  276. }
  277. });
  278. }
  279. get sensitivity() {
  280. return this._sensitivity;
  281. }
  282. /**
  283. * Builds Gizmo Axis Cache to enable features such as hover state preservation and graying out other axis during manipulation
  284. * @param mesh Axis gizmo mesh
  285. * @param cache Gizmo axis definition used for reactive gizmo UI
  286. */
  287. addToAxisCache(mesh, cache) {
  288. this._gizmoAxisCache.set(mesh, cache);
  289. }
  290. /**
  291. * Get the cache set with addToAxisCache for a specific mesh
  292. * @param mesh Axis gizmo mesh
  293. * @returns Gizmo axis definition used for reactive gizmo UI
  294. */
  295. getAxisCache(mesh) {
  296. return this._gizmoAxisCache.get(mesh);
  297. }
  298. /**
  299. * Force release the drag action by code
  300. */
  301. releaseDrag() {
  302. this.xGizmo.dragBehavior.releaseDrag();
  303. this.yGizmo.dragBehavior.releaseDrag();
  304. this.zGizmo.dragBehavior.releaseDrag();
  305. this.uniformScaleGizmo.dragBehavior.releaseDrag();
  306. }
  307. /**
  308. * Disposes of the gizmo
  309. */
  310. dispose() {
  311. [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
  312. if (gizmo) {
  313. gizmo.dispose();
  314. }
  315. });
  316. this._observables.forEach((obs) => {
  317. this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(obs);
  318. });
  319. this.onDragStartObservable.clear();
  320. this.onDragObservable.clear();
  321. this.onDragEndObservable.clear();
  322. [this._uniformScalingMesh, this._octahedron].forEach((msh) => {
  323. if (msh) {
  324. msh.dispose();
  325. }
  326. });
  327. [this._coloredMaterial, this._hoverMaterial, this._disableMaterial].forEach((matl) => {
  328. if (matl) {
  329. matl.dispose();
  330. }
  331. });
  332. }
  333. }
  334. //# sourceMappingURL=scaleGizmo.js.map