Ver código fonte

bounding box working

Trevor Baron 7 anos atrás
pai
commit
75a3407f7a

+ 1 - 0
Tools/Gulp/config.json

@@ -1054,6 +1054,7 @@
                 "../../src/Gizmos/babylon.positionGizmo.js",
                 "../../src/Gizmos/babylon.positionGizmo.js",
                 "../../src/Gizmos/babylon.rotationGizmo.js",
                 "../../src/Gizmos/babylon.rotationGizmo.js",
                 "../../src/Gizmos/babylon.scaleGizmo.js",
                 "../../src/Gizmos/babylon.scaleGizmo.js",
+                "../../src/Gizmos/babylon.boundingBoxGizmo.js",
                 "../../src/Gizmos/babylon.gizmoManager.js"
                 "../../src/Gizmos/babylon.gizmoManager.js"
             ],
             ],
             "dependUpon": [
             "dependUpon": [

+ 44 - 20
src/Behaviors/Mesh/babylon.pointerDragBehavior.ts

@@ -9,11 +9,18 @@ module BABYLON {
         private _pointerObserver:Nullable<Observer<PointerInfo>>;
         private _pointerObserver:Nullable<Observer<PointerInfo>>;
         private static _planeScene:Scene;
         private static _planeScene:Scene;
         private _draggingID = -1;
         private _draggingID = -1;
+        // Debug mode will display drag planes to help visualize behavior
+        private _debugMode = false;
+        private _maxDragAngle = Math.PI/5;
         
         
         /**
         /**
          *  Fires each time the attached mesh is dragged with the pointer
          *  Fires each time the attached mesh is dragged with the pointer
+         *  delta between last drag position and current drag position in world space
+         *  dragDistance along the drag axis
+         *  dragPlaneNormal normal of the current drag plane used during the drag
+         *  dragPlanePoint in world space where the drag intersects the drag plane
          */
          */
-        public onDragObservable = new Observable<{delta:Vector3, dragPlanePoint:Vector3}>()
+        public onDragObservable = new Observable<{delta:Vector3, dragPlanePoint:Vector3, dragPlaneNormal:Vector3, dragDistance:number}>()
         /**
         /**
          *  Fires each time a drag begins (eg. mouse down on mesh)
          *  Fires each time a drag begins (eg. mouse down on mesh)
          */
          */
@@ -38,10 +45,13 @@ module BABYLON {
         
         
         /**
         /**
          * Creates a pointer drag behavior that can be attached to a mesh
          * 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 across.
+         * @param options The drag axis or normal of the plane that will be dragged across. If no options are specified the drag plane will always face the ray's origin (eg. camera)
          */
          */
         constructor(private options:{dragAxis?:Vector3, dragPlaneNormal?:Vector3}){
         constructor(private options:{dragAxis?:Vector3, dragPlaneNormal?:Vector3}){
             var optionCount = 0;
             var optionCount = 0;
+            if(options === undefined){
+                options = {}
+            }
             if(options.dragAxis){
             if(options.dragAxis){
                 optionCount++;
                 optionCount++;
             }
             }
@@ -51,9 +61,6 @@ module BABYLON {
             if(optionCount > 1){
             if(optionCount > 1){
                 throw "Multiple drag modes specified in dragBehavior options. Only one expected";
                 throw "Multiple drag modes specified in dragBehavior options. Only one expected";
             }
             }
-            if(optionCount < 1){
-                throw "At least one drag mode option must be specified";
-            }
         }
         }
 
 
         /**
         /**
@@ -78,15 +85,20 @@ module BABYLON {
 
 
             // Initialize drag plane to not interfere with existing scene
             // Initialize drag plane to not interfere with existing scene
             if(!PointerDragBehavior._planeScene){
             if(!PointerDragBehavior._planeScene){
-                PointerDragBehavior._planeScene = new BABYLON.Scene(this._scene.getEngine())
-                this._scene.getEngine().scenes.pop();
+                if(this._debugMode){
+                    PointerDragBehavior._planeScene = this._scene;
+                }else{
+                    PointerDragBehavior._planeScene = new BABYLON.Scene(this._scene.getEngine());
+                    this._scene.getEngine().scenes.pop();
+                }
             }
             }
-            this._dragPlane = BABYLON.Mesh.CreatePlane("pointerDragPlane", 1000, PointerDragBehavior._planeScene, false, BABYLON.Mesh.DOUBLESIDE);
+            this._dragPlane = BABYLON.Mesh.CreatePlane("pointerDragPlane", this._debugMode ? 1 : 10000, PointerDragBehavior._planeScene, false, BABYLON.Mesh.DOUBLESIDE);
 
 
             // State of the drag
             // State of the drag
             var dragging = false;
             var dragging = false;
             var lastPosition = new BABYLON.Vector3(0,0,0);
             var lastPosition = new BABYLON.Vector3(0,0,0);
             var delta = new BABYLON.Vector3(0,0,0);
             var delta = new BABYLON.Vector3(0,0,0);
+            var dragLength = 0;
 
 
             var pickPredicate = (m:AbstractMesh)=>{
             var pickPredicate = (m:AbstractMesh)=>{
                 return this._attachedNode == m || m.isDescendantOf(this._attachedNode)
                 return this._attachedNode == m || m.isDescendantOf(this._attachedNode)
@@ -117,21 +129,30 @@ module BABYLON {
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE){
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE){
                     if(this._draggingID == (<PointerEvent>pointerInfo.event).pointerId && dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.ray){
                     if(this._draggingID == (<PointerEvent>pointerInfo.event).pointerId && dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.ray){
                         var pickedPoint = this._pickWithRayOnDragPlane(pointerInfo.pickInfo.ray);
                         var pickedPoint = this._pickWithRayOnDragPlane(pointerInfo.pickInfo.ray);
-                        this._updateDragPlanePosition(pointerInfo.pickInfo.ray);
+                        
+                         // Get angle between drag plane and ray. Only update the drag plane at non steep angles to avoid jumps in delta position
+                        var angle = Math.acos(Vector3.Dot(this._dragPlane.forward, pointerInfo.pickInfo.ray.direction));
+                        if(angle < this._maxDragAngle){
+                            this._updateDragPlanePosition(pointerInfo.pickInfo.ray);
+                        }
+                        
                         if (pickedPoint) {
                         if (pickedPoint) {
                             // depending on the drag mode option drag accordingly
                             // depending on the drag mode option drag accordingly
                             if(this.options.dragAxis){
                             if(this.options.dragAxis){
-                                //get the closest point on the dragaxis from the selected mesh to the picked point location
-                                // https://www.opengl.org/discussion_boards/showthread.php/159717-Closest-point-on-a-Vector-to-a-point
-                                this.options.dragAxis.scaleToRef(BABYLON.Vector3.Dot(pickedPoint.subtract(lastPosition), this.options.dragAxis), delta);
+                                // Convert local drag axis to world
+                                var worldDragAxis = Vector3.TransformCoordinates(this.options.dragAxis, this._attachedNode.getWorldMatrix().getRotationMatrix());
+
+                                // Project delta drag from the drag plane onto the drag axis
+                                dragLength = BABYLON.Vector3.Dot(pickedPoint.subtract(lastPosition), worldDragAxis)
+                                worldDragAxis.scaleToRef(dragLength, delta);
                             }else{
                             }else{
+                                dragLength = delta.length();
                                 pickedPoint.subtractToRef(lastPosition, delta);
                                 pickedPoint.subtractToRef(lastPosition, delta);
                             }
                             }
                             if(this.moveAttached){
                             if(this.moveAttached){
                                 (<Mesh>this._attachedNode).position.addInPlace(delta);
                                 (<Mesh>this._attachedNode).position.addInPlace(delta);
-                                
                             }
                             }
-                            this.onDragObservable.notifyObservers({delta: delta, dragPlanePoint: pickedPoint});
+                            this.onDragObservable.notifyObservers({dragDistance: dragLength, delta: delta, dragPlanePoint: pickedPoint, dragPlaneNormal: this._dragPlane.forward});
                             lastPosition.copyFrom(pickedPoint);
                             lastPosition.copyFrom(pickedPoint);
                         }
                         }
                     }
                     }
@@ -153,13 +174,13 @@ module BABYLON {
 
 
         // Position the drag plane based on the attached mesh position, for single axis rotate the plane along the axis to face the camera
         // Position the drag plane based on the attached mesh position, for single axis rotate the plane along the axis to face the camera
         private _updateDragPlanePosition(ray:Ray){
         private _updateDragPlanePosition(ray:Ray){
-            var pointA = this._dragPlaneParent ? this._dragPlaneParent.position : (<Mesh>this._attachedNode).position // center
+            var pointA = this._dragPlaneParent ? this._dragPlaneParent.absolutePosition : (<Mesh>this._attachedNode).absolutePosition;
             if(this.options.dragAxis){
             if(this.options.dragAxis){
-                var camPos = ray.origin;
+                var localAxis = Vector3.TransformCoordinates(this.options.dragAxis, this._attachedNode.getWorldMatrix().getRotationMatrix());
 
 
                 // Calculate plane normal in direction of camera but perpendicular to drag axis
                 // Calculate plane normal in direction of camera but perpendicular to drag axis
-                var pointB = pointA.add(this.options.dragAxis); // towards drag axis
-                var pointC = pointA.add(camPos.subtract(pointA).normalize()); // towards camera
+                var pointB = pointA.add(localAxis); // towards drag axis
+                var pointC = pointA.add(ray.origin.subtract(pointA).normalize()); // towards camera
                 // Get perpendicular line from direction to camera and drag axis
                 // Get perpendicular line from direction to camera and drag axis
                 var lineA = pointB.subtract(pointA);
                 var lineA = pointB.subtract(pointA);
                 var lineB = pointC.subtract(pointA);
                 var lineB = pointC.subtract(pointA);
@@ -168,10 +189,13 @@ module BABYLON {
                 var norm = BABYLON.Vector3.Cross(lineA, perpLine).normalize();
                 var norm = BABYLON.Vector3.Cross(lineA, perpLine).normalize();
 
 
                 this._dragPlane.position.copyFrom(pointA);
                 this._dragPlane.position.copyFrom(pointA);
-                this._dragPlane.lookAt(pointA.add(norm));
+                this._dragPlane.lookAt(pointA.subtract(norm));
             }else if(this.options.dragPlaneNormal){
             }else if(this.options.dragPlaneNormal){
                 this._dragPlane.position.copyFrom(pointA);
                 this._dragPlane.position.copyFrom(pointA);
-                this._dragPlane.lookAt(pointA.add(this.options.dragPlaneNormal));
+                this._dragPlane.lookAt(pointA.subtract(this.options.dragPlaneNormal));
+            }else{
+                this._dragPlane.position.copyFrom(pointA);
+                this._dragPlane.lookAt(ray.origin);
             }
             }
             this._dragPlane.computeWorldMatrix(true);
             this._dragPlane.computeWorldMatrix(true);
         }
         }

+ 1 - 1
src/Gizmos/babylon.axisDragGizmo.ts

@@ -35,7 +35,7 @@ module BABYLON {
             this._rootMesh.lookAt(this._rootMesh.position.subtract(dragAxis));
             this._rootMesh.lookAt(this._rootMesh.position.subtract(dragAxis));
 
 
             // Add drag behavior to handle events when the gizmo is dragged
             // Add drag behavior to handle events when the gizmo is dragged
-            this._dragBehavior = new PointerDragBehavior({dragAxis: dragAxis});
+            this._dragBehavior = new PointerDragBehavior({dragAxis: new BABYLON.Vector3(0,0,1)});
             this._dragBehavior.moveAttached = false;
             this._dragBehavior.moveAttached = false;
             this._rootMesh.addBehavior(this._dragBehavior);
             this._rootMesh.addBehavior(this._dragBehavior);
             this._dragBehavior.onDragObservable.add((event)=>{
             this._dragBehavior.onDragObservable.add((event)=>{

+ 1 - 1
src/Gizmos/babylon.axisScaleGizmo.ts

@@ -35,7 +35,7 @@ module BABYLON {
             this._rootMesh.lookAt(this._rootMesh.position.subtract(dragAxis));
             this._rootMesh.lookAt(this._rootMesh.position.subtract(dragAxis));
 
 
             // Add drag behavior to handle events when the gizmo is dragged
             // Add drag behavior to handle events when the gizmo is dragged
-            this._dragBehavior = new PointerDragBehavior({dragAxis: dragAxis});
+            this._dragBehavior = new PointerDragBehavior({dragAxis: new BABYLON.Vector3(0,0,1)});
             this._dragBehavior.moveAttached = false;
             this._dragBehavior.moveAttached = false;
             this._rootMesh.addBehavior(this._dragBehavior);
             this._rootMesh.addBehavior(this._dragBehavior);
 
 

+ 201 - 0
src/Gizmos/babylon.boundingBoxGizmo.ts

@@ -0,0 +1,201 @@
+module BABYLON {
+    /**
+     * Bounding box gizmo
+     */
+    export class BoundingBoxGizmo extends Gizmo {
+        private _lineBoundingBox:AbstractMesh;
+        private _rotateSpheresParent:AbstractMesh;
+        private _scaleBoxesParent:AbstractMesh;
+        private _boundingDimensions = new BABYLON.Vector3(1,1,1);
+
+        /**
+         * Creates an BoundingBoxGizmo
+         * @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);
+
+            // Do not update the gizmo's scale so it has a fixed size to the object its attached to
+            this._updateScale = false
+
+            // Create Material
+            var coloredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
+            coloredMaterial.disableLighting = true;
+            coloredMaterial.emissiveColor = color;
+
+            // Build bounding box out of lines
+            this._lineBoundingBox = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
+            this._lineBoundingBox.rotationQuaternion = new BABYLON.Quaternion();
+            var lines = []
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(0,0,0), new BABYLON.Vector3(this._boundingDimensions.x,0,0)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(0,0,0), new BABYLON.Vector3(0,this._boundingDimensions.y,0)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(0,0,0), new BABYLON.Vector3(0,0,this._boundingDimensions.z)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(this._boundingDimensions.x,0,0), new BABYLON.Vector3(this._boundingDimensions.x,this._boundingDimensions.y,0)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(this._boundingDimensions.x,0,0), new BABYLON.Vector3(this._boundingDimensions.x,0,this._boundingDimensions.z)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(0,this._boundingDimensions.y,0), new BABYLON.Vector3(this._boundingDimensions.x,this._boundingDimensions.y,0)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(0,this._boundingDimensions.y,0), new BABYLON.Vector3(0,this._boundingDimensions.y,this._boundingDimensions.z)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(0,0,this._boundingDimensions.z), new BABYLON.Vector3(this._boundingDimensions.x,0,this._boundingDimensions.z)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(0,0,this._boundingDimensions.z), new BABYLON.Vector3(0,this._boundingDimensions.y,this._boundingDimensions.z)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(this._boundingDimensions.x,this._boundingDimensions.y,this._boundingDimensions.z), new BABYLON.Vector3(0,this._boundingDimensions.y,this._boundingDimensions.z)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(this._boundingDimensions.x,this._boundingDimensions.y,this._boundingDimensions.z), new BABYLON.Vector3(this._boundingDimensions.x,0,this._boundingDimensions.z)]}, gizmoLayer.utilityLayerScene));
+            lines.push(BABYLON.MeshBuilder.CreateLines("lines", {points: [new BABYLON.Vector3(this._boundingDimensions.x,this._boundingDimensions.y,this._boundingDimensions.z), new BABYLON.Vector3(this._boundingDimensions.x,this._boundingDimensions.y,0)]}, gizmoLayer.utilityLayerScene));
+            lines.forEach((l)=>{
+                l.color = color
+                l.position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x/2,-this._boundingDimensions.y/2,-this._boundingDimensions.z/2))
+                l.isPickable=false;
+                this._lineBoundingBox.addChild(l)
+            })
+            this._rootMesh.addChild(this._lineBoundingBox);
+
+            // Create rotation spheres
+            this._rotateSpheresParent = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
+            this._rotateSpheresParent.rotationQuaternion = new Quaternion();
+            for(let i=0;i<12;i++){
+                let sphere = BABYLON.MeshBuilder.CreateSphere("", {diameter: 0.1}, gizmoLayer.utilityLayerScene);
+                sphere.rotationQuaternion = new Quaternion();
+                    sphere.material = coloredMaterial;
+                    var _dragBehavior = new PointerDragBehavior({});
+                    _dragBehavior.moveAttached = false;
+                    sphere.addBehavior(_dragBehavior);
+                    _dragBehavior.onDragObservable.add((event)=>{
+                        if(this.attachedMesh){
+                            var worldDragDirection = sphere.forward;
+
+                            // project the world right on to the drag plane
+                            var toSub = event.dragPlaneNormal.scale(Vector3.Dot(event.dragPlaneNormal, worldDragDirection));
+                            var dragAxis = worldDragDirection.subtract(toSub).normalizeToNew();
+
+                            // project drag delta on to the resulting drag axis and rotate based on that
+                            var projectDist = Vector3.Dot(dragAxis, event.delta);
+
+                            // Rotate based on axis
+                            if(i>=8){
+                                this.attachedMesh.rotation.z -= projectDist;
+                            }else if(i>=4){
+                                this.attachedMesh.rotation.y -= projectDist;
+                            }else{
+                                this.attachedMesh.rotation.x -= projectDist;
+                            }
+                        }
+                    });
+
+                    // Selection/deselection
+                    _dragBehavior.onDragStartObservable.add(()=>{
+                        this._selectNode(sphere)
+                    })
+                    _dragBehavior.onDragEndObservable.add(()=>{
+                        this._selectNode(null)
+                    })
+
+                this._rotateSpheresParent.addChild(sphere);
+            }
+            this._rootMesh.addChild(this._rotateSpheresParent);
+
+            // Create scale cubes
+            this._scaleBoxesParent = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
+            this._scaleBoxesParent.rotationQuaternion = new Quaternion();
+            for(var i=0;i<2;i++){
+                for(var j=0;j<2;j++){
+                    for(var k=0;k<2;k++){
+                        let box = BABYLON.MeshBuilder.CreateBox("", {size: 0.1}, gizmoLayer.utilityLayerScene);
+                        box.material = coloredMaterial;
+
+                        // Dragging logic
+                        var _dragBehavior = new PointerDragBehavior({dragAxis: new BABYLON.Vector3(i==0?-1:1,j==0?-1:1,k==0?-1:1)});
+                        _dragBehavior.moveAttached = false;
+                        box.addBehavior(_dragBehavior);
+                        _dragBehavior.onDragObservable.add((event)=>{
+                            if(this.attachedMesh){
+                                this.attachedMesh.scaling.addInPlace(new Vector3(event.dragDistance,event.dragDistance,event.dragDistance));
+                            }
+                        })
+
+                        // Selection/deselection
+                        _dragBehavior.onDragStartObservable.add(()=>{
+                            this._selectNode(box)
+                        })
+                        _dragBehavior.onDragEndObservable.add(()=>{
+                            this._selectNode(null)
+                        })
+
+                        this._scaleBoxesParent.addChild(box);
+                    }
+                }
+            }
+            this._rootMesh.addChild(this._scaleBoxesParent);
+
+            // Update bounding box positions
+            this.gizmoLayer.originalScene.onBeforeRenderObservable.add(()=>{
+                if(this.attachedMesh){
+                    var boundingInfo = this.attachedMesh.getBoundingInfo().boundingBox;
+                    var boundBoxDimensions = boundingInfo.maximum.subtract(boundingInfo.minimum).multiplyInPlace(this.attachedMesh.scaling);
+                    this._boundingDimensions.copyFrom(boundBoxDimensions);
+                    this._lineBoundingBox.scaling.copyFrom(this._boundingDimensions);
+                    if(!this.attachedMesh.rotationQuaternion){
+                        this.attachedMesh.rotationQuaternion = new BABYLON.Quaternion();
+                    }
+                    this._lineBoundingBox.rotationQuaternion!.copyFrom(this.attachedMesh.rotationQuaternion);
+                    this._rotateSpheresParent.rotationQuaternion!.copyFrom(this.attachedMesh.rotationQuaternion);
+                    this._scaleBoxesParent.rotationQuaternion!.copyFrom(this.attachedMesh.rotationQuaternion);
+                    this._updateBoundingBox();
+                }
+            })
+            this._updateBoundingBox();
+        }
+
+        private _selectNode(selectedMesh:Nullable<Mesh>){
+            this._rotateSpheresParent.getChildMeshes()
+            .concat(this._scaleBoxesParent.getChildMeshes()).forEach((m,i)=>{
+                m.isVisible = (!selectedMesh || m == selectedMesh);
+            })
+        }
+
+        private _updateBoundingBox(){            
+            var rotateSpheres = this._rotateSpheresParent.getChildMeshes();
+            for(var i=0;i<3;i++){
+                for(var j=0;j<2;j++){
+                    for(var k=0;k<2;k++){
+                        var index= ((i*4)+(j*2))+k
+                        if(i==0){
+                            rotateSpheres[index].position.set(this._boundingDimensions.x/2,this._boundingDimensions.y*j,this._boundingDimensions.z*k);
+                            rotateSpheres[index].position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x/2,-this._boundingDimensions.y/2,-this._boundingDimensions.z/2));
+                            rotateSpheres[index].lookAt(Vector3.Cross(Vector3.Right(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                        }
+                        if(i==1){
+                            rotateSpheres[index].position.set(this._boundingDimensions.x*j,this._boundingDimensions.y/2,this._boundingDimensions.z*k);
+                            rotateSpheres[index].position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x/2,-this._boundingDimensions.y/2,-this._boundingDimensions.z/2));
+                            rotateSpheres[index].lookAt(Vector3.Cross(Vector3.Up(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                        }
+                        if(i==2){
+                            rotateSpheres[index].position.set(this._boundingDimensions.x*j,this._boundingDimensions.y*k,this._boundingDimensions.z/2);
+                            rotateSpheres[index].position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x/2,-this._boundingDimensions.y/2,-this._boundingDimensions.z/2));
+                            rotateSpheres[index].lookAt(Vector3.Cross(Vector3.Forward(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                        }
+                    }
+                }
+            }
+
+            var scaleBoxes = this._scaleBoxesParent.getChildMeshes();
+            for(var i=0;i<2;i++){
+                for(var j=0;j<2;j++){
+                    for(var k=0;k<2;k++){
+                        var index= ((i*4)+(j*2))+k;
+                        if(scaleBoxes[index]){
+                            scaleBoxes[index].position.set(this._boundingDimensions.x*i,this._boundingDimensions.y*j,this._boundingDimensions.z*k);
+                            scaleBoxes[index].position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x/2,-this._boundingDimensions.y/2,-this._boundingDimensions.z/2));
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Disposes of the gizmo
+         */
+        public dispose(){
+            super.dispose();
+        } 
+    }
+}

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

@@ -11,6 +11,10 @@ module BABYLON {
          * Mesh that the gizmo will be attached to. (eg. on a drag gizmo the mesh that will be dragged)
          * Mesh that the gizmo will be attached to. (eg. on a drag gizmo the mesh that will be dragged)
          */
          */
         public attachedMesh:Nullable<AbstractMesh>;
         public attachedMesh:Nullable<AbstractMesh>;
+        /**
+         * When set, the gizmo will always appear the same size no matter where the camera is (default: false)
+         */
+        protected _updateScale = true;
         protected _interactionsEnabled = true;
         protected _interactionsEnabled = true;
         protected _onInteractionsEnabledChanged(value:boolean){
         protected _onInteractionsEnabledChanged(value:boolean){
         }
         }
@@ -35,7 +39,7 @@ module BABYLON {
         constructor(/** The utility layer the gizmo will be added to */ public gizmoLayer:UtilityLayerRenderer){
         constructor(/** The utility layer the gizmo will be added to */ public gizmoLayer:UtilityLayerRenderer){
             this._rootMesh = new BABYLON.Mesh("gizmoRootNode",gizmoLayer.utilityLayerScene);
             this._rootMesh = new BABYLON.Mesh("gizmoRootNode",gizmoLayer.utilityLayerScene);
             this._beforeRenderObserver = this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.add(()=>{
             this._beforeRenderObserver = this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.add(()=>{
-                if(this.gizmoLayer.utilityLayerScene.activeCamera && this.attachedMesh){
+                if(this._updateScale && this.gizmoLayer.utilityLayerScene.activeCamera && this.attachedMesh){
                     var dist = this.attachedMesh.position.subtract(this.gizmoLayer.utilityLayerScene.activeCamera.position).length()/3;
                     var dist = this.attachedMesh.position.subtract(this.gizmoLayer.utilityLayerScene.activeCamera.position).length()/3;
                     this._rootMesh.scaling.set(dist, dist, dist);
                     this._rootMesh.scaling.set(dist, dist, dist);
                 }
                 }

+ 5 - 1
src/Rendering/babylon.utilityLayerRenderer.ts

@@ -67,6 +67,10 @@ module BABYLON {
                     if(!prePointerInfo.skipOnPointerObservable){
                     if(!prePointerInfo.skipOnPointerObservable){
                         this.utilityLayerScene.onPointerObservable.notifyObservers(new PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick))
                         this.utilityLayerScene.onPointerObservable.notifyObservers(new PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick))
                     }
                     }
+                    let pointerEvent = <PointerEvent>(prePointerInfo.event);
+                    if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && this._pointerCaptures[pointerEvent.pointerId]) {
+                        this._pointerCaptures[pointerEvent.pointerId] = false;
+                    }
                     return;
                     return;
                 }
                 }
 
 
@@ -104,7 +108,7 @@ module BABYLON {
                                 delete this._lastPointerEvents[pointerEvent.pointerId];
                                 delete this._lastPointerEvents[pointerEvent.pointerId];
                             }
                             }
                         }
                         }
-
+                        
                         if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && this._pointerCaptures[pointerEvent.pointerId]) {
                         if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && this._pointerCaptures[pointerEvent.pointerId]) {
                             this._pointerCaptures[pointerEvent.pointerId] = false;
                             this._pointerCaptures[pointerEvent.pointerId] = false;
                         }
                         }