David Catuhe 7 years ago
parent
commit
55cb054bc5

File diff suppressed because it is too large
+ 9948 - 9938
Playground/babylon.d.txt


File diff suppressed because it is too large
+ 10097 - 10087
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 9 - 9
dist/preview release/babylon.js


+ 83 - 39
dist/preview release/babylon.max.js

@@ -32279,18 +32279,18 @@ var BABYLON;
                         var weight;
                         for (inf = 0; inf < 4; inf++) {
                             weight = matricesWeightsData[matWeightIdx + inf];
-                            if (weight <= 0)
-                                break;
-                            BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                            finalMatrix.addToSelf(tempMatrix);
+                            if (weight > 0) {
+                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                finalMatrix.addToSelf(tempMatrix);
+                            }
                         }
                         if (needExtras) {
                             for (inf = 0; inf < 4; inf++) {
                                 weight = matricesWeightsExtraData[matWeightIdx + inf];
-                                if (weight <= 0)
-                                    break;
-                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                finalMatrix.addToSelf(tempMatrix);
+                                if (weight > 0) {
+                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                    finalMatrix.addToSelf(tempMatrix);
+                                }
                             }
                         }
                         BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
@@ -34443,8 +34443,6 @@ var BABYLON;
                         BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
                         finalMatrix.addToSelf(tempMatrix);
                     }
-                    else
-                        break;
                 }
                 if (needExtras) {
                     for (inf = 0; inf < 4; inf++) {
@@ -34453,8 +34451,6 @@ var BABYLON;
                             BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
                             finalMatrix.addToSelf(tempMatrix);
                         }
-                        else
-                            break;
                     }
                 }
                 BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(this._sourcePositions[index], this._sourcePositions[index + 1], this._sourcePositions[index + 2], finalMatrix, tempVector3);
