浏览代码

Gizmo Mesh Upgrade - Position Gizmo Updates

Dave Gould 4 年之前
父节点
当前提交
b1bec68ecd
共有 3 个文件被更改,包括 146 次插入44 次删除
  1. 45 31
      src/Gizmos/axisDragGizmo.ts
  2. 14 12
      src/Gizmos/planeDragGizmo.ts
  3. 87 1
      src/Gizmos/positionGizmo.ts

+ 45 - 31
src/Gizmos/axisDragGizmo.ts

@@ -5,7 +5,6 @@ import { Vector3 } from "../Maths/math.vector";
 import { TransformNode } from "../Meshes/transformNode";
 import { Node } from "../node";
 import { Mesh } from "../Meshes/mesh";
-import { LinesMesh } from "../Meshes/linesMesh";
 import { CylinderBuilder } from "../Meshes/Builders/cylinderBuilder";
 import { PointerDragBehavior } from "../Behaviors/Meshes/pointerDragBehavior";
 import { Gizmo } from "./gizmo";
@@ -36,25 +35,34 @@ export class AxisDragGizmo extends Gizmo {
     private _isEnabled: boolean = true;
     private _parent: Nullable<PositionGizmo> = null;
 
-    private _arrow: TransformNode;
+    private _gizmoMesh: Mesh;
     private _coloredMaterial: StandardMaterial;
     private _hoverMaterial: StandardMaterial;
+    private _disableMaterial: StandardMaterial;
 
     /** @hidden */
-    public static _CreateArrow(scene: Scene, material: StandardMaterial, thickness: number = 1): TransformNode {
-        var arrow = new TransformNode("arrow", scene);
+    public static _CreateArrow(scene: Scene, material: StandardMaterial, thickness: number = 1, isCollider = false): Mesh {
+        var arrow = new Mesh("arrow", scene);
         var cylinder = CylinderBuilder.CreateCylinder("cylinder", { diameterTop: 0, height: 0.075, diameterBottom: 0.0375 * (1 + (thickness - 1) / 4), tessellation: 96 }, scene);
         var line = CylinderBuilder.CreateCylinder("cylinder", { diameterTop: 0.005 * thickness, height: 0.275, diameterBottom: 0.005 * thickness, tessellation: 96 }, scene);
-        line.material = material;
-        cylinder.parent = arrow;
-        line.parent = arrow;
 
         // Position arrow pointing in its drag axis
+        cylinder.parent = arrow;
         cylinder.material = material;
         cylinder.rotation.x = Math.PI / 2;
         cylinder.position.z += 0.3;
+        
+        line.parent = arrow;
+        line.material = material;
         line.position.z += 0.275 / 2;
         line.rotation.x = Math.PI / 2;
+
+        if (isCollider) {
+            line.name = 'ignore';
+            line.visibility = 0;
+            cylinder.name = 'ignore';
+            cylinder.visibility = 0;
+        }
         return arrow;
     }
 
@@ -78,20 +86,32 @@ export class AxisDragGizmo extends Gizmo {
     constructor(dragAxis: Vector3, color: Color3 = Color3.Gray(), gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, parent: Nullable<PositionGizmo> = null, thickness: number = 1) {
         super(gizmoLayer);
         this._parent = parent;
+
         // Create Material
         this._coloredMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
         this._coloredMaterial.diffuseColor = color;
         this._coloredMaterial.specularColor = color.subtract(new Color3(0.1, 0.1, 0.1));
 
         this._hoverMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
-        this._hoverMaterial.diffuseColor = color.add(new Color3(0.3, 0.3, 0.3));
-
-        // Build mesh on root node
-        this._arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, this._coloredMaterial, thickness);
+        this._hoverMaterial.diffuseColor = Color3.Yellow();
+
+        this._disableMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
+        this._disableMaterial.diffuseColor = Color3.Gray();
+        this._disableMaterial.alpha = 0.4;
+
+        // Build Mesh + Collider
+        const arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, this._coloredMaterial, thickness);
+        const collider = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, this._coloredMaterial, thickness * 4, true);
+        
+        // Add to Root Node
+        this._gizmoMesh = new Mesh("", gizmoLayer.utilityLayerScene);
+        [...arrow.getChildMeshes(), ...collider.getChildMeshes()].forEach(mesh => {
+            this._gizmoMesh.addChild(mesh);
+        });
 
-        this._arrow.lookAt(this._rootMesh.position.add(dragAxis));
-        this._arrow.scaling.scaleInPlace(1 / 3);
-        this._arrow.parent = this._rootMesh;
+        this._gizmoMesh.lookAt(this._rootMesh.position.add(dragAxis));
+        this._gizmoMesh.scaling.scaleInPlace(1 / 3);
+        this._gizmoMesh.parent = this._rootMesh;
 
         var currentSnapDragDistance = 0;
         var tmpVector = new Vector3();
@@ -133,22 +153,16 @@ export class AxisDragGizmo extends Gizmo {
             }
         });
 
