Bläddra i källkod

Merge pull request #4357 from TrevorDev/addPositionGizmo

add position gizmo and update drag behavior to use prePointerObservable
David Catuhe 7 år sedan
förälder
incheckning
be2a7c3b2e

+ 4 - 1
Tools/Gulp/config.json

@@ -1021,7 +1021,10 @@
                 "../../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",
+                "../../src/Gizmos/babylon.axisDragGizmo.js",
+                "../../src/Gizmos/babylon.positionGizmo.js"
             ],
             "dependUpon": [
                 "shaderMaterial",

+ 1 - 0
dist/preview release/what's new.md

@@ -22,6 +22,7 @@
 - UtilityLayer class to render another scene as a layer on top of an existing scene ([TrevorDev](https://github.com/TrevorDev))
 - AnimationGroup has now onAnimationGroupEnd observable ([RaananW](https://github.com/RaananW))
 - Pointer drag behavior to enable drag and drop with mouse or 6dof controller on a mesh ([TrevorDev](https://github.com/TrevorDev))
+- Gizmo class used to manipulate meshes in a scene, position gizmo ([TrevorDev](https://github.com/TrevorDev))
 
 ### glTF Loader
 

+ 1 - 1
gui/src/3D/gui3DManager.ts

@@ -71,7 +71,7 @@ module BABYLON.GUI {
             new BABYLON.HemisphericLight("hemi", Vector3.Up(), this._utilityLayer.utilityLayerScene);
         }
 
-        private _doPicking(type: number, pointerEvent: PointerEvent, ray?:Ray): boolean {
+        private _doPicking(type: number, pointerEvent: PointerEvent, ray?:Nullable<Ray>): boolean {
             if (!this._utilityLayer || !this._utilityLayer.utilityLayerScene.activeCamera) {
                 return false;                
             }

+ 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 across. pointerObservableScene can be used to listen to drag events from another 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);
             }
         }
     }

+ 55 - 0
src/Gizmos/babylon.axisDragGizmo.ts

@@ -0,0 +1,55 @@
+module BABYLON {
+    /**
+     * Single axis drag gizmo
+     */
+    export class AxisDragGizmo extends Gizmo {
+        private _dragBehavior:PointerDragBehavior;
+        /**
+         * Creates an AxisDragGizmo
+         * @param gizmoLayer The utility layer the gizmo will be added to
+         * @param dragAxis The axis which the gizmo will be able to drag on
+         * @param color The color of the gizmo
+         */
+        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);
+                }
+            })
+        }
+        /**
+         * Disposes of the gizmo
+         */
+        public dispose(){
+            this._dragBehavior.detach();
+            super.dispose();
+        } 
+    }
+}

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

@@ -0,0 +1,41 @@
+module BABYLON {
+    /**
+     * Renders gizmos on top of an existing scene which provide controls for position, rotation, etc.
+     */
+    export class Gizmo implements IDisposable {
+        /**
+         * The root mesh of the gizmo
+         */
+        protected _rootMesh:Mesh;
+        /**
+         * Mesh that the gizmo will be attached to. (eg. on a drag gizmo the mesh that will be dragged)
+         */
+        public attachedMesh:Nullable<Mesh>;
+        private _beforeRenderObserver:Nullable<Observer<Scene>>;
+        /**
+         * Creates a gizmo
+         * @param gizmoLayer The utility layer the gizmo will be added to
+         */
+        constructor(/** The utility layer the gizmo will be added to */ 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);
+                }
+            })
+        }
+        /**
+         * Disposes of the gizmo
+         */
+        public dispose(){
+            this._rootMesh.dispose()
+            if(this._beforeRenderObserver){
+                this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.remove(this._beforeRenderObserver);
+            }
+        }
+    }
+}

+ 35 - 0
src/Gizmos/babylon.positionGizmo.ts

@@ -0,0 +1,35 @@
+module BABYLON {
+    /**
+     * Gizmo that enables dragging a mesh along 3 axis
+     */
+    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;
+        }
+        /**
+         * Creates a PositionGizmo
+         * @param gizmoLayer The utility layer the gizmo will be added to
+         */
+        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"));
+        }
+
+        /**
+         * Disposes of the gizmo
+         */
+        public dispose(){
+            this._xDrag.dispose();
+            this._yDrag.dispose();
+            this._zDrag.dispose();
+        }
+    }
+}