@@ -89664,6 +89660,14 @@ var BABYLON;
         function PointerDragBehavior(options) {
             this.options = options;
             /**
+             * The maximum tolerated angle between the drag plane and dragging pointer rays to trigger pointer events. Set to 0 to allow any angle (default: 0)
+             */
+            this.maxDragAngle = 0;
+            /**
+             * @hidden
+             */
+            this._useAlternatePickedPointAboveMaxDragAngle = false;
+            /**
              * The id of the pointer that is currently interacting with the behavior (-1 when no pointer is active)
              */
             this.currentDraggingPointerID = -1;
@@ -89711,6 +89715,7 @@ var BABYLON;
              */
             this.useObjectOrienationForDragging = true;
             this._tmpVector = new BABYLON.Vector3(0, 0, 0);
+            this._alternatePickedPoint = new BABYLON.Vector3(0, 0, 0);
             this._worldDragAxis = new BABYLON.Vector3(0, 0, 0);
             // Variables to avoid instantiation in the below method
             this._pointA = new BABYLON.Vector3(0, 0, 0);
@@ -89846,6 +89851,32 @@ var BABYLON;
             if (!ray) {
                 return null;
             }
+            // Calculate angle between plane normal and ray
+            var angle = Math.acos(BABYLON.Vector3.Dot(this._dragPlane.forward, ray.direction));
+            // Correct if ray is casted from oposite side
+            if (angle > Math.PI / 2) {
+                angle = Math.PI - angle;
+            }
+            // If the angle is too perpendicular to the plane pick another point on the plane where it is looking
+            if (this.maxDragAngle > 0 && angle > this.maxDragAngle) {
+                if (this._useAlternatePickedPointAboveMaxDragAngle) {
+                    // Invert ray direction along the towards object axis
+                    this._tmpVector.copyFrom(ray.direction);
+                    this._attachedNode.absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
+                    this._alternatePickedPoint.normalize();
+                    this._alternatePickedPoint.scaleInPlace(-2 * BABYLON.Vector3.Dot(this._alternatePickedPoint, this._tmpVector));
+                    this._tmpVector.addInPlace(this._alternatePickedPoint);
+                    // Project resulting vector onto the drag plane and add it to the attached nodes absolute position to get a picked point
+                    var dot = BABYLON.Vector3.Dot(this._dragPlane.forward, this._tmpVector);
+                    this._dragPlane.forward.scaleToRef(-dot, this._alternatePickedPoint);
+                    this._alternatePickedPoint.addInPlace(this._tmpVector);
+                    this._alternatePickedPoint.addInPlace(this._attachedNode.absolutePosition);
+                    return this._alternatePickedPoint;
+                }
+                else {
+                    return null;
+                }
+            }
             var pickResult = PointerDragBehavior._planeScene.pickWithRay(ray, function (m) { return m == _this._dragPlane; });
             if (pickResult && pickResult.hit && pickResult.pickedMesh && pickResult.pickedPoint) {
                 return pickResult.pickedPoint;
@@ -90185,6 +90216,7 @@ var BABYLON;
             var _this = this;
             this.gizmoLayer = gizmoLayer;
             this._scaleFactor = 3;
+            this._tmpMatrix = new BABYLON.Matrix();
             /**
              * If set the gizmo's rotation will be updated to match the attached mesh each frame (Default: true)
              */
@@ -90204,9 +90236,23 @@ var BABYLON;
                 if (_this.attachedMesh) {
                     if (_this.updateGizmoRotationToMatchAttachedMesh) {
                         if (!_this._rootMesh.rotationQuaternion) {
-                            _this._rootMesh.rotationQuaternion = new BABYLON.Quaternion();
+                            _this._rootMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this._rootMesh.rotation.y, _this._rootMesh.rotation.x, _this._rootMesh.rotation.z);
+                        }
+                        // Remove scaling before getting rotation matrix to get rotation matrix unmodified by scale
+                        tempVector.copyFrom(_this.attachedMesh.scaling);
+                        if (_this.attachedMesh.scaling.x < 0) {
+                            _this.attachedMesh.scaling.x *= -1;
+                        }
+                        if (_this.attachedMesh.scaling.y < 0) {
+                            _this.attachedMesh.scaling.y *= -1;
+                        }
+                        if (_this.attachedMesh.scaling.z < 0) {
+                            _this.attachedMesh.scaling.z *= -1;
                         }
-                        BABYLON.Quaternion.FromRotationMatrixToRef(_this.attachedMesh.getWorldMatrix().getRotationMatrix(), _this._rootMesh.rotationQuaternion);
+                        _this.attachedMesh.computeWorldMatrix().getRotationMatrixToRef(_this._tmpMatrix);
+                        _this.attachedMesh.scaling.copyFrom(tempVector);
+                        _this.attachedMesh.computeWorldMatrix();
+                        BABYLON.Quaternion.FromRotationMatrixToRef(_this._tmpMatrix, _this._rootMesh.rotationQuaternion);
                     }
                     if (_this.updateGizmoPositionToMatchAttachedMesh) {
                         _this._rootMesh.position.copyFrom(_this.attachedMesh.absolutePosition);
@@ -90445,22 +90491,7 @@ var BABYLON;
                             tmpVector.scaleInPlace(0);
                         }
                     }
-                    var invertCount = 0;
-                    if (_this.attachedMesh.scaling["x"] < 0) {
-                        invertCount++;
-                    }
-                    if (_this.attachedMesh.scaling["y"] < 0) {
-                        invertCount++;
-                    }
-                    if (_this.attachedMesh.scaling["z"] < 0) {
-                        invertCount++;
-                    }
-                    if (invertCount % 2 == 0) {
-                        _this.attachedMesh.scaling.addInPlace(tmpVector);
-                    }
-                    else {
-                        _this.attachedMesh.scaling.subtractInPlace(tmpVector);
-                    }
+                    _this.attachedMesh.scaling.addInPlace(tmpVector);
                     if (snapped) {
                         tmpSnapEvent.snapDistance = _this.snapDistance * dragSteps;
                         _this.onSnapObservable.notifyObservers(tmpSnapEvent);
@@ -90550,11 +90581,13 @@ var BABYLON;
             // Add drag behavior to handle events when the gizmo is dragged
             _this.dragBehavior = new BABYLON.PointerDragBehavior({ dragPlaneNormal: planeNormal });
             _this.dragBehavior.moveAttached = false;
+            _this.dragBehavior.maxDragAngle = Math.PI * 9 / 20;
+            _this.dragBehavior._useAlternatePickedPointAboveMaxDragAngle = true;
             _this._rootMesh.addBehavior(_this.dragBehavior);
-            var lastDragPosition = null;
+            var lastDragPosition = new BABYLON.Vector3();
             _this.dragBehavior.onDragStartObservable.add(function (e) {
                 if (_this.attachedMesh) {
-                    lastDragPosition = e.dragPlanePoint;
+                    lastDragPosition.copyFrom(e.dragPlanePoint);
                 }
             });
             var rotationMatrix = new BABYLON.Matrix();
@@ -90563,9 +90596,9 @@ var BABYLON;
             var tmpSnapEvent = { snapDistance: 0 };
             var currentSnapDragDistance = 0;
             _this.dragBehavior.onDragObservable.add(function (event) {
-                if (_this.attachedMesh && lastDragPosition) {
+                if (_this.attachedMesh) {
                     if (!_this.attachedMesh.rotationQuaternion) {
-                        _this.attachedMesh.rotationQuaternion = new BABYLON.Quaternion();
+                        _this.attachedMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this.attachedMesh.rotation.y, _this.attachedMesh.rotation.x, _this.attachedMesh.rotation.z);
                     }
                     // Calc angle over full 360 degree (https://stackoverflow.com/questions/43493711/the-angle-between-two-3d-vectors-with-a-result-range-0-360)
                     var newVector = event.dragPlanePoint.subtract(_this.attachedMesh.position).normalize();
@@ -90607,9 +90640,15 @@ var BABYLON;
                     // Convert angle and axis to quaternion (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm)
                     var quaternionCoefficient = Math.sin(angle / 2);
                     var amountToRotate = new BABYLON.Quaternion(planeNormalTowardsCamera.x * quaternionCoefficient, planeNormalTowardsCamera.y * quaternionCoefficient, planeNormalTowardsCamera.z * quaternionCoefficient, Math.cos(angle / 2));
-                    // Rotate selected mesh quaternion over fixed axis
-                    _this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
-                    lastDragPosition = event.dragPlanePoint;
+                    if (_this.updateGizmoRotationToMatchAttachedMesh) {
+                        // Rotate selected mesh quaternion over fixed axis
+                        _this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
+                    }
+                    else {
+                        // Rotate selected mesh quaternion over rotated axis
+                        amountToRotate.multiplyToRef(_this.attachedMesh.rotationQuaternion, _this.attachedMesh.rotationQuaternion);
+                    }
+                    lastDragPosition.copyFrom(event.dragPlanePoint);
                     if (snapped) {
                         tmpSnapEvent.snapDistance = angle;
                         _this.onSnapObservable.notifyObservers(tmpSnapEvent);
@@ -91007,8 +91046,13 @@ var BABYLON;
                                 var worldMoveDirection = BABYLON.Vector3.TransformCoordinates(moveDirection, _this.attachedMesh.getWorldMatrix().getRotationMatrix());
                                 // Update scale and position
                                 _this.attachedMesh.scaling.addInPlace(deltaScale);
-                                _this.attachedMesh.getAbsolutePosition().addToRef(worldMoveDirection, _this._tmpVector);
-                                _this.attachedMesh.setAbsolutePosition(_this._tmpVector);
+                                if (_this.attachedMesh.scaling.x < 0 || _this.attachedMesh.scaling.y < 0 || _this.attachedMesh.scaling.z < 0) {
+                                    _this.attachedMesh.scaling.subtractInPlace(deltaScale);
+                                }
+                                else {
+                                    _this.attachedMesh.getAbsolutePosition().addToRef(worldMoveDirection, _this._tmpVector);
+                                    _this.attachedMesh.setAbsolutePosition(_this._tmpVector);
+                                }
                             }
                         });
                         // Selection/deselection

+ 83 - 39
dist/preview release/babylon.no-module.max.js

@@ -32246,18 +32246,18 @@ var BABYLON;
                         var weight;
                         for (inf = 0; inf < 4; inf++) {
                             weight = matricesWeightsData[matWeightIdx + inf];
-                            if (weight <= 0)
-                                break;
-                            BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                            finalMatrix.addToSelf(tempMatrix);
+                            if (weight > 0) {
+                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                finalMatrix.addToSelf(tempMatrix);
+                            }
                         }
                         if (needExtras) {
                             for (inf = 0; inf < 4; inf++) {
                                 weight = matricesWeightsExtraData[matWeightIdx + inf];
-                                if (weight <= 0)
-                                    break;
-                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                finalMatrix.addToSelf(tempMatrix);
+                                if (weight > 0) {
+                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                    finalMatrix.addToSelf(tempMatrix);
+                                }
                             }
                         }
                         BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
@@ -34410,8 +34410,6 @@ var BABYLON;
                         BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
                         finalMatrix.addToSelf(tempMatrix);
                     }
-                    else
-                        break;
                 }
                 if (needExtras) {
                     for (inf = 0; inf < 4; inf++) {
@@ -34420,8 +34418,6 @@ var BABYLON;
                             BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
                             finalMatrix.addToSelf(tempMatrix);
                         }
-                        else
-                            break;
                     }
                 }
                 BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(this._sourcePositions[index], this._sourcePositions[index + 1], this._sourcePositions[index + 2], finalMatrix, tempVector3);