-        this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
-            if (this._customMeshSet) {
-                return;
-            }
-            this._isHovered = !!(pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1));
-            var material = this._isHovered ? this._hoverMaterial : this._coloredMaterial;
-            this._rootMesh.getChildMeshes().forEach((m) => {
-                m.material = material;
-                if ((<LinesMesh>m).color) {
-                    (<LinesMesh>m).color = material.diffuseColor;
-                }
-            });
-        });
-
         var light = gizmoLayer._getSharedGizmoLight();
         light.includedOnlyMeshes = light.includedOnlyMeshes.concat(this._rootMesh.getChildMeshes(false));
+
+        const cache: any = {
+            material: this._coloredMaterial,
+            hoverMaterial: this._hoverMaterial,
+            disableMaterial: this._disableMaterial,
+            active: false
+        };
+        this._parent?.addToAxisCache((this._gizmoMesh as Mesh), cache);
     }
     protected _attachedNodeChanged(value: Nullable<Node>) {
         if (this.dragBehavior) {
@@ -183,10 +197,10 @@ export class AxisDragGizmo extends Gizmo {
         this.onSnapObservable.clear();
         this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
         this.dragBehavior.detach();
-        if (this._arrow) {
-            this._arrow.dispose();
+        if (this._gizmoMesh) {
+            this._gizmoMesh.dispose();
         }
-        [this._coloredMaterial, this._hoverMaterial].forEach((matl) => {
+        [this._coloredMaterial, this._hoverMaterial, this._disableMaterial].forEach((matl) => {
             if (matl) {
                 matl.dispose();
             }

+ 14 - 12
src/Gizmos/planeDragGizmo.ts

@@ -35,6 +35,7 @@ export class PlaneDragGizmo extends Gizmo {
     private _plane: TransformNode;
     private _coloredMaterial: StandardMaterial;
     private _hoverMaterial: StandardMaterial;
+    private _disableMaterial: StandardMaterial;
 
     private _isEnabled: boolean = false;
     private _parent: Nullable<PositionGizmo> = null;
@@ -75,7 +76,11 @@ export class PlaneDragGizmo extends Gizmo {
         this._coloredMaterial.specularColor = color.subtract(new Color3(0.1, 0.1, 0.1));
 
         this._hoverMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
-        this._hoverMaterial.diffuseColor = color.add(new Color3(0.3, 0.3, 0.3));
+        this._hoverMaterial.diffuseColor = Color3.Yellow();
+        
+        this._disableMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
+        this._disableMaterial.diffuseColor = Color3.Gray();
+        this._disableMaterial.alpha = 0.4;
 
         // Build plane mesh on root node
         this._plane = PlaneDragGizmo._CreatePlane(gizmoLayer.utilityLayerScene, this._coloredMaterial);
@@ -117,19 +122,16 @@ export class PlaneDragGizmo extends Gizmo {
             }
         });
 
-        this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
-            if (this._customMeshSet) {
-                return;
-            }
-            this._isHovered = !!(pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1));
-            var material = this._isHovered ? this._hoverMaterial : this._coloredMaterial;
-            this._rootMesh.getChildMeshes().forEach((m) => {
-                m.material = material;
-            });
-        });
-
         var light = gizmoLayer._getSharedGizmoLight();
         light.includedOnlyMeshes = light.includedOnlyMeshes.concat(this._rootMesh.getChildMeshes(false));
+
+        const cache: any = {
+            material: this._coloredMaterial,
+            hoverMaterial: this._hoverMaterial,
+            disableMaterial: this._disableMaterial,
+            active: false
+        };
+        this._parent?.addToAxisCache((this._plane as Mesh), cache);
     }
     protected _attachedNodeChanged(value: Nullable<Node>) {
         if (this.dragBehavior) {

+ 87 - 1
src/Gizmos/positionGizmo.ts

@@ -1,5 +1,5 @@
 import { Logger } from "../Misc/logger";
-import { Observable } from "../Misc/observable";
+import { Observable, Observer } from "../Misc/observable";
 import { Nullable } from "../types";
 import { Vector3 } from "../Maths/math.vector";
 import { Color3 } from '../Maths/math.color';
@@ -10,6 +10,8 @@ import { Gizmo } from "./gizmo";
 import { AxisDragGizmo } from "./axisDragGizmo";
 import { PlaneDragGizmo } from "./planeDragGizmo";
 import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
+import { PointerEventTypes, PointerInfo } from "../Events/pointerEvents";
+import { LinesMesh } from "../Meshes/linesMesh";
 /**
  * Gizmo that enables dragging a mesh along 3 axis
  */
@@ -45,6 +47,12 @@ export class PositionGizmo extends Gizmo {
     private _meshAttached: Nullable<AbstractMesh> = null;
     private _nodeAttached: Nullable<Node> = null;
     private _snapDistance: number;
+    private _observables: Nullable<Observer<PointerInfo>>[] = [];
+
+    /** Gizmo state variables used for UI behavior */
+    private dragging = false;
+    /** Node Caching for quick lookup */
+    private gizmoAxisCache: Map<Mesh, any> = new Map();
 
     /** Fires an event when any of it's sub gizmos are dragged */
     public onDragStartObservable = new Observable();
@@ -124,6 +132,7 @@ export class PositionGizmo extends Gizmo {
         });
 
         this.attachedMesh = null;
+        this.subscribeToPointerObserver();
     }
 
     /**
@@ -193,6 +202,80 @@ export class PositionGizmo extends Gizmo {
     }
 
     /**
+     * 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(mesh: Mesh, cache: any) {
+        this.gizmoAxisCache.set(mesh, cache);
+    }
+
+    public subscribeToPointerObserver(): void {
+        // Assumption, if user sets custom mesh, it will be disposed and pointerInfo will never hold reference to that mesh.
+        // Will be equivilent to if (this._customMeshSet) return;
+        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((statusMap, parentMesh) => {
+                        const isHovered = pointerInfo.pickInfo && (parentMesh.getChildMeshes().indexOf((pointerInfo.pickInfo.pickedMesh as Mesh)) != -1);
+                        const material = isHovered || statusMap.active ? statusMap.hoverMaterial : statusMap.material;
+                        parentMesh.getChildMeshes().forEach((m) => {
+                            if (m.name !== 'ignore') {
+                                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((statusMap, parentMesh) => {
+                            const isHovered = pointerInfo.pickInfo && (parentMesh.getChildMeshes().indexOf((pointerInfo.pickInfo.pickedMesh as Mesh)) != -1);
+                            const material = isHovered || statusMap.active ? statusMap.hoverMaterial : statusMap.disableMaterial;
+                            parentMesh.getChildMeshes().forEach((m) => {
+                                if (m.name !== 'ignore') {
+                                    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((statusMap, parentMesh) => {
+                        statusMap.active = false;
+                        this.dragging = false;
+                        parentMesh.getChildMeshes().forEach((m) => {
+                            if (m.name !== 'ignore') {
+                                m.material = statusMap.material;
+                                if ((m as LinesMesh).color) {
+                                    (m as LinesMesh).color = statusMap.material.diffuseColor;
+                                }
+                            }
+                        });
+                    });
+                }
+            }
+        });
+
+        this._observables = [pointerObserver];
+    }
+
+    /**
      * Disposes of the gizmo
      */
     public dispose() {
@@ -201,6 +284,9 @@ export class PositionGizmo extends Gizmo {
                 gizmo.dispose();
             }
         });
+        this._observables.forEach(obs => {
+            this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(obs);
+        });
         this.onDragStartObservable.clear();
         this.onDragEndObservable.clear();
     }