Browse Source

Merge pull request #4689 from TrevorDev/updateGizmoManager

Update gizmo manager
David Catuhe 7 năm trước cách đây
mục cha
commit
bddecdca0e

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

@@ -7,7 +7,7 @@
 - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
 - Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
 - New GUI control: the [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
-- Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, rotation, scale and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
+- Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, scale, rotation and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
 - New behaviors: PointerDragBehavior, SixDofDragBehavior and MultiPointerScaleBehavior to enable smooth drag and drop/scaling with mouse or 6dof controller on a mesh. [Doc](http://doc.babylonjs.com/how_to/meshbehavior) ([TrevorDev](https://github.com/TrevorDev))
 - Particle system improvements ([Deltakosh](https://github.com/deltakosh))
   - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style. [Doc](https://doc.babylonjs.com/How_To/ParticleHelper) ([Deltakosh](https://github.com/deltakosh)) / ([DevChris](https://github.com/yovanoc))

+ 12 - 4
src/Behaviors/Mesh/babylon.sixDofDragBehavior.ts

@@ -177,10 +177,18 @@ module BABYLON {
          *  Detaches the behavior from the mesh
          */
         public detach(): void {
-            this._scene.onPointerObservable.remove(this._pointerObserver);
-            this._ownerNode.getScene().onBeforeRenderObservable.remove(this._sceneRenderObserver);
-            this._virtualOriginMesh.dispose()
-            this._virtualDragMesh.dispose();
+            if(this._scene){
+                this._scene.onPointerObservable.remove(this._pointerObserver);
+            }
+            if(this._ownerNode){
+                this._ownerNode.getScene().onBeforeRenderObservable.remove(this._sceneRenderObserver);
+            }
+            if(this._virtualOriginMesh){
+                this._virtualOriginMesh.dispose();
+            }
+            if(this._virtualDragMesh){
+                this._virtualDragMesh.dispose();
+            }
         }
     }
 }

+ 5 - 1
src/Gizmos/babylon.gizmo.ts

@@ -74,7 +74,11 @@ module BABYLON {
                         this._rootMesh.position.copyFrom(this.attachedMesh.absolutePosition);
                     }
                     if(this._updateScale && this.gizmoLayer.utilityLayerScene.activeCamera && this.attachedMesh){
-                        this._rootMesh.position.subtractToRef(this.gizmoLayer.utilityLayerScene.activeCamera.position, tempVector);
+                        var cameraPosition = this.gizmoLayer.utilityLayerScene.activeCamera.position;
+                        if((<WebVRFreeCamera>this.gizmoLayer.utilityLayerScene.activeCamera).devicePosition){
+                            cameraPosition = (<WebVRFreeCamera>this.gizmoLayer.utilityLayerScene.activeCamera).devicePosition;
+                        }
+                        this._rootMesh.position.subtractToRef(cameraPosition, tempVector);
                         var dist = tempVector.length()/this._scaleFactor;
                         this._rootMesh.scaling.set(dist, dist, dist);
                     }

+ 133 - 45
src/Gizmos/babylon.gizmoManager.ts

@@ -3,80 +3,168 @@ module BABYLON {
      * Helps setup gizmo's in the scene to rotate/scale/position meshes
      */
     export class GizmoManager implements IDisposable{
-
+        private _gizmoSet:{positionGizmo: Nullable<PositionGizmo>, rotationGizmo: Nullable<RotationGizmo>, scaleGizmo: Nullable<ScaleGizmo>, boundingBoxGizmo: Nullable<BoundingBoxGizmo>};
         private _gizmoLayer:UtilityLayerRenderer;
-        // Set of gizmos that are currently in the scene for each mesh
-        private _gizmoSet:{[meshID: string]: {positionGizmo: PositionGizmo, rotationGizmo: RotationGizmo}} = {}
         private _pointerObserver:Nullable<Observer<PointerInfo>> = null;
+        private _attachedMesh:Nullable<AbstractMesh> = null;
+        private _boundingBoxColor = BABYLON.Color3.FromHexString("#0984e3");
+        private _boundingBoxUtilLayer:Nullable<UtilityLayerRenderer> = null;
+        private _dragBehavior = new BABYLON.SixDofDragBehavior();
+        /**
+         * Array of meshes which will have the gizmo attached when a pointer selected them. If null, all meshes are attachable. (Default: null)
+         */
+        public attachableMeshes:Nullable<Array<AbstractMesh>> = null;
+        /**
+         * If pointer events should perform attaching/detaching a gizmo, if false this can be done manually via attachToMesh. (Default: true)
+         */
+        public usePointerToAttachGizmos = true;
 
         /**
          * Instatiates a gizmo manager
          * @param scene the scene to overlay the gizmos on top of
-         * @param options If only a single gizmo should exist at one time
          */
-        constructor(private scene:Scene, options?:{singleGizmo?:boolean}){
-            this._gizmoLayer = new UtilityLayerRenderer(scene);
-
-            // Options parsing
-            if(!options){
-                options = {}
-            }
-            if(options.singleGizmo === undefined){
-                options.singleGizmo = true;
-            }
+        constructor(private scene:Scene){
+            this._gizmoSet = {positionGizmo: null, rotationGizmo: null, scaleGizmo: null, boundingBoxGizmo: null};
 
             // Instatiate/dispose gizmos based on pointer actions
             this._pointerObserver = scene.onPointerObservable.add((pointerInfo, state)=>{
+                if(!this.usePointerToAttachGizmos){
+                    return;
+                }
                 if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERDOWN){
                     if(pointerInfo.pickInfo && pointerInfo.pickInfo.pickedMesh){
-                        if(!this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId]){
-                            if(options!.singleGizmo){
-                                this._clearGizmos();
-                            }                            
-                            // Enable gizmo when mesh is selected
-                            this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId] = {positionGizmo: new PositionGizmo(this._gizmoLayer), rotationGizmo: new RotationGizmo(this._gizmoLayer)}
-                            this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId].positionGizmo.attachedMesh = pointerInfo.pickInfo.pickedMesh;
-                            this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId].rotationGizmo.attachedMesh = pointerInfo.pickInfo.pickedMesh;
-                        }else{
-                            if(!options!.singleGizmo){
-                                // Disable gizmo when clicked again
-                                this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId].positionGizmo.dispose();
-                                this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId].rotationGizmo.dispose();
-                                delete this._gizmoSet[pointerInfo.pickInfo.pickedMesh.uniqueId];
+                        var node:Nullable<Node> = pointerInfo.pickInfo.pickedMesh;
+                        if(this.attachableMeshes == null){
+                            // Attach to the most parent node
+                            while(node && node.parent != null){
+                                node = node.parent;
                             }
-                        }
-                    }else {
-                        if(options!.singleGizmo){
-                            // Disable gizmo when clicked away
-                            if(pointerInfo.pickInfo && pointerInfo.pickInfo.ray){
-                                var gizmoPick = this._gizmoLayer.utilityLayerScene.pickWithRay(pointerInfo.pickInfo.ray);
-                                if(gizmoPick && !gizmoPick.hit){
-                                    this._clearGizmos();
+                        }else{
+                            // Attach to the parent node that is an attachableMesh
+                            var found = false;
+                            this.attachableMeshes.forEach((mesh)=>{
+                                if(node && (node == mesh || node.isDescendantOf(mesh))){
+                                    node = mesh;
+                                    found = true;
                                 }
+                            })
+                            if(!found){
+                                node = null;
                             }
                         }
+                        if(node instanceof AbstractMesh){
+                            this.attachToMesh(node);
+                        }
+                    }else{
+                        this.attachToMesh(null);
                     }
                 }
             })
         }
 
         /**
+         * Attaches a set of gizmos to the specified mesh
+         * @param mesh The mesh the gizmo's should be attached to
+         */
+        public attachToMesh(mesh:Nullable<AbstractMesh>){
+            if(this._attachedMesh){
+                this._attachedMesh.removeBehavior(this._dragBehavior);
+            }
+            this._attachedMesh = mesh;
+            for(var key in this._gizmoSet){
+                var gizmo = <Nullable<Gizmo>>((<any>this._gizmoSet)[key]);
+                if(gizmo){
+                    gizmo.attachedMesh = mesh;
+                }
+            }
+            if(this.boundingBoxGizmoEnabled && this._attachedMesh){
+                this._attachedMesh.addBehavior(this._dragBehavior);
+            }
+        }
+
+        /**
+         * If the position gizmo is enabled
+         */
+        public set positionGizmoEnabled(value:boolean){
+            if(value){
+                this._gizmoSet.positionGizmo = this._gizmoSet.positionGizmo || new PositionGizmo();
+                this._gizmoSet.positionGizmo.updateGizmoRotationToMatchAttachedMesh = false;
+                this._gizmoSet.positionGizmo.attachedMesh = this._attachedMesh;
+            }else if(this._gizmoSet.positionGizmo){
+                this._gizmoSet.positionGizmo.dispose();
+                this._gizmoSet.positionGizmo = null;
+            }
+        }
+        public get positionGizmoEnabled():boolean{
+            return this._gizmoSet.positionGizmo != null;
+        }
+        /**
+         * If the rotation gizmo is enabled
+         */
+        public set rotationGizmoEnabled(value:boolean){
+            if(value){
+                this._gizmoSet.rotationGizmo = this._gizmoSet.rotationGizmo || new RotationGizmo();
+                this._gizmoSet.rotationGizmo.updateGizmoRotationToMatchAttachedMesh = false;
+                this._gizmoSet.rotationGizmo.attachedMesh = this._attachedMesh;
+            }else if(this._gizmoSet.rotationGizmo){
+                this._gizmoSet.rotationGizmo.dispose();
+                this._gizmoSet.rotationGizmo = null;
+            }
+        }
+        public get rotationGizmoEnabled():boolean{
+            return this._gizmoSet.rotationGizmo != null;
+        }
+        /**
+         * If the scale gizmo is enabled
+         */
+        public set scaleGizmoEnabled(value:boolean){
+            if(value){
+                this._gizmoSet.scaleGizmo = this._gizmoSet.scaleGizmo || new ScaleGizmo();
+                this._gizmoSet.scaleGizmo.attachedMesh = this._attachedMesh;
+            }else if(this._gizmoSet.scaleGizmo){
+                this._gizmoSet.scaleGizmo.dispose();
+                this._gizmoSet.scaleGizmo = null;
+            }
+        }
+        public get scaleGizmoEnabled():boolean{
+            return this._gizmoSet.scaleGizmo != null;
+        }
+        /**
+         * If the boundingBox gizmo is enabled
+         */
+        public set boundingBoxGizmoEnabled(value:boolean){
+            if(value){
+                if(!this._boundingBoxUtilLayer){
+                    this._boundingBoxUtilLayer = new BABYLON.UtilityLayerRenderer(this.scene);
+                    this._boundingBoxUtilLayer.utilityLayerScene.autoClearDepthAndStencil = false;
+                }
+                this._gizmoSet.boundingBoxGizmo = this._gizmoSet.boundingBoxGizmo || new BoundingBoxGizmo(this._boundingBoxColor, this._boundingBoxUtilLayer);
+                this._gizmoSet.boundingBoxGizmo.attachedMesh = this._attachedMesh;
+                if(this._attachedMesh){
+                    this._attachedMesh.removeBehavior(this._dragBehavior);
+                    this._attachedMesh.addBehavior(this._dragBehavior);
+                }
+            }else if(this._gizmoSet.boundingBoxGizmo){
+                this._gizmoSet.boundingBoxGizmo.dispose();
+                this._gizmoSet.boundingBoxGizmo = null;
+            }
+        }
+        public get boundingBoxGizmoEnabled():boolean{
+            return this._gizmoSet.boundingBoxGizmo != null;
+        }
+
+        /**
          * Disposes of the gizmo manager
          */
         public dispose(){
             this.scene.onPointerObservable.remove(this._pointerObserver);
-            this._clearGizmos();
-            this._gizmoLayer.dispose();
-        }
-
-        private _clearGizmos(){
             for(var key in this._gizmoSet){
-                if(this._gizmoSet.hasOwnProperty(key)){
-                    this._gizmoSet[key].positionGizmo.dispose();
-                    this._gizmoSet[key].rotationGizmo.dispose();
-                    delete this._gizmoSet[key];
+                var gizmo = <Nullable<Gizmo>>((<any>this._gizmoSet)[key]);
+                if(gizmo){
+                    gizmo.dispose();
                 }
             }
+            this._gizmoLayer.dispose();
         }
     }
 }