@@ -89631,6 +89627,14 @@ var BABYLON;
         function PointerDragBehavior(options) {
             this.options = options;
             /**
+             * The maximum tolerated angle between the drag plane and dragging pointer rays to trigger pointer events. Set to 0 to allow any angle (default: 0)
+             */
+            this.maxDragAngle = 0;
+            /**
+             * @hidden
+             */
+            this._useAlternatePickedPointAboveMaxDragAngle = false;
+            /**
              * The id of the pointer that is currently interacting with the behavior (-1 when no pointer is active)
              */
             this.currentDraggingPointerID = -1;
@@ -89678,6 +89682,7 @@ var BABYLON;
              */
             this.useObjectOrienationForDragging = true;
             this._tmpVector = new BABYLON.Vector3(0, 0, 0);
+            this._alternatePickedPoint = new BABYLON.Vector3(0, 0, 0);
             this._worldDragAxis = new BABYLON.Vector3(0, 0, 0);
             // Variables to avoid instantiation in the below method
             this._pointA = new BABYLON.Vector3(0, 0, 0);
@@ -89813,6 +89818,32 @@ var BABYLON;
             if (!ray) {
                 return null;
             }
+            // Calculate angle between plane normal and ray
+            var angle = Math.acos(BABYLON.Vector3.Dot(this._dragPlane.forward, ray.direction));
+            // Correct if ray is casted from oposite side
+            if (angle > Math.PI / 2) {
+                angle = Math.PI - angle;
+            }
+            // If the angle is too perpendicular to the plane pick another point on the plane where it is looking
+            if (this.maxDragAngle > 0 && angle > this.maxDragAngle) {
+                if (this._useAlternatePickedPointAboveMaxDragAngle) {
+                    // Invert ray direction along the towards object axis
+                    this._tmpVector.copyFrom(ray.direction);
+                    this._attachedNode.absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
+                    this._alternatePickedPoint.normalize();
+                    this._alternatePickedPoint.scaleInPlace(-2 * BABYLON.Vector3.Dot(this._alternatePickedPoint, this._tmpVector));
+                    this._tmpVector.addInPlace(this._alternatePickedPoint);
+                    // Project resulting vector onto the drag plane and add it to the attached nodes absolute position to get a picked point
+                    var dot = BABYLON.Vector3.Dot(this._dragPlane.forward, this._tmpVector);
+                    this._dragPlane.forward.scaleToRef(-dot, this._alternatePickedPoint);
+                    this._alternatePickedPoint.addInPlace(this._tmpVector);
+                    this._alternatePickedPoint.addInPlace(this._attachedNode.absolutePosition);
+                    return this._alternatePickedPoint;
+                }
+                else {
+                    return null;
+                }
+            }
             var pickResult = PointerDragBehavior._planeScene.pickWithRay(ray, function (m) { return m == _this._dragPlane; });
             if (pickResult && pickResult.hit && pickResult.pickedMesh && pickResult.pickedPoint) {
                 return pickResult.pickedPoint;
@@ -90152,6 +90183,7 @@ var BABYLON;
             var _this = this;
             this.gizmoLayer = gizmoLayer;
             this._scaleFactor = 3;
+            this._tmpMatrix = new BABYLON.Matrix();
             /**
              * If set the gizmo's rotation will be updated to match the attached mesh each frame (Default: true)
              */
@@ -90171,9 +90203,23 @@ var BABYLON;
                 if (_this.attachedMesh) {
                     if (_this.updateGizmoRotationToMatchAttachedMesh) {
                         if (!_this._rootMesh.rotationQuaternion) {
-                            _this._rootMesh.rotationQuaternion = new BABYLON.Quaternion();
+                            _this._rootMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this._rootMesh.rotation.y, _this._rootMesh.rotation.x, _this._rootMesh.rotation.z);
+                        }
+                        // Remove scaling before getting rotation matrix to get rotation matrix unmodified by scale
+                        tempVector.copyFrom(_this.attachedMesh.scaling);
+                        if (_this.attachedMesh.scaling.x < 0) {
+                            _this.attachedMesh.scaling.x *= -1;
+                        }
+                        if (_this.attachedMesh.scaling.y < 0) {
+                            _this.attachedMesh.scaling.y *= -1;
+                        }
+                        if (_this.attachedMesh.scaling.z < 0) {
+                            _this.attachedMesh.scaling.z *= -1;
                         }
-                        BABYLON.Quaternion.FromRotationMatrixToRef(_this.attachedMesh.getWorldMatrix().getRotationMatrix(), _this._rootMesh.rotationQuaternion);
+                        _this.attachedMesh.computeWorldMatrix().getRotationMatrixToRef(_this._tmpMatrix);
+                        _this.attachedMesh.scaling.copyFrom(tempVector);
+                        _this.attachedMesh.computeWorldMatrix();
+                        BABYLON.Quaternion.FromRotationMatrixToRef(_this._tmpMatrix, _this._rootMesh.rotationQuaternion);
                     }
                     if (_this.updateGizmoPositionToMatchAttachedMesh) {
                         _this._rootMesh.position.copyFrom(_this.attachedMesh.absolutePosition);
@@ -90412,22 +90458,7 @@ var BABYLON;
                             tmpVector.scaleInPlace(0);
                         }
                     }
-                    var invertCount = 0;
-                    if (_this.attachedMesh.scaling["x"] < 0) {
-                        invertCount++;
-                    }
-                    if (_this.attachedMesh.scaling["y"] < 0) {
-                        invertCount++;
-                    }
-                    if (_this.attachedMesh.scaling["z"] < 0) {
-                        invertCount++;
-                    }
-                    if (invertCount % 2 == 0) {
-                        _this.attachedMesh.scaling.addInPlace(tmpVector);
-                    }
-                    else {
-                        _this.attachedMesh.scaling.subtractInPlace(tmpVector);
-                    }
+                    _this.attachedMesh.scaling.addInPlace(tmpVector);
                     if (snapped) {
                         tmpSnapEvent.snapDistance = _this.snapDistance * dragSteps;
                         _this.onSnapObservable.notifyObservers(tmpSnapEvent);
@@ -90517,11 +90548,13 @@ var BABYLON;
             // Add drag behavior to handle events when the gizmo is dragged
             _this.dragBehavior = new BABYLON.PointerDragBehavior({ dragPlaneNormal: planeNormal });
             _this.dragBehavior.moveAttached = false;
+            _this.dragBehavior.maxDragAngle = Math.PI * 9 / 20;
+            _this.dragBehavior._useAlternatePickedPointAboveMaxDragAngle = true;
             _this._rootMesh.addBehavior(_this.dragBehavior);
-            var lastDragPosition = null;
+            var lastDragPosition = new BABYLON.Vector3();
             _this.dragBehavior.onDragStartObservable.add(function (e) {
                 if (_this.attachedMesh) {
-                    lastDragPosition = e.dragPlanePoint;
+                    lastDragPosition.copyFrom(e.dragPlanePoint);
                 }
             });
             var rotationMatrix = new BABYLON.Matrix();
@@ -90530,9 +90563,9 @@ var BABYLON;
             var tmpSnapEvent = { snapDistance: 0 };
             var currentSnapDragDistance = 0;
             _this.dragBehavior.onDragObservable.add(function (event) {
-                if (_this.attachedMesh && lastDragPosition) {
+                if (_this.attachedMesh) {
                     if (!_this.attachedMesh.rotationQuaternion) {
-                        _this.attachedMesh.rotationQuaternion = new BABYLON.Quaternion();
+                        _this.attachedMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this.attachedMesh.rotation.y, _this.attachedMesh.rotation.x, _this.attachedMesh.rotation.z);
                     }
                     // Calc angle over full 360 degree (https://stackoverflow.com/questions/43493711/the-angle-between-two-3d-vectors-with-a-result-range-0-360)
                     var newVector = event.dragPlanePoint.subtract(_this.attachedMesh.position).normalize();
@@ -90574,9 +90607,15 @@ var BABYLON;
                     // Convert angle and axis to quaternion (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm)
                     var quaternionCoefficient = Math.sin(angle / 2);
                     var amountToRotate = new BABYLON.Quaternion(planeNormalTowardsCamera.x * quaternionCoefficient, planeNormalTowardsCamera.y * quaternionCoefficient, planeNormalTowardsCamera.z * quaternionCoefficient, Math.cos(angle / 2));
-                    // Rotate selected mesh quaternion over fixed axis
-                    _this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
-                    lastDragPosition = event.dragPlanePoint;
+                    if (_this.updateGizmoRotationToMatchAttachedMesh) {
+                        // Rotate selected mesh quaternion over fixed axis
+                        _this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
+                    }
+                    else {
+                        // Rotate selected mesh quaternion over rotated axis
+                        amountToRotate.multiplyToRef(_this.attachedMesh.rotationQuaternion, _this.attachedMesh.rotationQuaternion);
+                    }
+                    lastDragPosition.copyFrom(event.dragPlanePoint);
                     if (snapped) {
                         tmpSnapEvent.snapDistance = angle;
                         _this.onSnapObservable.notifyObservers(tmpSnapEvent);
@@ -90974,8 +91013,13 @@ var BABYLON;
                                 var worldMoveDirection = BABYLON.Vector3.TransformCoordinates(moveDirection, _this.attachedMesh.getWorldMatrix().getRotationMatrix());
                                 // Update scale and position
                                 _this.attachedMesh.scaling.addInPlace(deltaScale);
-                                _this.attachedMesh.getAbsolutePosition().addToRef(worldMoveDirection, _this._tmpVector);
-                                _this.attachedMesh.setAbsolutePosition(_this._tmpVector);
+                                if (_this.attachedMesh.scaling.x < 0 || _this.attachedMesh.scaling.y < 0 || _this.attachedMesh.scaling.z < 0) {
+                                    _this.attachedMesh.scaling.subtractInPlace(deltaScale);
+                                }
+                                else {
+                                    _this.attachedMesh.getAbsolutePosition().addToRef(worldMoveDirection, _this._tmpVector);
+                                    _this.attachedMesh.setAbsolutePosition(_this._tmpVector);
+                                }
                             }
                         });
                         // Selection/deselection

File diff suppressed because it is too large
+ 9 - 9
dist/preview release/babylon.worker.js


+ 83 - 39
dist/preview release/es6.js

@@ -32246,18 +32246,18 @@ var BABYLON;
                         var weight;
                         for (inf = 0; inf < 4; inf++) {
                             weight = matricesWeightsData[matWeightIdx + inf];
-                            if (weight <= 0)
-                                break;
-                            BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                            finalMatrix.addToSelf(tempMatrix);
+                            if (weight > 0) {
+                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                finalMatrix.addToSelf(tempMatrix);
+                            }
                         }
                         if (needExtras) {
                             for (inf = 0; inf < 4; inf++) {
                                 weight = matricesWeightsExtraData[matWeightIdx + inf];
-                                if (weight <= 0)
-                                    break;
-                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                finalMatrix.addToSelf(tempMatrix);
+                                if (weight > 0) {
+                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                    finalMatrix.addToSelf(tempMatrix);
+                                }
                             }
                         }
                         BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
@@ -34410,8 +34410,6 @@ var BABYLON;
                         BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
                         finalMatrix.addToSelf(tempMatrix);
                     }
-                    else
-                        break;
                 }
                 if (needExtras) {
                     for (inf = 0; inf < 4; inf++) {
@@ -34420,8 +34418,6 @@ var BABYLON;
                             BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
                             finalMatrix.addToSelf(tempMatrix);
                         }
-                        else
-                            break;
                     }
                 }
                 BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(this._sourcePositions[index], this._sourcePositions[index + 1], this._sourcePositions[index + 2], finalMatrix, tempVector3);
