Преглед изворни кода

Gizmo Meshes - manage state between multiple gizmos + centralize observers

Dave Gould пре 4 година
родитељ
комит
cb775a79b2

+ 67 - 0
src/Gizmos/gizmo.ts

@@ -12,6 +12,8 @@ import { Bone } from "../Bones/bone";
 import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
 import { TransformNode } from '../Meshes/transformNode';
 import { StandardMaterial } from '../Materials/standardMaterial';
+import { PointerEventTypes, PointerInfo } from '../Events/pointerEvents';
+import { LinesMesh } from '../Meshes/linesMesh';
 
 /**
  * Cache built by each axis. Used for managing state between all elements of gizmo for enhanced UI
@@ -295,6 +297,71 @@ export class Gizmo implements IDisposable {
     }
 
     /**
+     * Subscribes to pointer up, down, and hover events. Used for responsive gizmos.
+     */
+    public static GizmoAxisPointerObserver(gizmoLayer: UtilityLayerRenderer, gizmoAxisCache: Map<Mesh, GizmoAxisCache>): Observer<PointerInfo> {
+
+        let dragging = false;
+
+        const pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
+            if (pointerInfo.pickInfo) {
+                // On Hover Logic
+                if (pointerInfo.type === PointerEventTypes.POINTERMOVE) {
+                    if (dragging) { return; }
+                    gizmoAxisCache.forEach((cache) => {
+                        if (cache.colliderMeshes && cache.gizmoMeshes) {
+                            const isHovered = (cache.colliderMeshes?.indexOf((pointerInfo?.pickInfo?.pickedMesh as Mesh)) != -1);
+                            const material = isHovered || cache.active ? cache.hoverMaterial : cache.material;
+                            cache.gizmoMeshes.forEach((m: Mesh) => {
+                                m.material = material;
+                                if ((m as LinesMesh).color) {
+                                    (m as LinesMesh).color = material.diffuseColor;
+                                }
+                            });
+                        }
+                    });
+                }
+
+                // On Mouse Down
+                if (pointerInfo.type === PointerEventTypes.POINTERDOWN) {
+                    // If user Clicked Gizmo
+                    if (gizmoAxisCache.has(pointerInfo.pickInfo.pickedMesh?.parent as Mesh)) {
+                        dragging = true;
+                        const statusMap = gizmoAxisCache.get(pointerInfo.pickInfo.pickedMesh?.parent as Mesh);
+                        statusMap!.active = true;
+                        gizmoAxisCache.forEach((cache) => {
+                            const isHovered = (cache.colliderMeshes?.indexOf((pointerInfo?.pickInfo?.pickedMesh as Mesh)) != -1);
+                            const material = isHovered || cache.active ? cache.hoverMaterial : cache.disableMaterial;
+                            cache.gizmoMeshes.forEach((m: Mesh) => {
+                                m.material = material;
+                                if ((m as LinesMesh).color) {
+                                    (m as LinesMesh).color = material.diffuseColor;
+                                }
+                            });
+                        });
+                    }
+                }
+
+                // On Mouse Up
+                if (pointerInfo.type === PointerEventTypes.POINTERUP) {
+                    gizmoAxisCache.forEach((cache) => {
+                        cache.active = false;
+                        dragging = false;
+                        cache.gizmoMeshes.forEach((m: Mesh) => {
+                            m.material = cache.material;
+                            if ((m as LinesMesh).color) {
+                                (m as LinesMesh).color = cache.material.diffuseColor;
+                            }
+                        });
+                    });
+                }
+            }
+        });
+
+        return pointerObserver!;
+    }
+
+    /**
      * Disposes of the gizmo
      */
     public dispose() {

+ 34 - 8
src/Gizmos/gizmoManager.ts

@@ -4,11 +4,12 @@ import { PointerInfo, PointerEventTypes } from "../Events/pointerEvents";
 import { Scene, IDisposable } from "../scene";
 import { Node } from "../node";
 import { AbstractMesh } from "../Meshes/abstractMesh";
+import { Mesh } from '../Meshes/mesh';
+import { LinesMesh } from '../Meshes/linesMesh';
 import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
 import { Color3 } from '../Maths/math.color';
 import { SixDofDragBehavior } from "../Behaviors/Meshes/sixDofDragBehavior";
-
-import { Gizmo } from "./gizmo";
+import { Gizmo, GizmoAxisCache } from "./gizmo";
 import { RotationGizmo } from "./rotationGizmo";
 import { PositionGizmo } from "./positionGizmo";
 import { ScaleGizmo } from "./scaleGizmo";
@@ -33,13 +34,15 @@ export class GizmoManager implements IDisposable {
     public onAttachedToNodeObservable = new Observable<Nullable<Node>>();
 
     private _gizmosEnabled = { positionGizmo: false, rotationGizmo: false, scaleGizmo: false, boundingBoxGizmo: false };
-    private _pointerObserver: Nullable<Observer<PointerInfo>> = null;
+    private _pointerObservers: Observer<PointerInfo>[] = [];
     private _attachedMesh: Nullable<AbstractMesh> = null;
     private _attachedNode: Nullable<Node> = null;
     private _boundingBoxColor = Color3.FromHexString("#0984e3");
     private _defaultUtilityLayer: UtilityLayerRenderer;
     private _defaultKeepDepthUtilityLayer: UtilityLayerRenderer;
     private _thickness: number = 1;
+    /** Node Caching for quick lookup */
+    private _gizmoAxisCache: Map<Mesh, GizmoAxisCache> = new Map();
     /**
      * When bounding box gizmo is enabled, this can be used to track drag/end events
      */
@@ -98,8 +101,14 @@ export class GizmoManager implements IDisposable {
         this._thickness = thickness;
         this.gizmos = { positionGizmo: null, rotationGizmo: null, scaleGizmo: null, boundingBoxGizmo: null };
 
+        const attachToMeshPointerObserver = this._attachToMeshPointerObserver(scene);
+        const gizmoAxisPointerObserver = Gizmo.GizmoAxisPointerObserver(this._defaultUtilityLayer, this._gizmoAxisCache);
+        this._pointerObservers = [attachToMeshPointerObserver, gizmoAxisPointerObserver]
+    }
+
+    private _attachToMeshPointerObserver(scene: Scene): Observer<PointerInfo> {
         // Instatiate/dispose gizmos based on pointer actions
-        this._pointerObserver = scene.onPointerObservable.add((pointerInfo) => {
+        const pointerObserver = scene.onPointerObservable.add((pointerInfo) => {
             if (!this.usePointerToAttachGizmos) {
                 return;
             }
@@ -140,6 +149,7 @@ export class GizmoManager implements IDisposable {
                 }
             }
         });
+        return pointerObserver!;
     }
 
     /**
@@ -198,7 +208,7 @@ export class GizmoManager implements IDisposable {
     public set positionGizmoEnabled(value: boolean) {
         if (value) {
             if (!this.gizmos.positionGizmo) {
-                this.gizmos.positionGizmo = new PositionGizmo(this._defaultUtilityLayer, this._thickness);
+                this.gizmos.positionGizmo = new PositionGizmo(this._defaultUtilityLayer, this._thickness, this);
             }
             if (this._attachedNode) {
                 this.gizmos.positionGizmo.attachedNode = this._attachedNode;
@@ -219,7 +229,7 @@ export class GizmoManager implements IDisposable {
     public set rotationGizmoEnabled(value: boolean) {
         if (value) {
             if (!this.gizmos.rotationGizmo) {
-                this.gizmos.rotationGizmo = new RotationGizmo(this._defaultUtilityLayer, 32, false, this._thickness);
+                this.gizmos.rotationGizmo = new RotationGizmo(this._defaultUtilityLayer, 32, false, this._thickness, this);
             }
             if (this._attachedNode) {
                 this.gizmos.rotationGizmo.attachedNode = this._attachedNode;
@@ -239,7 +249,7 @@ export class GizmoManager implements IDisposable {
      */
     public set scaleGizmoEnabled(value: boolean) {
         if (value) {
-            this.gizmos.scaleGizmo = this.gizmos.scaleGizmo || new ScaleGizmo(this._defaultUtilityLayer, this._thickness);
+            this.gizmos.scaleGizmo = this.gizmos.scaleGizmo || new ScaleGizmo(this._defaultUtilityLayer, this._thickness, this);
             if (this._attachedNode) {
                 this.gizmos.scaleGizmo.attachedNode = this._attachedNode;
             } else {
@@ -287,10 +297,26 @@ export class GizmoManager implements IDisposable {
     }
 
     /**
+     * Builds Gizmo Axis Cache to enable features such as hover state preservation and graying out other axis during manipulation
+     * @param mesh Axis gizmo mesh
+      @param cache display gizmo axis thickness
+    */
+    public addToAxisCache(gizmoAxisCache: Map<Mesh, GizmoAxisCache>) {
+        if (gizmoAxisCache.size > 0) {
+            gizmoAxisCache.forEach((v, k) => {
+                this._gizmoAxisCache.set(k, v);
+            })
+        }
+    }
+
+    /**
      * Disposes of the gizmo manager
      */
     public dispose() {
-        this.scene.onPointerObservable.remove(this._pointerObserver);
+        
+        this._pointerObservers.forEach(observer => {
+            this.scene.onPointerObservable.remove(observer);
+        });
         for (var key in this.gizmos) {
             var gizmo = <Nullable<Gizmo>>((<any>this.gizmos)[key]);
             if (gizmo) {

+ 0 - 1
src/Gizmos/planeRotationGizmo.ts

@@ -289,7 +289,6 @@ export class PlaneRotationGizmo extends Gizmo {
 
             paths.push(path);
         }
-        console.log(paths);
 
         const mat = new StandardMaterial("", this.gizmoLayer.utilityLayerScene);
         mat.diffuseColor = Color3.Yellow();

+ 9 - 64
src/Gizmos/positionGizmo.ts

@@ -12,6 +12,7 @@ import { PlaneDragGizmo } from "./planeDragGizmo";
 import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
 import { PointerEventTypes, PointerInfo } from "../Events/pointerEvents";
 import { LinesMesh } from "../Meshes/linesMesh";
+import { GizmoManager } from './gizmoManager';
 /**
  * Gizmo that enables dragging a mesh along 3 axis
  */
@@ -112,7 +113,7 @@ export class PositionGizmo extends Gizmo {
      * @param gizmoLayer The utility layer the gizmo will be added to
       @param thickness display gizmo axis thickness
      */
-    constructor(gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, thickness: number = 1) {
+    constructor(gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, thickness: number = 1, gizmoManager?: GizmoManager) {
         super(gizmoLayer);
         this.xGizmo = new AxisDragGizmo(new Vector3(1, 0, 0), Color3.Red().scale(0.5), gizmoLayer, this, thickness);
         this.yGizmo = new AxisDragGizmo(new Vector3(0, 1, 0), Color3.Green().scale(0.5), gizmoLayer, this, thickness);
@@ -132,7 +133,13 @@ export class PositionGizmo extends Gizmo {
         });
 
         this.attachedMesh = null;
-        this._subscribeToPointerObserver();
+
+        if (gizmoManager) {
+            gizmoManager.addToAxisCache(this._gizmoAxisCache);
+        } else {
+            // Only subscribe to pointer event if gizmoManager isnt
+            Gizmo.GizmoAxisPointerObserver(gizmoLayer, this._gizmoAxisCache);
+        }
     }
 
     /**
@@ -211,68 +218,6 @@ export class PositionGizmo extends Gizmo {
     }
 
     /**
-     * Subscribes to pointer up, down, and hover events. Used for responsive gizmos.
-     */
-    public _subscribeToPointerObserver(): void {
-        const pointerObserver = this.gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
-            if (pointerInfo.pickInfo) {
-                // On Hover Logic
-                if (pointerInfo.type === PointerEventTypes.POINTERMOVE) {
-                    if (this._dragging) { return; }
-                    this._gizmoAxisCache.forEach((cache) => {
-                        if (cache.colliderMeshes && cache.gizmoMeshes) {
-                            const isHovered = (cache.colliderMeshes?.indexOf((pointerInfo?.pickInfo?.pickedMesh as Mesh)) != -1);
-                            const material = isHovered || cache.active ? cache.hoverMaterial : cache.material;
-                            cache.gizmoMeshes.forEach((m: Mesh) => {
-                                m.material = material;
-                                if ((m as LinesMesh).color) {
-                                    (m as LinesMesh).color = material.diffuseColor;
-                                }
-                            });
-                        }
-                    });
-                }
-
-                // On Mouse Down
-                if (pointerInfo.type === PointerEventTypes.POINTERDOWN) {
-                    // If user Clicked Gizmo
-                    if (this._gizmoAxisCache.has(pointerInfo.pickInfo.pickedMesh?.parent as Mesh)) {
-                        this._dragging = true;
-                        const statusMap = this._gizmoAxisCache.get(pointerInfo.pickInfo.pickedMesh?.parent as Mesh);
-                        statusMap!.active = true;
-                        this._gizmoAxisCache.forEach((cache) => {
-                            const isHovered = (cache.colliderMeshes?.indexOf((pointerInfo?.pickInfo?.pickedMesh as Mesh)) != -1);
-                            const material = isHovered || cache.active ? cache.hoverMaterial : cache.disableMaterial;
-                            cache.gizmoMeshes.forEach((m: Mesh) => {
-                                m.material = material;
-                                if ((m as LinesMesh).color) {
-                                    (m as LinesMesh).color = material.diffuseColor;
-                                }
-                            });
-                        });
-                    }
-                }
-
-                // On Mouse Up
-                if (pointerInfo.type === PointerEventTypes.POINTERUP) {
-                    this._gizmoAxisCache.forEach((cache) => {
-                        cache.active = false;
-                        this._dragging = false;
-                        cache.gizmoMeshes.forEach((m: Mesh) => {
-                            m.material = cache.material;
-                            if ((m as LinesMesh).color) {
-                                (m as LinesMesh).color = cache.material.diffuseColor;
-                            }
-                        });
-                    });
-                }
-            }
-        });
-
-        this._observables = [pointerObserver!];
-    }
-
-    /**
      * Disposes of the gizmo
      */
     public dispose() {

+ 9 - 64
src/Gizmos/rotationGizmo.ts

@@ -12,6 +12,7 @@ import { Node } from "../node";
 import { PointerEventTypes, PointerInfo } from "../Events/pointerEvents";
 import { LinesMesh } from "../Meshes/linesMesh";
 import { TransformNode } from "../Meshes/transformNode";
+import { GizmoManager } from './gizmoManager';
 /**
  * Gizmo that enables rotating a mesh along 3 axis
  */
@@ -101,7 +102,7 @@ export class RotationGizmo extends Gizmo {
      * @param useEulerRotation Use and update Euler angle instead of quaternion
      * @param thickness display gizmo axis thickness
      */
-    constructor(gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, tessellation = 32, useEulerRotation = false, thickness: number = 1) {
+    constructor(gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, tessellation = 32, useEulerRotation = false, thickness: number = 1, gizmoManager?: GizmoManager) {
         super(gizmoLayer);
         this.xGizmo = new PlaneRotationGizmo(new Vector3(1, 0, 0), Color3.Red().scale(0.5), gizmoLayer, tessellation, this, useEulerRotation, thickness);
         this.yGizmo = new PlaneRotationGizmo(new Vector3(0, 1, 0), Color3.Green().scale(0.5), gizmoLayer, tessellation, this, useEulerRotation, thickness);
@@ -119,7 +120,13 @@ export class RotationGizmo extends Gizmo {
 
         this.attachedMesh = null;
         this.attachedNode = null;
-        this._subscribeToPointerObserver();
+
+        if (gizmoManager) {
+            gizmoManager.addToAxisCache(this._gizmoAxisCache);
+        } else {
+            // Only subscribe to pointer event if gizmoManager isnt
+            Gizmo.GizmoAxisPointerObserver(gizmoLayer, this._gizmoAxisCache);
+        }
     }
 
     public set updateGizmoRotationToMatchAttachedMesh(value: boolean) {
@@ -170,68 +177,6 @@ export class RotationGizmo extends Gizmo {
     }
 
     /**
-     * Subscribes to pointer up, down, and hover events. Used for responsive gizmos.
-     */
-    public _subscribeToPointerObserver(): void {
-        const pointerObserver = this.gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
-            if (pointerInfo.pickInfo) {
-                // On Hover Logic
-                if (pointerInfo.type === PointerEventTypes.POINTERMOVE) {
-                    if (this._dragging) { return; }
-                    this._gizmoAxisCache.forEach((cache) => {
-                        if (cache.colliderMeshes && cache.gizmoMeshes) {
-                            const isHovered = (cache.colliderMeshes?.indexOf((pointerInfo?.pickInfo?.pickedMesh as Mesh)) != -1);
-                            const material = isHovered || cache.active ? cache.hoverMaterial : cache.material;
-                            cache.gizmoMeshes.forEach((m: Mesh) => {
-                                m.material = material;
-                                if ((m as LinesMesh).color) {
-                                    (m as LinesMesh).color = material.diffuseColor;
-                                }
-                            });
-                        }
-                    });
-                }
-
-                // On Mouse Down
-                if (pointerInfo.type === PointerEventTypes.POINTERDOWN) {
-                    // If user Clicked Gizmo
-                    if (this._gizmoAxisCache.has(pointerInfo.pickInfo.pickedMesh?.parent as Mesh)) {
-                        this._dragging = true;
-                        const statusMap = this._gizmoAxisCache.get(pointerInfo.pickInfo.pickedMesh?.parent as Mesh);
-                        statusMap!.active = true;
-                        this._gizmoAxisCache.forEach((cache) => {
-                            const isHovered = (cache.colliderMeshes?.indexOf((pointerInfo?.pickInfo?.pickedMesh as Mesh)) != -1);
-                            const material = isHovered || cache.active ? cache.hoverMaterial : cache.disableMaterial;
-                            cache.gizmoMeshes.forEach((m: Mesh) => {
-                                m.material = material;
-                                if ((m as LinesMesh).color) {
-                                    (m as LinesMesh).color = material.diffuseColor;
-                                }
-                            });
-                        });
-                    }
-                }
-
-                // On Mouse Up
-                if (pointerInfo.type === PointerEventTypes.POINTERUP) {
-                    this._gizmoAxisCache.forEach((cache) => {
-                        cache.active = false;
-                        this._dragging = false;
-                        cache.gizmoMeshes.forEach((m: Mesh) => {
-                            m.material = cache.material;
-                            if ((m as LinesMesh).color) {
-                                (m as LinesMesh).color = cache.material.diffuseColor;
-                            }
-                        });
-                    });
-                }
-            }
-        });
-
-        this._observables = [pointerObserver!];
-    }
-
-    /**
      * Disposes of the gizmo
      */
     public dispose() {

+ 9 - 63
src/Gizmos/scaleGizmo.ts

@@ -13,6 +13,7 @@ import { Node } from "../node";
 import { PointerEventTypes, PointerInfo } from "../Events/pointerEvents";
 import { LinesMesh } from "../Meshes/linesMesh";
 import { StandardMaterial } from "../Materials/standardMaterial";
+import { GizmoManager } from './gizmoManager';
 /**
  * Gizmo that enables scaling a mesh along 3 axis
  */
@@ -104,7 +105,7 @@ export class ScaleGizmo extends Gizmo {
      * @param gizmoLayer The utility layer the gizmo will be added to
      * @param thickness display gizmo axis thickness
      */
-    constructor(gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, thickness: number = 1) {
+    constructor(gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, thickness: number = 1, gizmoManager?: GizmoManager) {
         super(gizmoLayer);
         this.uniformScaleGizmo = this._createUniformScaleMesh();
         this.xGizmo = new AxisScaleGizmo(new Vector3(1, 0, 0), Color3.Red().scale(0.5), gizmoLayer, this, thickness);
@@ -123,7 +124,13 @@ export class ScaleGizmo extends Gizmo {
 
         this.attachedMesh = null;
         this.attachedNode = null;
-        this._subscribeToPointerObserver();
+
+        if (gizmoManager) {
+            gizmoManager.addToAxisCache(this._gizmoAxisCache);
+        } else {
+            // Only subscribe to pointer event if gizmoManager isnt
+            Gizmo.GizmoAxisPointerObserver(gizmoLayer, this._gizmoAxisCache);
+        }
     }
 
     /** Create Geometry for Gizmo */
@@ -237,67 +244,6 @@ export class ScaleGizmo extends Gizmo {
     }
 
     /**
-     * Subscribes to pointer up, down, and hover events. Used for responsive gizmos.
-     */
-    public _subscribeToPointerObserver(): void {
-        const pointerObserver = this.gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
-            if (pointerInfo.pickInfo) {
-                // On Hover Logic
-                if (pointerInfo.type === PointerEventTypes.POINTERMOVE) {
-                    if (this._dragging) { return; }
-                    this._gizmoAxisCache.forEach((cache) => {
-                        if (cache.colliderMeshes && cache.gizmoMeshes) {
-                            const isHovered = (cache.colliderMeshes?.indexOf((pointerInfo?.pickInfo?.pickedMesh as Mesh)) != -1);
-                            const material = isHovered || cache.active ? cache.hoverMaterial : cache.material;
-                            cache.gizmoMeshes.forEach((m: Mesh) => {
-                                m.material = material;
-                                if ((m as LinesMesh).color) {
-                                    (m as LinesMesh).color = material.diffuseColor;
-                                }
-                            });
-                        }
-                    });
-                }
-
-                // On Mouse Down
-                if (pointerInfo.type === PointerEventTypes.POINTERDOWN) {
-                    // If user Clicked Gizmo
-                    if (this._gizmoAxisCache.has(pointerInfo.pickInfo.pickedMesh?.parent as Mesh)) {
-                        this._dragging = true;
-                        const statusMap = this._gizmoAxisCache.get(pointerInfo.pickInfo.pickedMesh?.parent as Mesh);
-                        statusMap!.active = true;
-                        this._gizmoAxisCache.forEach((cache) => {
-                            const isHovered = (cache.colliderMeshes?.indexOf((pointerInfo?.pickInfo?.pickedMesh as Mesh)) != -1);
-                            const material = isHovered || cache.active ? cache.hoverMaterial : cache.disableMaterial;
-                            cache.gizmoMeshes.forEach((m: Mesh) => {
-                                m.material = material;
-                                if ((m as LinesMesh).color) {
-                                    (m as LinesMesh).color = material.diffuseColor;
-                                }
-                            });
-                        });
-                    }
-                }
-
-                // On Mouse Up
-                if (pointerInfo.type === PointerEventTypes.POINTERUP) {
-                    this._gizmoAxisCache.forEach((cache) => {
-                        cache.active = false;
-                        this._dragging = false;
-                        cache.gizmoMeshes.forEach((m: Mesh) => {
-                            m.material = cache.material;
-                            if ((m as LinesMesh).color) {
-                                (m as LinesMesh).color = cache.material.diffuseColor;
-                            }
-                        });
-                    });
-                }
-            }
-        });
-        this._observables = [pointerObserver!];
-    }
-
-    /**
      * Disposes of the gizmo
      */
     public dispose() {