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

add position gizmo and update drag behavior to use prePointerObservable

Trevor Baron пре 7 година
родитељ
комит
aa06d818e6
3 измењених фајлова са 137 додато и 24 уклоњено
  1. 2 1
      Tools/Gulp/config.json
  2. 40 23
      src/Behaviors/Mesh/babylon.pointerDragBehavior.ts
  3. 95 0
      src/Gizmos/babylon.gizmo.ts

+ 2 - 1
Tools/Gulp/config.json

@@ -1021,7 +1021,8 @@
                 "../../src/Debug/babylon.debugLayer.js",
                 "../../src/Debug/babylon.physicsViewer.js",
                 "../../src/Rendering/babylon.boundingBoxRenderer.js",
-                "../../src/Rendering/babylon.utilityLayerRenderer.js"
+                "../../src/Rendering/babylon.utilityLayerRenderer.js",
+                "../../src/Gizmos/babylon.gizmo.js"
             ],
             "dependUpon": [
                 "shaderMaterial",

+ 40 - 23
src/Behaviors/Mesh/babylon.pointerDragBehavior.ts

@@ -6,7 +6,7 @@ module BABYLON {
         private _attachedNode: Node; 
         private _dragPlane: Mesh;
         private _scene:Scene;
-        private _pointerObserver:Nullable<Observer<PointerInfo>>;
+        private _pointerObserver:Nullable<Observer<PointerInfoPre>>;
         private static _planeScene:Scene;
         private _draggingID = -1;
         
@@ -33,9 +33,9 @@ module BABYLON {
         
         /**
          * Creates a pointer drag behavior that can be attached to a mesh
-         * @param options The drag axis or normal of the plane that will be dragged accross
+         * @param options The drag axis or normal of the plane that will be dragged accross. pointerObservableScene can be used to listen to drag events from anther scene(eg. if the attached mesh is in an overlay scene).
          */
-        constructor(private options:{dragAxis?:Vector3, dragPlaneNormal?:Vector3}){
+        constructor(private options:{dragAxis?:Vector3, dragPlaneNormal?:Vector3, pointerObservableScene?:Scene}){
             var optionCount = 0;
             if(options.dragAxis){
                 optionCount++;
@@ -69,6 +69,9 @@ module BABYLON {
          */
         public attach(ownerNode: Mesh): void {
             this._scene = ownerNode.getScene();
+            if(!this.options.pointerObservableScene){
+                this.options.pointerObservableScene = this._scene;
+            }
             this._attachedNode = ownerNode;
 
             // Initialize drag plane to not interfere with existing scene
@@ -79,34 +82,48 @@ module BABYLON {
             this._dragPlane = BABYLON.Mesh.CreatePlane("pointerDragPlane", 1000, PointerDragBehavior._planeScene, false, BABYLON.Mesh.DOUBLESIDE);
 
             // State of the drag
-            var dragging = false
+            var dragging = false;
             var lastPosition = new BABYLON.Vector3(0,0,0);
             var delta = new BABYLON.Vector3(0,0,0);
 
-            this._pointerObserver = this._scene.onPointerObservable.add((pointerInfo)=>{
-                if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERDOWN) {
-                    if(!dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.hit && pointerInfo.pickInfo.pickedMesh && pointerInfo.pickInfo.ray){
-                        if(this._attachedNode == pointerInfo.pickInfo.pickedMesh){
-                            this._updateDragPlanePosition(pointerInfo.pickInfo.ray);
-                            var pickedPoint = this._pickWithRayOnDragPlane(pointerInfo.pickInfo.ray)
-                            if(pickedPoint){
-                                dragging = true;
-                                this._draggingID = (<PointerEvent>pointerInfo.event).pointerId;
-                                lastPosition.copyFrom(pickedPoint);
-                                this.onDragStartObservable.notifyObservers({dragPlanePoint: pickedPoint});
-                            }
+            var pickPredicate = (m:AbstractMesh)=>{
+                return this._attachedNode == m || m.isDescendantOf(this._attachedNode)
+            }
+
+            this._pointerObserver = this.options.pointerObservableScene!.onPrePointerObservable.add((pointerInfoPre, eventState)=>{
+                // Check if attached mesh is picked
+                var pickInfo = pointerInfoPre.ray ? this._scene.pickWithRay(pointerInfoPre.ray, pickPredicate) : this._scene.pick(this._scene.pointerX, this._scene.pointerY, pickPredicate);
+                if(pickInfo){
+                    pickInfo.ray = pointerInfoPre.ray;
+                    if(!pickInfo.ray){
+                        pickInfo.ray = this.options.pointerObservableScene!.createPickingRay(this._scene.pointerX, this._scene.pointerY, Matrix.Identity(), this._scene.activeCamera);
+                    }
+                    if(pickInfo.hit){
+                        eventState.skipNextObservers = true;
+                    }
+                }
+                
+                if (pointerInfoPre.type == BABYLON.PointerEventTypes.POINTERDOWN) {
+                    if(!dragging && pickInfo && pickInfo.hit && pickInfo.pickedMesh && pickInfo.ray){
+                        this._updateDragPlanePosition(pickInfo.ray);
+                        var pickedPoint = this._pickWithRayOnDragPlane(pickInfo.ray);
+                        if(pickedPoint){
+                            dragging = true;
+                            this._draggingID = (<PointerEvent>pointerInfoPre.event).pointerId;
+                            lastPosition.copyFrom(pickedPoint);
+                            this.onDragStartObservable.notifyObservers({dragPlanePoint: pickedPoint});
                         }
                     }
-                }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERUP){
-                    if(this._draggingID == (<PointerEvent>pointerInfo.event).pointerId){
+                }else if(pointerInfoPre.type == BABYLON.PointerEventTypes.POINTERUP){
+                    if(this._draggingID == (<PointerEvent>pointerInfoPre.event).pointerId){
                         dragging = false;
                         this._draggingID = -1;
                         this.onDragEndObservable.notifyObservers({dragPlanePoint: lastPosition});
                     }
-                }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE){
-                    if(this._draggingID == (<PointerEvent>pointerInfo.event).pointerId && dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.ray){
-                        var pickedPoint = this._pickWithRayOnDragPlane(pointerInfo.pickInfo.ray)
-                        this._updateDragPlanePosition(pointerInfo.pickInfo.ray);
+                }else if(pointerInfoPre.type == BABYLON.PointerEventTypes.POINTERMOVE){
+                    if(this._draggingID == (<PointerEvent>pointerInfoPre.event).pointerId && dragging && pickInfo && pickInfo.ray){
+                        var pickedPoint = this._pickWithRayOnDragPlane(pickInfo.ray)
+                        this._updateDragPlanePosition(pickInfo.ray);
                         if (pickedPoint) {
                             // depending on the drag mode option drag accordingly
                             if(this.options.dragAxis){
@@ -170,7 +187,7 @@ module BABYLON {
          */
         public detach(): void {
             if(this._pointerObserver){
-                this._scene.onPointerObservable.remove(this._pointerObserver);
+                this._scene.onPrePointerObservable.remove(this._pointerObserver);
             }
         }
     }

+ 95 - 0
src/Gizmos/babylon.gizmo.ts

@@ -0,0 +1,95 @@
+module BABYLON {
+    /**
+     * Renders gizmos on top of an existing scene which provide controls for position, rotation, etc.
+     */
+    export class Gizmo implements IDisposable {
+        protected _rootMesh:Mesh;
+        public attachedMesh:Nullable<Mesh>;
+        private _beforeRenderObserver:Nullable<Observer<Scene>>;
+        constructor(public gizmoLayer:UtilityLayerRenderer){
+            this._rootMesh = new BABYLON.Mesh("gizmoRootNode",gizmoLayer.utilityLayerScene);
+            this._beforeRenderObserver = this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.add(()=>{
+                if(this.gizmoLayer.utilityLayerScene.activeCamera && this.attachedMesh){
+                    var dist = this.attachedMesh.position.subtract(this.gizmoLayer.utilityLayerScene.activeCamera.position).length()/5;
+                    this._rootMesh.scaling.set(dist, dist, dist);
+                }
+                if(this.attachedMesh){
+                    this._rootMesh.position.copyFrom(this.attachedMesh.position);
+                }
+            })
+        }
+        public dispose(){
+            this._rootMesh.dispose()
+            if(this._beforeRenderObserver){
+                this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.remove(this._beforeRenderObserver);
+            }
+        }
+    }
+
+    export class AxisDragGizmo extends Gizmo {
+        private _dragBehavior:PointerDragBehavior;
+        constructor(gizmoLayer:UtilityLayerRenderer, dragAxis:Vector3, color:Color3){
+            super(gizmoLayer);
+
+            // Create Material
+            var coloredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
+            coloredMaterial.disableLighting = true;
+            coloredMaterial.emissiveColor = color;
+
+            // Build mesh on root node
+            var arrowMesh = BABYLON.MeshBuilder.CreateCylinder("yPosMesh", {diameterTop:0, height: 2, tessellation: 96}, gizmoLayer.utilityLayerScene);
+            var arrowTail = BABYLON.MeshBuilder.CreateCylinder("yPosMesh", {diameter:0.03, height: 0.2, tessellation: 96}, gizmoLayer.utilityLayerScene);
+            this._rootMesh.addChild(arrowMesh);
+            this._rootMesh.addChild(arrowTail);
+
+            // Position arrow pointing in its drag axis
+            arrowMesh.scaling.scaleInPlace(0.1);
+            arrowMesh.material = coloredMaterial;
+            arrowMesh.rotation.x = Math.PI/2;
+            arrowMesh.position.z+=0.3;
+            arrowTail.rotation.x = Math.PI/2;
+            arrowTail.material = coloredMaterial;
+            arrowTail.position.z+=0.2;
+            this._rootMesh.lookAt(this._rootMesh.position.subtract(dragAxis));
+
+            // Add drag behavior to handle events when the gizmo is dragged
+            this._dragBehavior = new PointerDragBehavior({dragAxis: dragAxis, pointerObservableScene: gizmoLayer.originalScene});
+            this._dragBehavior.moveAttached = false;
+            this._rootMesh.addBehavior(this._dragBehavior);
+            this._dragBehavior.onDragObservable.add((event)=>{
+                if(this.attachedMesh){
+                    this.attachedMesh.position.addInPlace(event.delta);
+                }
+            })
+        }
+        public dispose(){
+            this._dragBehavior.detach();
+            super.dispose();
+        } 
+    }
+
+    export class PositionGizmo extends Gizmo {
+        private _xDrag:AxisDragGizmo;
+        private _yDrag:AxisDragGizmo;
+        private _zDrag:AxisDragGizmo;
+
+        public set attachedMesh(mesh:Nullable<Mesh>){
+            this._xDrag.attachedMesh = mesh;
+            this._yDrag.attachedMesh = mesh;
+            this._zDrag.attachedMesh = mesh;
+        }
+
+        constructor(gizmoLayer:UtilityLayerRenderer){
+            super(gizmoLayer);
+            this._xDrag = new AxisDragGizmo(gizmoLayer, new Vector3(1,0,0), BABYLON.Color3.FromHexString("#00b894"));
+            this._yDrag = new AxisDragGizmo(gizmoLayer, new Vector3(0,1,0), BABYLON.Color3.FromHexString("#d63031"));
+            this._zDrag = new AxisDragGizmo(gizmoLayer, new Vector3(0,0,1), BABYLON.Color3.FromHexString("#0984e3"));
+        }
+
+        public dispose(){
+            this._xDrag.dispose();
+            this._yDrag.dispose();
+            this._zDrag.dispose();
+        }
+    }
+}