@@ -89631,6 +89627,14 @@ var BABYLON;
         function PointerDragBehavior(options) {
             this.options = options;
             /**
+             * The maximum tolerated angle between the drag plane and dragging pointer rays to trigger pointer events. Set to 0 to allow any angle (default: 0)
+             */
+            this.maxDragAngle = 0;
+            /**
+             * @hidden
+             */
+            this._useAlternatePickedPointAboveMaxDragAngle = false;
+            /**
              * The id of the pointer that is currently interacting with the behavior (-1 when no pointer is active)
              */
             this.currentDraggingPointerID = -1;
@@ -89678,6 +89682,7 @@ var BABYLON;
              */
             this.useObjectOrienationForDragging = true;
             this._tmpVector = new BABYLON.Vector3(0, 0, 0);
+            this._alternatePickedPoint = new BABYLON.Vector3(0, 0, 0);
             this._worldDragAxis = new BABYLON.Vector3(0, 0, 0);
             // Variables to avoid instantiation in the below method
             this._pointA = new BABYLON.Vector3(0, 0, 0);
@@ -89813,6 +89818,32 @@ var BABYLON;
             if (!ray) {
                 return null;
             }
+            // Calculate angle between plane normal and ray
+            var angle = Math.acos(BABYLON.Vector3.Dot(this._dragPlane.forward, ray.direction));
+            // Correct if ray is casted from oposite side
+            if (angle > Math.PI / 2) {
+                angle = Math.PI - angle;
+            }
+            // If the angle is too perpendicular to the plane pick another point on the plane where it is looking
+            if (this.maxDragAngle > 0 && angle > this.maxDragAngle) {
+                if (this._useAlternatePickedPointAboveMaxDragAngle) {
+                    // Invert ray direction along the towards object axis
+                    this._tmpVector.copyFrom(ray.direction);
+                    this._attachedNode.absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
+                    this._alternatePickedPoint.normalize();
+                    this._alternatePickedPoint.scaleInPlace(-2 * BABYLON.Vector3.Dot(this._alternatePickedPoint, this._tmpVector));
+                    this._tmpVector.addInPlace(this._alternatePickedPoint);
+                    // Project resulting vector onto the drag plane and add it to the attached nodes absolute position to get a picked point
+                    var dot = BABYLON.Vector3.Dot(this._dragPlane.forward, this._tmpVector);
+                    this._dragPlane.forward.scaleToRef(-dot, this._alternatePickedPoint);
+                    this._alternatePickedPoint.addInPlace(this._tmpVector);
+                    this._alternatePickedPoint.addInPlace(this._attachedNode.absolutePosition);
+                    return this._alternatePickedPoint;
+                }
+                else {
+                    return null;
+                }
+            }
             var pickResult = PointerDragBehavior._planeScene.pickWithRay(ray, function (m) { return m == _this._dragPlane; });
             if (pickResult && pickResult.hit && pickResult.pickedMesh && pickResult.pickedPoint) {
                 return pickResult.pickedPoint;
@@ -90152,6 +90183,7 @@ var BABYLON;
             var _this = this;
             this.gizmoLayer = gizmoLayer;
             this._scaleFactor = 3;
+            this._tmpMatrix = new BABYLON.Matrix();
             /**
              * If set the gizmo's rotation will be updated to match the attached mesh each frame (Default: true)
              */
@@ -90171,9 +90203,23 @@ var BABYLON;
                 if (_this.attachedMesh) {
                     if (_this.updateGizmoRotationToMatchAttachedMesh) {
                         if (!_this._rootMesh.rotationQuaternion) {
-                            _this._rootMesh.rotationQuaternion = new BABYLON.Quaternion();
+                            _this._rootMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this._rootMesh.rotation.y, _this._rootMesh.rotation.x, _this._rootMesh.rotation.z);
+                        }
+                        // Remove scaling before getting rotation matrix to get rotation matrix unmodified by scale
+                        tempVector.copyFrom(_this.attachedMesh.scaling);
+                        if (_this.attachedMesh.scaling.x < 0) {
+                            _this.attachedMesh.scaling.x *= -1;
+                        }
+                        if (_this.attachedMesh.scaling.y < 0) {
+                            _this.attachedMesh.scaling.y *= -1;
+                        }
+                        if (_this.attachedMesh.scaling.z < 0) {
+                            _this.attachedMesh.scaling.z *= -1;
                         }
-                        BABYLON.Quaternion.FromRotationMatrixToRef(_this.attachedMesh.getWorldMatrix().getRotationMatrix(), _this._rootMesh.rotationQuaternion);
+                        _this.attachedMesh.computeWorldMatrix().getRotationMatrixToRef(_this._tmpMatrix);
+                        _this.attachedMesh.scaling.copyFrom(tempVector);
+                        _this.attachedMesh.computeWorldMatrix();
+                        BABYLON.Quaternion.FromRotationMatrixToRef(_this._tmpMatrix, _this._rootMesh.rotationQuaternion);
                     }
                     if (_this.updateGizmoPositionToMatchAttachedMesh) {
                         _this._rootMesh.position.copyFrom(_this.attachedMesh.absolutePosition);
@@ -90412,22 +90458,7 @@ var BABYLON;
                             tmpVector.scaleInPlace(0);
                         }
                     }
-                    var invertCount = 0;
-                    if (_this.attachedMesh.scaling["x"] < 0) {
-                        invertCount++;
-                    }
-                    if (_this.attachedMesh.scaling["y"] < 0) {
-                        invertCount++;
-                    }
-                    if (_this.attachedMesh.scaling["z"] < 0) {
-                        invertCount++;
-                    }
-                    if (invertCount % 2 == 0) {
-                        _this.attachedMesh.scaling.addInPlace(tmpVector);
-                    }
-                    else {
-                        _this.attachedMesh.scaling.subtractInPlace(tmpVector);
-                    }
+                    _this.attachedMesh.scaling.addInPlace(tmpVector);
                     if (snapped) {
                         tmpSnapEvent.snapDistance = _this.snapDistance * dragSteps;
                         _this.onSnapObservable.notifyObservers(tmpSnapEvent);
@@ -90517,11 +90548,13 @@ var BABYLON;
             // Add drag behavior to handle events when the gizmo is dragged
             _this.dragBehavior = new BABYLON.PointerDragBehavior({ dragPlaneNormal: planeNormal });
             _this.dragBehavior.moveAttached = false;
+            _this.dragBehavior.maxDragAngle = Math.PI * 9 / 20;
+            _this.dragBehavior._useAlternatePickedPointAboveMaxDragAngle = true;
             _this._rootMesh.addBehavior(_this.dragBehavior);
-            var lastDragPosition = null;
+            var lastDragPosition = new BABYLON.Vector3();
             _this.dragBehavior.onDragStartObservable.add(function (e) {
                 if (_this.attachedMesh) {
-                    lastDragPosition = e.dragPlanePoint;
+                    lastDragPosition.copyFrom(e.dragPlanePoint);
                 }
             });
             var rotationMatrix = new BABYLON.Matrix();
@@ -90530,9 +90563,9 @@ var BABYLON;
             var tmpSnapEvent = { snapDistance: 0 };
             var currentSnapDragDistance = 0;
             _this.dragBehavior.onDragObservable.add(function (event) {
-                if (_this.attachedMesh && lastDragPosition) {
+                if (_this.attachedMesh) {
                     if (!_this.attachedMesh.rotationQuaternion) {
-                        _this.attachedMesh.rotationQuaternion = new BABYLON.Quaternion();
+                        _this.attachedMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this.attachedMesh.rotation.y, _this.attachedMesh.rotation.x, _this.attachedMesh.rotation.z);
                     }
                     // Calc angle over full 360 degree (https://stackoverflow.com/questions/43493711/the-angle-between-two-3d-vectors-with-a-result-range-0-360)
                     var newVector = event.dragPlanePoint.subtract(_this.attachedMesh.position).normalize();
@@ -90574,9 +90607,15 @@ var BABYLON;
                     // Convert angle and axis to quaternion (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm)
                     var quaternionCoefficient = Math.sin(angle / 2);
                     var amountToRotate = new BABYLON.Quaternion(planeNormalTowardsCamera.x * quaternionCoefficient, planeNormalTowardsCamera.y * quaternionCoefficient, planeNormalTowardsCamera.z * quaternionCoefficient, Math.cos(angle / 2));
-                    // Rotate selected mesh quaternion over fixed axis
-                    _this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
-                    lastDragPosition = event.dragPlanePoint;
+                    if (_this.updateGizmoRotationToMatchAttachedMesh) {
+                        // Rotate selected mesh quaternion over fixed axis
+                        _this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
+                    }
+                    else {
+                        // Rotate selected mesh quaternion over rotated axis
+                        amountToRotate.multiplyToRef(_this.attachedMesh.rotationQuaternion, _this.attachedMesh.rotationQuaternion);
+                    }
+                    lastDragPosition.copyFrom(event.dragPlanePoint);
                     if (snapped) {
                         tmpSnapEvent.snapDistance = angle;
                         _this.onSnapObservable.notifyObservers(tmpSnapEvent);
@@ -90974,8 +91013,13 @@ var BABYLON;
                                 var worldMoveDirection = BABYLON.Vector3.TransformCoordinates(moveDirection, _this.attachedMesh.getWorldMatrix().getRotationMatrix());
                                 // Update scale and position
                                 _this.attachedMesh.scaling.addInPlace(deltaScale);
-                                _this.attachedMesh.getAbsolutePosition().addToRef(worldMoveDirection, _this._tmpVector);
-                                _this.attachedMesh.setAbsolutePosition(_this._tmpVector);
+                                if (_this.attachedMesh.scaling.x < 0 || _this.attachedMesh.scaling.y < 0 || _this.attachedMesh.scaling.z < 0) {
+                                    _this.attachedMesh.scaling.subtractInPlace(deltaScale);
+                                }
+                                else {
+                                    _this.attachedMesh.getAbsolutePosition().addToRef(worldMoveDirection, _this._tmpVector);
+                                    _this.attachedMesh.setAbsolutePosition(_this._tmpVector);
+                                }
                             }
                         });
                         // Selection/deselection

File diff suppressed because it is too large
+ 9 - 9
dist/preview release/viewer/babylon.viewer.js


+ 83 - 39
dist/preview release/viewer/babylon.viewer.max.js

@@ -32367,18 +32367,18 @@ var BABYLON;
                         var weight;
                         for (inf = 0; inf < 4; inf++) {
                             weight = matricesWeightsData[matWeightIdx + inf];
-                            if (weight <= 0)
-                                break;
-                            BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                            finalMatrix.addToSelf(tempMatrix);
+                            if (weight > 0) {
+                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                finalMatrix.addToSelf(tempMatrix);
+                            }
                         }
                         if (needExtras) {
                             for (inf = 0; inf < 4; inf++) {
                                 weight = matricesWeightsExtraData[matWeightIdx + inf];
-                                if (weight <= 0)
-                                    break;
-                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                finalMatrix.addToSelf(tempMatrix);
+                                if (weight > 0) {
+                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                    finalMatrix.addToSelf(tempMatrix);
+                                }
                             }
                         }
                         BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
@@ -34531,8 +34531,6 @@ var BABYLON;
                         BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
                         finalMatrix.addToSelf(tempMatrix);
                     }
-                    else
-                        break;
                 }
                 if (needExtras) {
                     for (inf = 0; inf < 4; inf++) {
@@ -34541,8 +34539,6 @@ var BABYLON;
                             BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
                             finalMatrix.addToSelf(tempMatrix);
                         }
-                        else
-                            break;
                     }
                 }
                 BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(this._sourcePositions[index], this._sourcePositions[index + 1], this._sourcePositions[index + 2], finalMatrix, tempVector3);
@@ -89752,6 +89748,14 @@ var BABYLON;
         function PointerDragBehavior(options) {
             this.options = options;
             /**
+             * The maximum tolerated angle between the drag plane and dragging pointer rays to trigger pointer events. Set to 0 to allow any angle (default: 0)
+             */
+            this.maxDragAngle = 0;
+            /**
+             * @hidden
+             */
+            this._useAlternatePickedPointAboveMaxDragAngle = false;
+            /**
              * The id of the pointer that is currently interacting with the behavior (-1 when no pointer is active)
              */
             this.currentDraggingPointerID = -1;
@@ -89799,6 +89803,7 @@ var BABYLON;
              */
             this.useObjectOrienationForDragging = true;
             this._tmpVector = new BABYLON.Vector3(0, 0, 0);
+            this._alternatePickedPoint = new BABYLON.Vector3(0, 0, 0);
             this._worldDragAxis = new BABYLON.Vector3(0, 0, 0);
             // Variables to avoid instantiation in the below method
             this._pointA = new BABYLON.Vector3(0, 0, 0);
@@ -89934,6 +89939,32 @@ var BABYLON;
             if (!ray) {
                 return null;
             }
+            // Calculate angle between plane normal and ray
+            var angle = Math.acos(BABYLON.Vector3.Dot(this._dragPlane.forward, ray.direction));
+            // Correct if ray is casted from oposite side
+            if (angle > Math.PI / 2) {
+                angle = Math.PI - angle;
+            }
+            // If the angle is too perpendicular to the plane pick another point on the plane where it is looking
+            if (this.maxDragAngle > 0 && angle > this.maxDragAngle) {
+                if (this._useAlternatePickedPointAboveMaxDragAngle) {
+                    // Invert ray direction along the towards object axis
+                    this._tmpVector.copyFrom(ray.direction);
+                    this._attachedNode.absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
+                    this._alternatePickedPoint.normalize();
+                    this._alternatePickedPoint.scaleInPlace(-2 * BABYLON.Vector3.Dot(this._alternatePickedPoint, this._tmpVector));
+                    this._tmpVector.addInPlace(this._alternatePickedPoint);
+                    // Project resulting vector onto the drag plane and add it to the attached nodes absolute position to get a picked point
+                    var dot = BABYLON.Vector3.Dot(this._dragPlane.forward, this._tmpVector);
+                    this._dragPlane.forward.scaleToRef(-dot, this._alternatePickedPoint);
+                    this._alternatePickedPoint.addInPlace(this._tmpVector);
+                    this._alternatePickedPoint.addInPlace(this._attachedNode.absolutePosition);
+                    return this._alternatePickedPoint;
+                }
+                else {
+                    return null;
+                }
+            }
             var pickResult = PointerDragBehavior._planeScene.pickWithRay(ray, function (m) { return m == _this._dragPlane; });
             if (pickResult && pickResult.hit && pickResult.pickedMesh && pickResult.pickedPoint) {
                 return pickResult.pickedPoint;
@@ -90273,6 +90304,7 @@ var BABYLON;
             var _this = this;
             this.gizmoLayer = gizmoLayer;
             this._scaleFactor = 3;
+            this._tmpMatrix = new BABYLON.Matrix();
             /**
              * If set the gizmo's rotation will be updated to match the attached mesh each frame (Default: true)
              */
@@ -90292,9 +90324,23 @@ var BABYLON;
                 if (_this.attachedMesh) {
                     if (_this.updateGizmoRotationToMatchAttachedMesh) {
                         if (!_this._rootMesh.rotationQuaternion) {
-                            _this._rootMesh.rotationQuaternion = new BABYLON.Quaternion();
+                            _this._rootMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this._rootMesh.rotation.y, _this._rootMesh.rotation.x, _this._rootMesh.rotation.z);
+                        }
+                        // Remove scaling before getting rotation matrix to get rotation matrix unmodified by scale
+                        tempVector.copyFrom(_this.attachedMesh.scaling);
+                        if (_this.attachedMesh.scaling.x < 0) {
+                            _this.attachedMesh.scaling.x *= -1;
+                        }
+                        if (_this.attachedMesh.scaling.y < 0) {
+                            _this.attachedMesh.scaling.y *= -1;
+                        }
+                        if (_this.attachedMesh.scaling.z < 0) {
+                            _this.attachedMesh.scaling.z *= -1;
                         }
-                        BABYLON.Quaternion.FromRotationMatrixToRef(_this.attachedMesh.getWorldMatrix().getRotationMatrix(), _this._rootMesh.rotationQuaternion);
+                        _this.attachedMesh.computeWorldMatrix().getRotationMatrixToRef(_this._tmpMatrix);
+                        _this.attachedMesh.scaling.copyFrom(tempVector);
+                        _this.attachedMesh.computeWorldMatrix();
+                        BABYLON.Quaternion.FromRotationMatrixToRef(_this._tmpMatrix, _this._rootMesh.rotationQuaternion);
                     }
                     if (_this.updateGizmoPositionToMatchAttachedMesh) {
                         _this._rootMesh.position.copyFrom(_this.attachedMesh.absolutePosition);
@@ -90533,22 +90579,7 @@ var BABYLON;
                             tmpVector.scaleInPlace(0);
                         }
                     }
-                    var invertCount = 0;
-                    if (_this.attachedMesh.scaling["x"] < 0) {
-                        invertCount++;
-                    }
-                    if (_this.attachedMesh.scaling["y"] < 0) {
-                        invertCount++;
-                    }
-                    if (_this.attachedMesh.scaling["z"] < 0) {
-                        invertCount++;
-                    }
-                    if (invertCount % 2 == 0) {
-                        _this.attachedMesh.scaling.addInPlace(tmpVector);
-                    }
-                    else {
-                        _this.attachedMesh.scaling.subtractInPlace(tmpVector);
-                    }
+                    _this.attachedMesh.scaling.addInPlace(tmpVector);
                     if (snapped) {
                         tmpSnapEvent.snapDistance = _this.snapDistance * dragSteps;
                         _this.onSnapObservable.notifyObservers(tmpSnapEvent);
@@ -90638,11 +90669,13 @@ var BABYLON;
             // Add drag behavior to handle events when the gizmo is dragged
             _this.dragBehavior = new BABYLON.PointerDragBehavior({ dragPlaneNormal: planeNormal });
             _this.dragBehavior.moveAttached = false;
+            _this.dragBehavior.maxDragAngle = Math.PI * 9 / 20;
+            _this.dragBehavior._useAlternatePickedPointAboveMaxDragAngle = true;
             _this._rootMesh.addBehavior(_this.dragBehavior);
-            var lastDragPosition = null;
+            var lastDragPosition = new BABYLON.Vector3();
             _this.dragBehavior.onDragStartObservable.add(function (e) {
                 if (_this.attachedMesh) {
-                    lastDragPosition = e.dragPlanePoint;
+                    lastDragPosition.copyFrom(e.dragPlanePoint);
                 }
             });
             var rotationMatrix = new BABYLON.Matrix();
@@ -90651,9 +90684,9 @@ var BABYLON;
             var tmpSnapEvent = { snapDistance: 0 };
             var currentSnapDragDistance = 0;
             _this.dragBehavior.onDragObservable.add(function (event) {
-                if (_this.attachedMesh && lastDragPosition) {
+                if (_this.attachedMesh) {
                     if (!_this.attachedMesh.rotationQuaternion) {
-                        _this.attachedMesh.rotationQuaternion = new BABYLON.Quaternion();
+                        _this.attachedMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this.attachedMesh.rotation.y, _this.attachedMesh.rotation.x, _this.attachedMesh.rotation.z);
                     }
                     // Calc angle over full 360 degree (https://stackoverflow.com/questions/43493711/the-angle-between-two-3d-vectors-with-a-result-range-0-360)
                     var newVector = event.dragPlanePoint.subtract(_this.attachedMesh.position).normalize();
@@ -90695,9 +90728,15 @@ var BABYLON;
                     // Convert angle and axis to quaternion (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm)
                     var quaternionCoefficient = Math.sin(angle / 2);
                     var amountToRotate = new BABYLON.Quaternion(planeNormalTowardsCamera.x * quaternionCoefficient, planeNormalTowardsCamera.y * quaternionCoefficient, planeNormalTowardsCamera.z * quaternionCoefficient, Math.cos(angle / 2));
-                    // Rotate selected mesh quaternion over fixed axis
-                    _this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
-                    lastDragPosition = event.dragPlanePoint;
+                    if (_this.updateGizmoRotationToMatchAttachedMesh) {
+                        // Rotate selected mesh quaternion over fixed axis
+                        _this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
+                    }
+                    else {
+                        // Rotate selected mesh quaternion over rotated axis
+                        amountToRotate.multiplyToRef(_this.attachedMesh.rotationQuaternion, _this.attachedMesh.rotationQuaternion);
+                    }
+                    lastDragPosition.copyFrom(event.dragPlanePoint);
                     if (snapped) {
                         tmpSnapEvent.snapDistance = angle;
                         _this.onSnapObservable.notifyObservers(tmpSnapEvent);
@@ -91095,8 +91134,13 @@ var BABYLON;
                                 var worldMoveDirection = BABYLON.Vector3.TransformCoordinates(moveDirection, _this.attachedMesh.getWorldMatrix().getRotationMatrix());
                                 // Update scale and position
                                 _this.attachedMesh.scaling.addInPlace(deltaScale);
-                                _this.attachedMesh.getAbsolutePosition().addToRef(worldMoveDirection, _this._tmpVector);
-                                _this.attachedMesh.setAbsolutePosition(_this._tmpVector);
+                                if (_this.attachedMesh.scaling.x < 0 || _this.attachedMesh.scaling.y < 0 || _this.attachedMesh.scaling.z < 0) {
+                                    _this.attachedMesh.scaling.subtractInPlace(deltaScale);
+                                }
+                                else {
+                                    _this.attachedMesh.getAbsolutePosition().addToRef(worldMoveDirection, _this._tmpVector);
+                                    _this.attachedMesh.setAbsolutePosition(_this._tmpVector);
+                                }
                             }
                         });
                         // Selection/deselection