sebavan hace 6 años
padre
commit
6ff54156a6
Se han modificado 56 ficheros con 8547 adiciones y 5165 borrados
  1. 5740 2841
      Playground/babylon.d.txt
  2. 1882 1871
      dist/preview release/babylon.d.ts
  3. 1 1
      dist/preview release/babylon.js
  4. 87 62
      dist/preview release/babylon.max.js
  5. 87 62
      dist/preview release/babylon.no-module.max.js
  6. 1 1
      dist/preview release/babylon.worker.js
  7. 87 62
      dist/preview release/es6.js
  8. 21 7
      dist/preview release/gui/babylon.gui.d.ts
  9. 1 1
      dist/preview release/gui/babylon.gui.js
  10. 1 1
      dist/preview release/gui/babylon.gui.min.js
  11. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  12. 43 14
      dist/preview release/gui/babylon.gui.module.d.ts
  13. 7 7
      dist/preview release/inspector/babylon.inspector.bundle.js
  14. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  15. 1 1
      dist/preview release/inspector/babylon.inspector.d.ts
  16. 2 2
      dist/preview release/inspector/babylon.inspector.module.d.ts
  17. 2 6
      dist/preview release/viewer/babylon.viewer.d.ts
  18. 1 1
      dist/preview release/viewer/babylon.viewer.js
  19. 4 4
      dist/preview release/viewer/babylon.viewer.max.js
  20. 2 7
      dist/preview release/viewer/babylon.viewer.module.d.ts
  21. 6 0
      dist/preview release/what's new.md
  22. 54 3
      gui/src/2D/controls/colorpicker.ts
  23. 2 8
      gui/src/2D/controls/container.ts
  24. 20 1
      gui/src/2D/controls/control.ts
  25. 9 0
      gui/src/2D/controls/grid.ts
  26. 194 28
      gui/src/2D/controls/inputText.ts
  27. 2 18
      gui/src/2D/controls/scrollViewers/scrollViewer.ts
  28. 2 10
      gui/src/2D/controls/sliders/scrollBar.ts
  29. 4 4
      gui/src/2D/controls/textBlock.ts
  30. 2 2
      gui/src/3D/controls/cylinderPanel.ts
  31. 2 2
      gui/src/3D/controls/planePanel.ts
  32. 2 2
      gui/src/3D/controls/scatterPanel.ts
  33. 2 2
      gui/src/3D/controls/spherePanel.ts
  34. 4 0
      inspector/src/components/actionTabs/actionTabs.scss
  35. 2 1
      inspector/src/components/actionTabs/lines/textLineComponent.tsx
  36. 2 3
      inspector/src/components/actionTabs/tabs/debugTabComponent.tsx
  37. 10 2
      inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx
  38. 2 4
      inspector/src/components/actionTabs/tabs/propertyGrids/animationGroupPropertyGridComponent.tsx
  39. 28 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx
  40. 80 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/gridPropertyGridComponent.tsx
  41. 0 1
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/scrollViewerPropertyGridComponent.tsx
  42. 4 4
      inspector/src/components/actionTabs/tabs/propertyGrids/gridPropertyGridComponent.tsx
  43. 4 4
      inspector/src/inspector.ts
  44. 25 25
      src/Behaviors/Meshes/pointerDragBehavior.ts
  45. 6 6
      src/Behaviors/Meshes/sixDofDragBehavior.ts
  46. 17 1
      src/Cameras/VR/vrExperienceHelper.ts
  47. 3 10
      src/Debug/axesViewer.ts
  48. 20 14
      src/Engines/engine.ts
  49. 1 1
      src/Gizmos/axisDragGizmo.ts
  50. 9 9
      src/Gizmos/axisScaleGizmo.ts
  51. 5 5
      src/Gizmos/boundingBoxGizmo.ts
  52. 10 10
      src/Gizmos/planeRotationGizmo.ts
  53. 1 1
      src/Meshes/meshBuilder.ts
  54. 2 2
      src/Meshes/transformNode.ts
  55. 38 28
      src/Physics/Plugins/ammoJSPlugin.ts
  56. 1 1
      src/Physics/physicsImpostor.ts

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 5740 - 2841
Playground/babylon.d.txt


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1882 - 1871
dist/preview release/babylon.d.ts


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/babylon.js


+ 87 - 62
dist/preview release/babylon.max.js

@@ -13794,23 +13794,29 @@ var BABYLON;
          * @param clearColor defines the clear color
          */
         Engine.prototype.scissorClear = function (x, y, width, height, clearColor) {
+            this.enableScissor(x, y, width, height);
+            this.clear(clearColor, true, true, true);
+            this.disableScissor();
+        };
+        /**
+         * Enable scissor test on a specific rectangle (ie. render will only be executed on a specific portion of the screen)
+         * @param x defines the x-coordinate of the top left corner of the clear rectangle
+         * @param y defines the y-coordinate of the corner of the clear rectangle
+         * @param width defines the width of the clear rectangle
+         * @param height defines the height of the clear rectangle
+         */
+        Engine.prototype.enableScissor = function (x, y, width, height) {
             var gl = this._gl;
-            // Save state
-            var curScissor = gl.getParameter(gl.SCISSOR_TEST);
-            var curScissorBox = gl.getParameter(gl.SCISSOR_BOX);
             // Change state
             gl.enable(gl.SCISSOR_TEST);
             gl.scissor(x, y, width, height);
-            // Clear
-            this.clear(clearColor, true, true, true);
-            // Restore state
-            gl.scissor(curScissorBox[0], curScissorBox[1], curScissorBox[2], curScissorBox[3]);
-            if (curScissor === true) {
-                gl.enable(gl.SCISSOR_TEST);
-            }
-            else {
-                gl.disable(gl.SCISSOR_TEST);
-            }
+        };
+        /**
+         * Disable previously set scissor test rectangle
+         */
+        Engine.prototype.disableScissor = function () {
+            var gl = this._gl;
+            gl.disable(gl.SCISSOR_TEST);
         };
         /** @hidden */
         Engine.prototype._viewport = function (x, y, width, height) {
@@ -20605,9 +20611,9 @@ var BABYLON;
             if (yawCor === void 0) { yawCor = 0; }
             if (pitchCor === void 0) { pitchCor = 0; }
             if (rollCor === void 0) { rollCor = 0; }
-            var yaw = -Math.atan2(localAxis.z, localAxis.x) - Math.PI / 2;
+            var yaw = -Math.atan2(localAxis.z, localAxis.x) + Math.PI / 2;
             var len = Math.sqrt(localAxis.x * localAxis.x + localAxis.z * localAxis.z);
-            var pitch = Math.atan2(localAxis.y, len);
+            var pitch = -Math.atan2(localAxis.y, len);
             if (this.rotationQuaternion) {
                 BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
             }
@@ -66648,7 +66654,6 @@ var BABYLON;
             function AxesViewer(scene, scaleLines, renderingGroupId, xAxis, yAxis, zAxis) {
                 if (scaleLines === void 0) { scaleLines = 1; }
                 if (renderingGroupId === void 0) { renderingGroupId = 2; }
-                this._tmpVector = new BABYLON.Vector3();
                 this._scaleLinesFactor = 4;
                 this._instanced = false;
                 /**
@@ -66675,13 +66680,10 @@ var BABYLON;
                     zAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
                 }
                 this._xAxis = xAxis;
-                this._xAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._yAxis = yAxis;
-                this._yAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zAxis = zAxis;
-                this._zAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 if (renderingGroupId != null) {
                     AxesViewer._SetRenderingGroupId(this._xAxis, renderingGroupId);
@@ -66724,16 +66726,13 @@ var BABYLON;
              */
             AxesViewer.prototype.update = function (position, xaxis, yaxis, zaxis) {
                 this._xAxis.position.copyFrom(position);
-                xaxis.scaleToRef(-1, this._tmpVector);
-                this._xAxis.setDirection(this._tmpVector);
+                this._xAxis.setDirection(xaxis);
                 this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._yAxis.position.copyFrom(position);
-                yaxis.scaleToRef(-1, this._tmpVector);
-                this._yAxis.setDirection(this._tmpVector);
+                this._yAxis.setDirection(yaxis);
                 this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zAxis.position.copyFrom(position);
-                zaxis.scaleToRef(-1, this._tmpVector);
-                this._zAxis.setDirection(this._tmpVector);
+                this._zAxis.setDirection(zaxis);
                 this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
             };
             /**
@@ -70760,7 +70759,7 @@ var BABYLON;
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
                 plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
-                plane.setDirection(options.sourcePlane.normal);
+                plane.setDirection(options.sourcePlane.normal.scale(-1));
             }
             return plane;
         };
@@ -97792,7 +97791,7 @@ var BABYLON;
                     _this._tmpQuat.copyFrom(_this.object.rotationQuaternion || new BABYLON.Quaternion());
                 }
                 if (!_this._options.disableBidirectionalTransformation) {
-                    _this.object.rotationQuaternion && _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, /*bInfo.boundingBox.centerWorld*/ _this.object.getAbsolutePivotPoint(), _this._tmpQuat);
+                    _this.object.rotationQuaternion && _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, /*bInfo.boundingBox.centerWorld*/ _this.object.getAbsolutePosition(), _this._tmpQuat);
                 }
                 _this._onBeforePhysicsStepCallbacks.forEach(function (func) {
                     func(_this);
@@ -100260,34 +100259,43 @@ var BABYLON;
             var extendSize = impostor.getObjectExtendSize();
             if (!ignoreChildren) {
                 var meshChildren = impostor.object.getChildMeshes ? impostor.object.getChildMeshes(true) : [];
-                if (meshChildren.length > 0) {
-                    returnValue = new Ammo.btCompoundShape();
-                    // Add shape of all children to the compound shape
-                    meshChildren.forEach(function (childMesh) {
-                        var childImpostor = childMesh.getPhysicsImpostor();
-                        if (childImpostor) {
-                            var shape = _this._createShape(childImpostor);
-                            // Position needs to be scaled based on parent's scaling
-                            var parentMat = childMesh.parent.getWorldMatrix().clone();
-                            var s = new BABYLON.Vector3();
-                            parentMat.decompose(s);
-                            _this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
-                            _this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion.x, childMesh.rotationQuaternion.y, childMesh.rotationQuaternion.z, childMesh.rotationQuaternion.w);
-                            _this._tmpAmmoTransform.setRotation(_this._tmpAmmoQuaternion);
-                            returnValue.addChildShape(_this._tmpAmmoTransform, shape);
-                            childImpostor.dispose();
-                        }
-                    });
+                returnValue = new Ammo.btCompoundShape();
+                // Add shape of all children to the compound shape
+                var childrenAdded = 0;
+                meshChildren.forEach(function (childMesh) {
+                    var childImpostor = childMesh.getPhysicsImpostor();
+                    if (childImpostor) {
+                        var shape = _this._createShape(childImpostor);
+                        // Position needs to be scaled based on parent's scaling
+                        var parentMat = childMesh.parent.getWorldMatrix().clone();
+                        var s = new BABYLON.Vector3();
+                        parentMat.decompose(s);
+                        _this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
+                        _this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion.x, childMesh.rotationQuaternion.y, childMesh.rotationQuaternion.z, childMesh.rotationQuaternion.w);
+                        _this._tmpAmmoTransform.setRotation(_this._tmpAmmoQuaternion);
+                        returnValue.addChildShape(_this._tmpAmmoTransform, shape);
+                        childImpostor.dispose();
+                        childrenAdded++;
+                    }
+                });
+                if (childrenAdded > 0) {
                     // Add parents shape as a child if present
-                    var shape = this._createShape(impostor, true);
-                    if (shape) {
-                        this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
-                        this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
-                        this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
-                        returnValue.addChildShape(this._tmpAmmoTransform, shape);
+                    if (impostor.type != BABYLON.PhysicsImpostor.NoImpostor) {
+                        var shape = this._createShape(impostor, true);
+                        if (shape) {
+                            this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
+                            this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
+                            this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
+                            returnValue.addChildShape(this._tmpAmmoTransform, shape);
+                        }
                     }
                     return returnValue;
                 }
+                else {
+                    // If no children with impostors create the actual shape below instead
+                    Ammo.destroy(returnValue);
+                    returnValue = null;
+                }
             }
             switch (impostor.type) {
                 case BABYLON.PhysicsImpostor.SphereImpostor:
@@ -100317,6 +100325,9 @@ var BABYLON;
                     // Fill with sphere but collision is disabled on the rigid body in generatePhysicsBody, using an empty shape caused unexpected movement with joints
                     returnValue = new Ammo.btSphereShape(extendSize.x / 2);
                     break;
+                default:
+                    BABYLON.Tools.Warn("The impostor type is not currently supported by the ammo plugin.");
+                    break;
             }
             return returnValue;
         };
@@ -103549,13 +103560,13 @@ var BABYLON;
                 BABYLON.Vector3.CrossToRef(this._lineA, this._lookAt, this._lookAt);
                 this._lookAt.normalize();
                 this._dragPlane.position.copyFrom(this._pointA);
-                this._pointA.subtractToRef(this._lookAt, this._lookAt);
+                this._pointA.addToRef(this._lookAt, this._lookAt);
                 this._dragPlane.lookAt(this._lookAt);
             }
             else if (this._options.dragPlaneNormal) {
                 this.useObjectOrienationForDragging ? BABYLON.Vector3.TransformCoordinatesToRef(this._options.dragPlaneNormal, this._attachedNode.getWorldMatrix().getRotationMatrix(), this._localAxis) : this._localAxis.copyFrom(this._options.dragPlaneNormal);
                 this._dragPlane.position.copyFrom(this._pointA);
-                this._pointA.subtractToRef(this._localAxis, this._lookAt);
+                this._pointA.addToRef(this._localAxis, this._lookAt);
                 this._dragPlane.lookAt(this._lookAt);
             }
             else {
@@ -103785,7 +103796,7 @@ var BABYLON;
                         lastSixDofOriginPosition.copyFrom(pointerInfo.pickInfo.ray.origin);
                         // Set position and orientation of the controller
                         _this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
-                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
+                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.add(pointerInfo.pickInfo.ray.direction));
                         // Attach the virtual drag mesh to the virtual origin mesh so it can be dragged
                         _this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
                         pickedMesh.computeWorldMatrix();
@@ -103849,7 +103860,7 @@ var BABYLON;
                         }
                         // Update the controller position
                         _this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
-                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
+                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.add(pointerInfo.pickInfo.ray.direction));
                         _this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
                         // Move the virtualObjectsPosition into the picked mesh's space if needed
                         _this._targetPosition.copyFrom(_this._virtualDragMesh.absolutePosition);
@@ -104355,7 +104366,7 @@ var BABYLON;
             hoverMaterial.emissiveColor = color.add(new BABYLON.Color3(0.3, 0.3, 0.3));
             // Build mesh on root node
             var arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, coloredMaterial);
-            arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
+            arrow.lookAt(_this._rootMesh.position.add(dragAxis));
             arrow.scaling.scaleInPlace(1 / 3);
             arrow.parent = _this._rootMesh;
             var currentSnapDragDistance = 0;
@@ -104514,7 +104525,7 @@ var BABYLON;
             arrowTail.scaling.scaleInPlace(0.26);
             arrowTail.rotation.x = Math.PI / 2;
             arrowTail.material = _this._coloredMaterial;
-            arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
+            arrow.lookAt(_this._rootMesh.position.add(dragAxis));
             _this._rootMesh.addChild(arrow);
             arrow.scaling.scaleInPlace(1 / 3);
             // Add drag behavior to handle events when the gizmo is dragged
@@ -104668,7 +104679,7 @@ var BABYLON;
             rotationMesh.material = coloredMaterial;
             rotationMesh.rotation.x = Math.PI / 2;
             parentMesh.addChild(rotationMesh);
-            parentMesh.lookAt(_this._rootMesh.position.subtract(planeNormal));
+            parentMesh.lookAt(_this._rootMesh.position.add(planeNormal));
             _this._rootMesh.addChild(parentMesh);
             parentMesh.scaling.scaleInPlace(1 / 3);
             // Add drag behavior to handle events when the gizmo is dragged
@@ -105533,17 +105544,17 @@ var BABYLON;
                         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(BABYLON.Vector3.Cross(BABYLON.Vector3.Right(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Right()).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(BABYLON.Vector3.Cross(BABYLON.Vector3.Up(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Up()).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(BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Forward()).normalizeToNew().add(rotateSpheres[index].position));
                         }
                         if (this.fixedDragMeshScreenSize && this.gizmoLayer.utilityLayerScene.activeCamera) {
                             rotateSpheres[index].absolutePosition.subtractToRef(this.gizmoLayer.utilityLayerScene.activeCamera.position, this._tmpVector);
@@ -109336,6 +109347,13 @@ var BABYLON;
             if (this._interactionsEnabled) {
                 this._scene.registerBeforeRender(this.beforeRender);
             }
+            if (this._displayLaserPointer) {
+                [this._leftController, this._rightController].forEach(function (controller) {
+                    if (controller) {
+                        controller._activatePointer();
+                    }
+                });
+            }
             this._hasEnteredVR = true;
         };
         /**
@@ -109410,6 +109428,11 @@ var BABYLON;
                 }
                 // resize to update width and height when exiting vr exits fullscreen
                 this._scene.getEngine().resize();
+                [this._leftController, this._rightController].forEach(function (controller) {
+                    if (controller) {
+                        controller._deactivatePointer();
+                    }
+                });
                 this._hasEnteredVR = false;
             }
         };
@@ -109547,7 +109570,9 @@ var BABYLON;
             var controllerMesh = controller.webVRController.mesh;
             if (controllerMesh) {
                 controller._interactionsEnabled = true;
-                controller._activatePointer();
+                if (this.isInVRMode && this._displayLaserPointer) {
+                    controller._activatePointer();
+                }
                 if (this.webVROptions.laserToggle) {
                     controller.webVRController.onMainButtonStateChangedObservable.add(function (stateObject) {
                         // Enabling / disabling laserPointer

+ 87 - 62
dist/preview release/babylon.no-module.max.js

@@ -13761,23 +13761,29 @@ var BABYLON;
          * @param clearColor defines the clear color
          */
         Engine.prototype.scissorClear = function (x, y, width, height, clearColor) {
+            this.enableScissor(x, y, width, height);
+            this.clear(clearColor, true, true, true);
+            this.disableScissor();
+        };
+        /**
+         * Enable scissor test on a specific rectangle (ie. render will only be executed on a specific portion of the screen)
+         * @param x defines the x-coordinate of the top left corner of the clear rectangle
+         * @param y defines the y-coordinate of the corner of the clear rectangle
+         * @param width defines the width of the clear rectangle
+         * @param height defines the height of the clear rectangle
+         */
+        Engine.prototype.enableScissor = function (x, y, width, height) {
             var gl = this._gl;
-            // Save state
-            var curScissor = gl.getParameter(gl.SCISSOR_TEST);
-            var curScissorBox = gl.getParameter(gl.SCISSOR_BOX);
             // Change state
             gl.enable(gl.SCISSOR_TEST);
             gl.scissor(x, y, width, height);
-            // Clear
-            this.clear(clearColor, true, true, true);
-            // Restore state
-            gl.scissor(curScissorBox[0], curScissorBox[1], curScissorBox[2], curScissorBox[3]);
-            if (curScissor === true) {
-                gl.enable(gl.SCISSOR_TEST);
-            }
-            else {
-                gl.disable(gl.SCISSOR_TEST);
-            }
+        };
+        /**
+         * Disable previously set scissor test rectangle
+         */
+        Engine.prototype.disableScissor = function () {
+            var gl = this._gl;
+            gl.disable(gl.SCISSOR_TEST);
         };
         /** @hidden */
         Engine.prototype._viewport = function (x, y, width, height) {
@@ -20572,9 +20578,9 @@ var BABYLON;
             if (yawCor === void 0) { yawCor = 0; }
             if (pitchCor === void 0) { pitchCor = 0; }
             if (rollCor === void 0) { rollCor = 0; }
-            var yaw = -Math.atan2(localAxis.z, localAxis.x) - Math.PI / 2;
+            var yaw = -Math.atan2(localAxis.z, localAxis.x) + Math.PI / 2;
             var len = Math.sqrt(localAxis.x * localAxis.x + localAxis.z * localAxis.z);
-            var pitch = Math.atan2(localAxis.y, len);
+            var pitch = -Math.atan2(localAxis.y, len);
             if (this.rotationQuaternion) {
                 BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
             }
@@ -66615,7 +66621,6 @@ var BABYLON;
             function AxesViewer(scene, scaleLines, renderingGroupId, xAxis, yAxis, zAxis) {
                 if (scaleLines === void 0) { scaleLines = 1; }
                 if (renderingGroupId === void 0) { renderingGroupId = 2; }
-                this._tmpVector = new BABYLON.Vector3();
                 this._scaleLinesFactor = 4;
                 this._instanced = false;
                 /**
@@ -66642,13 +66647,10 @@ var BABYLON;
                     zAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
                 }
                 this._xAxis = xAxis;
-                this._xAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._yAxis = yAxis;
-                this._yAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zAxis = zAxis;
-                this._zAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 if (renderingGroupId != null) {
                     AxesViewer._SetRenderingGroupId(this._xAxis, renderingGroupId);
@@ -66691,16 +66693,13 @@ var BABYLON;
              */
             AxesViewer.prototype.update = function (position, xaxis, yaxis, zaxis) {
                 this._xAxis.position.copyFrom(position);
-                xaxis.scaleToRef(-1, this._tmpVector);
-                this._xAxis.setDirection(this._tmpVector);
+                this._xAxis.setDirection(xaxis);
                 this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._yAxis.position.copyFrom(position);
-                yaxis.scaleToRef(-1, this._tmpVector);
-                this._yAxis.setDirection(this._tmpVector);
+                this._yAxis.setDirection(yaxis);
                 this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zAxis.position.copyFrom(position);
-                zaxis.scaleToRef(-1, this._tmpVector);
-                this._zAxis.setDirection(this._tmpVector);
+                this._zAxis.setDirection(zaxis);
                 this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
             };
             /**
@@ -70727,7 +70726,7 @@ var BABYLON;
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
                 plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
-                plane.setDirection(options.sourcePlane.normal);
+                plane.setDirection(options.sourcePlane.normal.scale(-1));
             }
             return plane;
         };
@@ -97759,7 +97758,7 @@ var BABYLON;
                     _this._tmpQuat.copyFrom(_this.object.rotationQuaternion || new BABYLON.Quaternion());
                 }
                 if (!_this._options.disableBidirectionalTransformation) {
-                    _this.object.rotationQuaternion && _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, /*bInfo.boundingBox.centerWorld*/ _this.object.getAbsolutePivotPoint(), _this._tmpQuat);
+                    _this.object.rotationQuaternion && _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, /*bInfo.boundingBox.centerWorld*/ _this.object.getAbsolutePosition(), _this._tmpQuat);
                 }
                 _this._onBeforePhysicsStepCallbacks.forEach(function (func) {
                     func(_this);
@@ -100227,34 +100226,43 @@ var BABYLON;
             var extendSize = impostor.getObjectExtendSize();
             if (!ignoreChildren) {
                 var meshChildren = impostor.object.getChildMeshes ? impostor.object.getChildMeshes(true) : [];
-                if (meshChildren.length > 0) {
-                    returnValue = new Ammo.btCompoundShape();
-                    // Add shape of all children to the compound shape
-                    meshChildren.forEach(function (childMesh) {
-                        var childImpostor = childMesh.getPhysicsImpostor();
-                        if (childImpostor) {
-                            var shape = _this._createShape(childImpostor);
-                            // Position needs to be scaled based on parent's scaling
-                            var parentMat = childMesh.parent.getWorldMatrix().clone();
-                            var s = new BABYLON.Vector3();
-                            parentMat.decompose(s);
-                            _this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
-                            _this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion.x, childMesh.rotationQuaternion.y, childMesh.rotationQuaternion.z, childMesh.rotationQuaternion.w);
-                            _this._tmpAmmoTransform.setRotation(_this._tmpAmmoQuaternion);
-                            returnValue.addChildShape(_this._tmpAmmoTransform, shape);
-                            childImpostor.dispose();
-                        }
-                    });
+                returnValue = new Ammo.btCompoundShape();
+                // Add shape of all children to the compound shape
+                var childrenAdded = 0;
+                meshChildren.forEach(function (childMesh) {
+                    var childImpostor = childMesh.getPhysicsImpostor();
+                    if (childImpostor) {
+                        var shape = _this._createShape(childImpostor);
+                        // Position needs to be scaled based on parent's scaling
+                        var parentMat = childMesh.parent.getWorldMatrix().clone();
+                        var s = new BABYLON.Vector3();
+                        parentMat.decompose(s);
+                        _this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
+                        _this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion.x, childMesh.rotationQuaternion.y, childMesh.rotationQuaternion.z, childMesh.rotationQuaternion.w);
+                        _this._tmpAmmoTransform.setRotation(_this._tmpAmmoQuaternion);
+                        returnValue.addChildShape(_this._tmpAmmoTransform, shape);
+                        childImpostor.dispose();
+                        childrenAdded++;
+                    }
+                });
+                if (childrenAdded > 0) {
                     // Add parents shape as a child if present
-                    var shape = this._createShape(impostor, true);
-                    if (shape) {
-                        this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
-                        this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
-                        this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
-                        returnValue.addChildShape(this._tmpAmmoTransform, shape);
+                    if (impostor.type != BABYLON.PhysicsImpostor.NoImpostor) {
+                        var shape = this._createShape(impostor, true);
+                        if (shape) {
+                            this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
+                            this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
+                            this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
+                            returnValue.addChildShape(this._tmpAmmoTransform, shape);
+                        }
                     }
                     return returnValue;
                 }
+                else {
+                    // If no children with impostors create the actual shape below instead
+                    Ammo.destroy(returnValue);
+                    returnValue = null;
+                }
             }
             switch (impostor.type) {
                 case BABYLON.PhysicsImpostor.SphereImpostor:
@@ -100284,6 +100292,9 @@ var BABYLON;
                     // Fill with sphere but collision is disabled on the rigid body in generatePhysicsBody, using an empty shape caused unexpected movement with joints
                     returnValue = new Ammo.btSphereShape(extendSize.x / 2);
                     break;
+                default:
+                    BABYLON.Tools.Warn("The impostor type is not currently supported by the ammo plugin.");
+                    break;
             }
             return returnValue;
         };
@@ -103516,13 +103527,13 @@ var BABYLON;
                 BABYLON.Vector3.CrossToRef(this._lineA, this._lookAt, this._lookAt);
                 this._lookAt.normalize();
                 this._dragPlane.position.copyFrom(this._pointA);
-                this._pointA.subtractToRef(this._lookAt, this._lookAt);
+                this._pointA.addToRef(this._lookAt, this._lookAt);
                 this._dragPlane.lookAt(this._lookAt);
             }
             else if (this._options.dragPlaneNormal) {
                 this.useObjectOrienationForDragging ? BABYLON.Vector3.TransformCoordinatesToRef(this._options.dragPlaneNormal, this._attachedNode.getWorldMatrix().getRotationMatrix(), this._localAxis) : this._localAxis.copyFrom(this._options.dragPlaneNormal);
                 this._dragPlane.position.copyFrom(this._pointA);
-                this._pointA.subtractToRef(this._localAxis, this._lookAt);
+                this._pointA.addToRef(this._localAxis, this._lookAt);
                 this._dragPlane.lookAt(this._lookAt);
             }
             else {
@@ -103752,7 +103763,7 @@ var BABYLON;
                         lastSixDofOriginPosition.copyFrom(pointerInfo.pickInfo.ray.origin);
                         // Set position and orientation of the controller
                         _this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
-                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
+                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.add(pointerInfo.pickInfo.ray.direction));
                         // Attach the virtual drag mesh to the virtual origin mesh so it can be dragged
                         _this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
                         pickedMesh.computeWorldMatrix();
@@ -103816,7 +103827,7 @@ var BABYLON;
                         }
                         // Update the controller position
                         _this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
-                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
+                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.add(pointerInfo.pickInfo.ray.direction));
                         _this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
                         // Move the virtualObjectsPosition into the picked mesh's space if needed
                         _this._targetPosition.copyFrom(_this._virtualDragMesh.absolutePosition);
@@ -104322,7 +104333,7 @@ var BABYLON;
             hoverMaterial.emissiveColor = color.add(new BABYLON.Color3(0.3, 0.3, 0.3));
             // Build mesh on root node
             var arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, coloredMaterial);
-            arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
+            arrow.lookAt(_this._rootMesh.position.add(dragAxis));
             arrow.scaling.scaleInPlace(1 / 3);
             arrow.parent = _this._rootMesh;
             var currentSnapDragDistance = 0;
@@ -104481,7 +104492,7 @@ var BABYLON;
             arrowTail.scaling.scaleInPlace(0.26);
             arrowTail.rotation.x = Math.PI / 2;
             arrowTail.material = _this._coloredMaterial;
-            arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
+            arrow.lookAt(_this._rootMesh.position.add(dragAxis));
             _this._rootMesh.addChild(arrow);
             arrow.scaling.scaleInPlace(1 / 3);
             // Add drag behavior to handle events when the gizmo is dragged
@@ -104635,7 +104646,7 @@ var BABYLON;
             rotationMesh.material = coloredMaterial;
             rotationMesh.rotation.x = Math.PI / 2;
             parentMesh.addChild(rotationMesh);
-            parentMesh.lookAt(_this._rootMesh.position.subtract(planeNormal));
+            parentMesh.lookAt(_this._rootMesh.position.add(planeNormal));
             _this._rootMesh.addChild(parentMesh);
             parentMesh.scaling.scaleInPlace(1 / 3);
             // Add drag behavior to handle events when the gizmo is dragged
@@ -105500,17 +105511,17 @@ var BABYLON;
                         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(BABYLON.Vector3.Cross(BABYLON.Vector3.Right(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Right()).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(BABYLON.Vector3.Cross(BABYLON.Vector3.Up(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Up()).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(BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Forward()).normalizeToNew().add(rotateSpheres[index].position));
                         }
                         if (this.fixedDragMeshScreenSize && this.gizmoLayer.utilityLayerScene.activeCamera) {
                             rotateSpheres[index].absolutePosition.subtractToRef(this.gizmoLayer.utilityLayerScene.activeCamera.position, this._tmpVector);
@@ -109303,6 +109314,13 @@ var BABYLON;
             if (this._interactionsEnabled) {
                 this._scene.registerBeforeRender(this.beforeRender);
             }
+            if (this._displayLaserPointer) {
+                [this._leftController, this._rightController].forEach(function (controller) {
+                    if (controller) {
+                        controller._activatePointer();
+                    }
+                });
+            }
             this._hasEnteredVR = true;
         };
         /**
@@ -109377,6 +109395,11 @@ var BABYLON;
                 }
                 // resize to update width and height when exiting vr exits fullscreen
                 this._scene.getEngine().resize();
+                [this._leftController, this._rightController].forEach(function (controller) {
+                    if (controller) {
+                        controller._deactivatePointer();
+                    }
+                });
                 this._hasEnteredVR = false;
             }
         };
@@ -109514,7 +109537,9 @@ var BABYLON;
             var controllerMesh = controller.webVRController.mesh;
             if (controllerMesh) {
                 controller._interactionsEnabled = true;
-                controller._activatePointer();
+                if (this.isInVRMode && this._displayLaserPointer) {
+                    controller._activatePointer();
+                }
                 if (this.webVROptions.laserToggle) {
                     controller.webVRController.onMainButtonStateChangedObservable.add(function (stateObject) {
                         // Enabling / disabling laserPointer

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/babylon.worker.js


+ 87 - 62
dist/preview release/es6.js

@@ -13761,23 +13761,29 @@ var BABYLON;
          * @param clearColor defines the clear color
          */
         Engine.prototype.scissorClear = function (x, y, width, height, clearColor) {
+            this.enableScissor(x, y, width, height);
+            this.clear(clearColor, true, true, true);
+            this.disableScissor();
+        };
+        /**
+         * Enable scissor test on a specific rectangle (ie. render will only be executed on a specific portion of the screen)
+         * @param x defines the x-coordinate of the top left corner of the clear rectangle
+         * @param y defines the y-coordinate of the corner of the clear rectangle
+         * @param width defines the width of the clear rectangle
+         * @param height defines the height of the clear rectangle
+         */
+        Engine.prototype.enableScissor = function (x, y, width, height) {
             var gl = this._gl;
-            // Save state
-            var curScissor = gl.getParameter(gl.SCISSOR_TEST);
-            var curScissorBox = gl.getParameter(gl.SCISSOR_BOX);
             // Change state
             gl.enable(gl.SCISSOR_TEST);
             gl.scissor(x, y, width, height);
-            // Clear
-            this.clear(clearColor, true, true, true);
-            // Restore state
-            gl.scissor(curScissorBox[0], curScissorBox[1], curScissorBox[2], curScissorBox[3]);
-            if (curScissor === true) {
-                gl.enable(gl.SCISSOR_TEST);
-            }
-            else {
-                gl.disable(gl.SCISSOR_TEST);
-            }
+        };
+        /**
+         * Disable previously set scissor test rectangle
+         */
+        Engine.prototype.disableScissor = function () {
+            var gl = this._gl;
+            gl.disable(gl.SCISSOR_TEST);
         };
         /** @hidden */
         Engine.prototype._viewport = function (x, y, width, height) {
@@ -20572,9 +20578,9 @@ var BABYLON;
             if (yawCor === void 0) { yawCor = 0; }
             if (pitchCor === void 0) { pitchCor = 0; }
             if (rollCor === void 0) { rollCor = 0; }
-            var yaw = -Math.atan2(localAxis.z, localAxis.x) - Math.PI / 2;
+            var yaw = -Math.atan2(localAxis.z, localAxis.x) + Math.PI / 2;
             var len = Math.sqrt(localAxis.x * localAxis.x + localAxis.z * localAxis.z);
-            var pitch = Math.atan2(localAxis.y, len);
+            var pitch = -Math.atan2(localAxis.y, len);
             if (this.rotationQuaternion) {
                 BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
             }
@@ -66615,7 +66621,6 @@ var BABYLON;
             function AxesViewer(scene, scaleLines, renderingGroupId, xAxis, yAxis, zAxis) {
                 if (scaleLines === void 0) { scaleLines = 1; }
                 if (renderingGroupId === void 0) { renderingGroupId = 2; }
-                this._tmpVector = new BABYLON.Vector3();
                 this._scaleLinesFactor = 4;
                 this._instanced = false;
                 /**
@@ -66642,13 +66647,10 @@ var BABYLON;
                     zAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
                 }
                 this._xAxis = xAxis;
-                this._xAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._yAxis = yAxis;
-                this._yAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zAxis = zAxis;
-                this._zAxis.rotationQuaternion = new BABYLON.Quaternion();
                 this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 if (renderingGroupId != null) {
                     AxesViewer._SetRenderingGroupId(this._xAxis, renderingGroupId);
@@ -66691,16 +66693,13 @@ var BABYLON;
              */
             AxesViewer.prototype.update = function (position, xaxis, yaxis, zaxis) {
                 this._xAxis.position.copyFrom(position);
-                xaxis.scaleToRef(-1, this._tmpVector);
-                this._xAxis.setDirection(this._tmpVector);
+                this._xAxis.setDirection(xaxis);
                 this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._yAxis.position.copyFrom(position);
-                yaxis.scaleToRef(-1, this._tmpVector);
-                this._yAxis.setDirection(this._tmpVector);
+                this._yAxis.setDirection(yaxis);
                 this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zAxis.position.copyFrom(position);
-                zaxis.scaleToRef(-1, this._tmpVector);
-                this._zAxis.setDirection(this._tmpVector);
+                this._zAxis.setDirection(zaxis);
                 this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
             };
             /**
@@ -70727,7 +70726,7 @@ var BABYLON;
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
                 plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
-                plane.setDirection(options.sourcePlane.normal);
+                plane.setDirection(options.sourcePlane.normal.scale(-1));
             }
             return plane;
         };
@@ -97759,7 +97758,7 @@ var BABYLON;
                     _this._tmpQuat.copyFrom(_this.object.rotationQuaternion || new BABYLON.Quaternion());
                 }
                 if (!_this._options.disableBidirectionalTransformation) {
-                    _this.object.rotationQuaternion && _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, /*bInfo.boundingBox.centerWorld*/ _this.object.getAbsolutePivotPoint(), _this._tmpQuat);
+                    _this.object.rotationQuaternion && _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, /*bInfo.boundingBox.centerWorld*/ _this.object.getAbsolutePosition(), _this._tmpQuat);
                 }
                 _this._onBeforePhysicsStepCallbacks.forEach(function (func) {
                     func(_this);
@@ -100227,34 +100226,43 @@ var BABYLON;
             var extendSize = impostor.getObjectExtendSize();
             if (!ignoreChildren) {
                 var meshChildren = impostor.object.getChildMeshes ? impostor.object.getChildMeshes(true) : [];
-                if (meshChildren.length > 0) {
-                    returnValue = new Ammo.btCompoundShape();
-                    // Add shape of all children to the compound shape
-                    meshChildren.forEach(function (childMesh) {
-                        var childImpostor = childMesh.getPhysicsImpostor();
-                        if (childImpostor) {
-                            var shape = _this._createShape(childImpostor);
-                            // Position needs to be scaled based on parent's scaling
-                            var parentMat = childMesh.parent.getWorldMatrix().clone();
-                            var s = new BABYLON.Vector3();
-                            parentMat.decompose(s);
-                            _this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
-                            _this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion.x, childMesh.rotationQuaternion.y, childMesh.rotationQuaternion.z, childMesh.rotationQuaternion.w);
-                            _this._tmpAmmoTransform.setRotation(_this._tmpAmmoQuaternion);
-                            returnValue.addChildShape(_this._tmpAmmoTransform, shape);
-                            childImpostor.dispose();
-                        }
-                    });
+                returnValue = new Ammo.btCompoundShape();
+                // Add shape of all children to the compound shape
+                var childrenAdded = 0;
+                meshChildren.forEach(function (childMesh) {
+                    var childImpostor = childMesh.getPhysicsImpostor();
+                    if (childImpostor) {
+                        var shape = _this._createShape(childImpostor);
+                        // Position needs to be scaled based on parent's scaling
+                        var parentMat = childMesh.parent.getWorldMatrix().clone();
+                        var s = new BABYLON.Vector3();
+                        parentMat.decompose(s);
+                        _this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
+                        _this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion.x, childMesh.rotationQuaternion.y, childMesh.rotationQuaternion.z, childMesh.rotationQuaternion.w);
+                        _this._tmpAmmoTransform.setRotation(_this._tmpAmmoQuaternion);
+                        returnValue.addChildShape(_this._tmpAmmoTransform, shape);
+                        childImpostor.dispose();
+                        childrenAdded++;
+                    }
+                });
+                if (childrenAdded > 0) {
                     // Add parents shape as a child if present
-                    var shape = this._createShape(impostor, true);
-                    if (shape) {
-                        this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
-                        this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
-                        this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
-                        returnValue.addChildShape(this._tmpAmmoTransform, shape);
+                    if (impostor.type != BABYLON.PhysicsImpostor.NoImpostor) {
+                        var shape = this._createShape(impostor, true);
+                        if (shape) {
+                            this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
+                            this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
+                            this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
+                            returnValue.addChildShape(this._tmpAmmoTransform, shape);
+                        }
                     }
                     return returnValue;
                 }
+                else {
+                    // If no children with impostors create the actual shape below instead
+                    Ammo.destroy(returnValue);
+                    returnValue = null;
+                }
             }
             switch (impostor.type) {
                 case BABYLON.PhysicsImpostor.SphereImpostor:
@@ -100284,6 +100292,9 @@ var BABYLON;
                     // Fill with sphere but collision is disabled on the rigid body in generatePhysicsBody, using an empty shape caused unexpected movement with joints
                     returnValue = new Ammo.btSphereShape(extendSize.x / 2);
                     break;
+                default:
+                    BABYLON.Tools.Warn("The impostor type is not currently supported by the ammo plugin.");
+                    break;
             }
             return returnValue;
         };
@@ -103516,13 +103527,13 @@ var BABYLON;
                 BABYLON.Vector3.CrossToRef(this._lineA, this._lookAt, this._lookAt);
                 this._lookAt.normalize();
                 this._dragPlane.position.copyFrom(this._pointA);
-                this._pointA.subtractToRef(this._lookAt, this._lookAt);
+                this._pointA.addToRef(this._lookAt, this._lookAt);
                 this._dragPlane.lookAt(this._lookAt);
             }
             else if (this._options.dragPlaneNormal) {
                 this.useObjectOrienationForDragging ? BABYLON.Vector3.TransformCoordinatesToRef(this._options.dragPlaneNormal, this._attachedNode.getWorldMatrix().getRotationMatrix(), this._localAxis) : this._localAxis.copyFrom(this._options.dragPlaneNormal);
                 this._dragPlane.position.copyFrom(this._pointA);
-                this._pointA.subtractToRef(this._localAxis, this._lookAt);
+                this._pointA.addToRef(this._localAxis, this._lookAt);
                 this._dragPlane.lookAt(this._lookAt);
             }
             else {
@@ -103752,7 +103763,7 @@ var BABYLON;
                         lastSixDofOriginPosition.copyFrom(pointerInfo.pickInfo.ray.origin);
                         // Set position and orientation of the controller
                         _this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
-                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
+                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.add(pointerInfo.pickInfo.ray.direction));
                         // Attach the virtual drag mesh to the virtual origin mesh so it can be dragged
                         _this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
                         pickedMesh.computeWorldMatrix();
@@ -103816,7 +103827,7 @@ var BABYLON;
                         }
                         // Update the controller position
                         _this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
-                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
+                        _this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.add(pointerInfo.pickInfo.ray.direction));
                         _this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
                         // Move the virtualObjectsPosition into the picked mesh's space if needed
                         _this._targetPosition.copyFrom(_this._virtualDragMesh.absolutePosition);
@@ -104322,7 +104333,7 @@ var BABYLON;
             hoverMaterial.emissiveColor = color.add(new BABYLON.Color3(0.3, 0.3, 0.3));
             // Build mesh on root node
             var arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, coloredMaterial);
-            arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
+            arrow.lookAt(_this._rootMesh.position.add(dragAxis));
             arrow.scaling.scaleInPlace(1 / 3);
             arrow.parent = _this._rootMesh;
             var currentSnapDragDistance = 0;
@@ -104481,7 +104492,7 @@ var BABYLON;
             arrowTail.scaling.scaleInPlace(0.26);
             arrowTail.rotation.x = Math.PI / 2;
             arrowTail.material = _this._coloredMaterial;
-            arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
+            arrow.lookAt(_this._rootMesh.position.add(dragAxis));
             _this._rootMesh.addChild(arrow);
             arrow.scaling.scaleInPlace(1 / 3);
             // Add drag behavior to handle events when the gizmo is dragged
@@ -104635,7 +104646,7 @@ var BABYLON;
             rotationMesh.material = coloredMaterial;
             rotationMesh.rotation.x = Math.PI / 2;
             parentMesh.addChild(rotationMesh);
-            parentMesh.lookAt(_this._rootMesh.position.subtract(planeNormal));
+            parentMesh.lookAt(_this._rootMesh.position.add(planeNormal));
             _this._rootMesh.addChild(parentMesh);
             parentMesh.scaling.scaleInPlace(1 / 3);
             // Add drag behavior to handle events when the gizmo is dragged
@@ -105500,17 +105511,17 @@ var BABYLON;
                         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(BABYLON.Vector3.Cross(BABYLON.Vector3.Right(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Right()).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(BABYLON.Vector3.Cross(BABYLON.Vector3.Up(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Up()).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(BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
+                            rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), BABYLON.Vector3.Forward()).normalizeToNew().add(rotateSpheres[index].position));
                         }
                         if (this.fixedDragMeshScreenSize && this.gizmoLayer.utilityLayerScene.activeCamera) {
                             rotateSpheres[index].absolutePosition.subtractToRef(this.gizmoLayer.utilityLayerScene.activeCamera.position, this._tmpVector);
@@ -109303,6 +109314,13 @@ var BABYLON;
             if (this._interactionsEnabled) {
                 this._scene.registerBeforeRender(this.beforeRender);
             }
+            if (this._displayLaserPointer) {
+                [this._leftController, this._rightController].forEach(function (controller) {
+                    if (controller) {
+                        controller._activatePointer();
+                    }
+                });
+            }
             this._hasEnteredVR = true;
         };
         /**
@@ -109377,6 +109395,11 @@ var BABYLON;
                 }
                 // resize to update width and height when exiting vr exits fullscreen
                 this._scene.getEngine().resize();
+                [this._leftController, this._rightController].forEach(function (controller) {
+                    if (controller) {
+                        controller._deactivatePointer();
+                    }
+                });
                 this._hasEnteredVR = false;
             }
         };
@@ -109514,7 +109537,9 @@ var BABYLON;
             var controllerMesh = controller.webVRController.mesh;
             if (controllerMesh) {
                 controller._interactionsEnabled = true;
-                controller._activatePointer();
+                if (this.isInVRMode && this._displayLaserPointer) {
+                    controller._activatePointer();
+                }
                 if (this.webVROptions.laserToggle) {
                     controller.webVRController.onMainButtonStateChangedObservable.add(function (stateObject) {
                         // Enabling / disabling laserPointer

+ 21 - 7
dist/preview release/gui/babylon.gui.d.ts

@@ -1,7 +1,7 @@
 /*Babylon.js GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
-//   ../../../../Tools/gulp/2D
+//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../Tools/Gulp/2D
 declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
@@ -752,7 +752,10 @@ declare module BABYLON.GUI {
             onValueChangedObservable: BABYLON.Observable<BABYLON.Color3>;
             /** Gets or sets the color of the color picker */
             value: BABYLON.Color3;
-            /** Gets or sets control width */
+            /**
+                * Gets or sets control width
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
             width: string | number;
             /** Gets or sets control height */
             height: string | number;
@@ -765,6 +768,8 @@ declare module BABYLON.GUI {
             constructor(name?: string | undefined);
             protected _getTypeName(): string;
             /** @hidden */
+            protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            /** @hidden */
             _draw(context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
             _onPointerMove(target: Control, coordinates: BABYLON.Vector2): void;
@@ -788,8 +793,6 @@ declare module BABYLON.GUI {
             protected _adaptWidthToChildren: boolean;
             /** @hidden */
             protected _adaptHeightToChildren: boolean;
-            /** @hidden */
-            protected _rebuildLayout: boolean;
             /** Gets or sets a boolean indicating if the container should try to adapt to its children height */
             adaptHeightToChildren: boolean;
             /** Gets or sets a boolean indicating if the container should try to adapt to its children width */
@@ -921,6 +924,8 @@ declare module BABYLON.GUI {
             protected _isEnabled: boolean;
             protected _disabledColor: string;
             /** @hidden */
+            protected _rebuildLayout: boolean;
+            /** @hidden */
             _isClipped: boolean;
             /** @hidden */
             _tag: any;
@@ -997,6 +1002,10 @@ declare module BABYLON.GUI {
                 * An event triggered after the control was drawn
                 */
             onAfterDrawObservable: BABYLON.Observable<Control>;
+            /**
+                * Get the hosting AdvancedDynamicTexture
+                */
+            readonly host: AdvancedDynamicTexture;
             /** Gets or set information about font offsets (used to render and align text) */
             fontOffset: {
                     ascent: number;
@@ -1427,6 +1436,12 @@ declare module BABYLON.GUI {
                 */
             getChildrenAt(row: number, column: number): BABYLON.Nullable<Array<Control>>;
             /**
+                * Gets a string representing the child cell info (row x column)
+                * @param child defines the control to get info from
+                * @returns a string containing the child cell info (row x column)
+                */
+            getChildCellInfo(child: Control): string;
+            /**
                 * Remove a column definition at specified index
                 * @param index defines the index of the column to remove
                 * @returns the current grid
@@ -1637,6 +1652,7 @@ declare module BABYLON.GUI {
             processKeyboard(evt: KeyboardEvent): void;
             _draw(context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+            _onPointerMove(target: Control, coordinates: BABYLON.Vector2): void;
             _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
             protected _beforeRenderText(text: string): string;
             dispose(): void;
@@ -2040,8 +2056,6 @@ declare module BABYLON.GUI {
             barColor: string;
             /** Gets or sets the size of the bar */
             barSize: number;
-            /** Gets or sets the bar color */
-            barBorderColor: string;
             /** Gets or sets the bar background */
             barBackground: string;
             _link(host: AdvancedDynamicTexture): void;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/gui/babylon.gui.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 43 - 14
dist/preview release/gui/babylon.gui.module.d.ts

@@ -1,7 +1,7 @@
 /*Babylon.js GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
-//   ../../../../Tools/gulp/2D
+//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../Tools/Gulp/2D
 
 declare module 'babylonjs-gui' {
     export * from "babylonjs-gui/2D";
@@ -836,6 +836,7 @@ declare module 'babylonjs-gui/2D/controls/checkbox' {
 declare module 'babylonjs-gui/2D/controls/colorpicker' {
     import { Control } from "babylonjs-gui/2D/controls/control";
     import { Color3, Observable, Vector2 } from "babylonjs";
+    import { Measure } from "2D";
     /** Class used to create color pickers */
     export class ColorPicker extends Control {
             name?: string | undefined;
@@ -845,7 +846,10 @@ declare module 'babylonjs-gui/2D/controls/colorpicker' {
             onValueChangedObservable: Observable<Color3>;
             /** Gets or sets the color of the color picker */
             value: Color3;
-            /** Gets or sets control width */
+            /**
+                * Gets or sets control width
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
             width: string | number;
             /** Gets or sets control height */
             height: string | number;
@@ -858,6 +862,8 @@ declare module 'babylonjs-gui/2D/controls/colorpicker' {
             constructor(name?: string | undefined);
             protected _getTypeName(): string;
             /** @hidden */
+            protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            /** @hidden */
             _draw(context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
             _onPointerMove(target: Control, coordinates: Vector2): void;
@@ -886,8 +892,6 @@ declare module 'babylonjs-gui/2D/controls/container' {
             protected _adaptWidthToChildren: boolean;
             /** @hidden */
             protected _adaptHeightToChildren: boolean;
-            /** @hidden */
-            protected _rebuildLayout: boolean;
             /** Gets or sets a boolean indicating if the container should try to adapt to its children height */
             adaptHeightToChildren: boolean;
             /** Gets or sets a boolean indicating if the container should try to adapt to its children width */
@@ -1027,6 +1031,8 @@ declare module 'babylonjs-gui/2D/controls/control' {
             protected _isEnabled: boolean;
             protected _disabledColor: string;
             /** @hidden */
+            protected _rebuildLayout: boolean;
+            /** @hidden */
             _isClipped: boolean;
             /** @hidden */
             _tag: any;
@@ -1103,6 +1109,10 @@ declare module 'babylonjs-gui/2D/controls/control' {
                 * An event triggered after the control was drawn
                 */
             onAfterDrawObservable: Observable<Control>;
+            /**
+                * Get the hosting AdvancedDynamicTexture
+                */
+            readonly host: AdvancedDynamicTexture;
             /** Gets or set information about font offsets (used to render and align text) */
             fontOffset: {
                     ascent: number;
@@ -1542,6 +1552,12 @@ declare module 'babylonjs-gui/2D/controls/grid' {
                 */
             getChildrenAt(row: number, column: number): Nullable<Array<Control>>;
             /**
+                * Gets a string representing the child cell info (row x column)
+                * @param child defines the control to get info from
+                * @returns a string containing the child cell info (row x column)
+                */
+            getChildCellInfo(child: Control): string;
+            /**
                 * Remove a column definition at specified index
                 * @param index defines the index of the column to remove
                 * @returns the current grid
@@ -1761,6 +1777,7 @@ declare module 'babylonjs-gui/2D/controls/inputText' {
             processKeyboard(evt: KeyboardEvent): void;
             _draw(context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+            _onPointerMove(target: Control, coordinates: Vector2): void;
             _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
             protected _beforeRenderText(text: string): string;
             dispose(): void;
@@ -2191,8 +2208,6 @@ declare module 'babylonjs-gui/2D/controls/scrollViewers/scrollViewer' {
             barColor: string;
             /** Gets or sets the size of the bar */
             barSize: number;
-            /** Gets or sets the bar color */
-            barBorderColor: string;
             /** Gets or sets the bar background */
             barBackground: string;
             _link(host: AdvancedDynamicTexture): void;
@@ -3155,8 +3170,8 @@ declare module 'babylonjs-gui/3D/materials/fluentMaterial' {
 
 /*Babylon.js GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
-//   ../../../../Tools/gulp/2D
+//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../Tools/Gulp/2D
 declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
@@ -3907,7 +3922,10 @@ declare module BABYLON.GUI {
             onValueChangedObservable: BABYLON.Observable<BABYLON.Color3>;
             /** Gets or sets the color of the color picker */
             value: BABYLON.Color3;
-            /** Gets or sets control width */
+            /**
+                * Gets or sets control width
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
             width: string | number;
             /** Gets or sets control height */
             height: string | number;
@@ -3920,6 +3938,8 @@ declare module BABYLON.GUI {
             constructor(name?: string | undefined);
             protected _getTypeName(): string;
             /** @hidden */
+            protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            /** @hidden */
             _draw(context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
             _onPointerMove(target: Control, coordinates: BABYLON.Vector2): void;
@@ -3943,8 +3963,6 @@ declare module BABYLON.GUI {
             protected _adaptWidthToChildren: boolean;
             /** @hidden */
             protected _adaptHeightToChildren: boolean;
-            /** @hidden */
-            protected _rebuildLayout: boolean;
             /** Gets or sets a boolean indicating if the container should try to adapt to its children height */
             adaptHeightToChildren: boolean;
             /** Gets or sets a boolean indicating if the container should try to adapt to its children width */
@@ -4076,6 +4094,8 @@ declare module BABYLON.GUI {
             protected _isEnabled: boolean;
             protected _disabledColor: string;
             /** @hidden */
+            protected _rebuildLayout: boolean;
+            /** @hidden */
             _isClipped: boolean;
             /** @hidden */
             _tag: any;
@@ -4152,6 +4172,10 @@ declare module BABYLON.GUI {
                 * An event triggered after the control was drawn
                 */
             onAfterDrawObservable: BABYLON.Observable<Control>;
+            /**
+                * Get the hosting AdvancedDynamicTexture
+                */
+            readonly host: AdvancedDynamicTexture;
             /** Gets or set information about font offsets (used to render and align text) */
             fontOffset: {
                     ascent: number;
@@ -4582,6 +4606,12 @@ declare module BABYLON.GUI {
                 */
             getChildrenAt(row: number, column: number): BABYLON.Nullable<Array<Control>>;
             /**
+                * Gets a string representing the child cell info (row x column)
+                * @param child defines the control to get info from
+                * @returns a string containing the child cell info (row x column)
+                */
+            getChildCellInfo(child: Control): string;
+            /**
                 * Remove a column definition at specified index
                 * @param index defines the index of the column to remove
                 * @returns the current grid
@@ -4792,6 +4822,7 @@ declare module BABYLON.GUI {
             processKeyboard(evt: KeyboardEvent): void;
             _draw(context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+            _onPointerMove(target: Control, coordinates: BABYLON.Vector2): void;
             _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
             protected _beforeRenderText(text: string): string;
             dispose(): void;
@@ -5195,8 +5226,6 @@ declare module BABYLON.GUI {
             barColor: string;
             /** Gets or sets the size of the bar */
             barSize: number;
-            /** Gets or sets the bar color */
-            barBorderColor: string;
             /** Gets or sets the bar background */
             barBackground: string;
             _link(host: AdvancedDynamicTexture): void;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 7 - 7
dist/preview release/inspector/babylon.inspector.bundle.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


+ 1 - 1
dist/preview release/inspector/babylon.inspector.d.ts

@@ -1,6 +1,6 @@
 /*Babylon.js Inspector*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 declare module INSPECTOR {
 }
 declare module INSPECTOR {

+ 2 - 2
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -1,6 +1,6 @@
 /*Babylon.js Inspector*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 
 declare module 'babylonjs-inspector' {
     export * from "babylonjs-inspector/inspector";
@@ -31,7 +31,7 @@ declare module 'babylonjs-inspector/components/propertyChangedEvent' {
 
 /*Babylon.js Inspector*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 declare module INSPECTOR {
 }
 declare module INSPECTOR {

+ 2 - 6
dist/preview release/viewer/babylon.viewer.d.ts

@@ -2,14 +2,10 @@
 /// <reference path="./babylon.glTF2Interface.d.ts"/>
 /// <reference path="./babylonjs.loaders.d.ts"/>
 declare module "babylonjs-loaders"{ export=BABYLON;}
-/// <reference path="./babylon.d.ts"/>
-/// <reference path="./babylon.glTF2Interface.d.ts"/>
-/// <reference path="./babylonjs.loaders.d.ts"/>
-declare module "babylonjs-loaders"{ export=BABYLON;}
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../../Tools/gulp/babylonjs
-//   ../../../../../Tools/gulp/babylonjs-loaders
+//   ../../../../../Tools/Gulp/babylonjs
+//   ../../../../../Tools/Gulp/babylonjs-loaders
 declare module BabylonViewer {
     /**
         * BabylonJS Viewer

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 4 - 4
dist/preview release/viewer/babylon.viewer.max.js


+ 2 - 7
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -3,15 +3,10 @@
 /// <reference path="./babylonjs.loaders.d.ts"/>
 declare module "babylonjs-loaders"{ export=BABYLON;}
 
-/// <reference path="./babylon.d.ts"/>
-/// <reference path="./babylon.glTF2Interface.d.ts"/>
-/// <reference path="./babylonjs.loaders.d.ts"/>
-declare module "babylonjs-loaders"{ export=BABYLON;}
-
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../../Tools/gulp/babylonjs
-//   ../../../../../Tools/gulp/babylonjs-loaders
+//   ../../../../../Tools/Gulp/babylonjs
+//   ../../../../../Tools/Gulp/babylonjs-loaders
 
 declare module 'babylonjs-viewer' {
     import { mapperManager } from 'babylonjs-viewer/configuration/mappers';

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

@@ -33,9 +33,11 @@
 - Added `inputText.onTextCopyObservable`, `inputText.onTextCutObservable` and `inputText.onTextPasteObservable` to inputText ([Saket Saurabh](https://github.com/ssaket))
 - Added `AdvancedDynamicTexture.onClipboardObservable` to observe for clipboard events in AdvancedDynamicTexture([Saket Saurabh](https://github.com/ssaket))
 - Added `inputText.onFocusSelectAll` to allow complete selection of text on focus event.([Saket Saurabh](https://github.com/ssaket))
+- Added mouse drag to highlight text in inputText ([Saket Saurabh](https://github.com/ssaket))
 
 ### Core Engine
 
+- Added support for Scissor testing ([Deltakosh](https://github.com/deltakosh))
 - Added `Engine.onNewSceneAddedObservable` ([Deltakosh](https://github.com/deltakosh))
 - Added new `PassCubePostProcess` to render cube map content ([Deltakosh](https://github.com/deltakosh))
 - Added support for utility layer for SkeletonViewer ([Deltakosh](https://github.com/deltakosh))
@@ -93,6 +95,7 @@
 ### Materials Library
 
 ## Bug fixes
+- Fixed TransformNode.setDirection (orientation was wrong) ([Deltakosh](https://github.com/deltakosh))
 - Fixed ArcRotateCamera control when upVector was modified ([Deltakosh](https://github.com/deltakosh))
 - Fixed anaglyph mode for Free and Universal cameras ([Deltakosh](https://github.com/deltakosh))
 - Fixed FileLoader's loading of a skybox, & added a parsed value for whether to create with PBR or STDMaterial ([Palmer-JC](https://github.com/Palmer-JC))
@@ -110,7 +113,10 @@
 - MakeNotPickableAndWrapInBoundingBox had unexpected behavior when input had scaling of 0 on an axis ([TrevorDev](https://github.com/TrevorDev))
 - Fixed an issue with loading base64 encoded images in the glTF loader ([bghgary](https://github.com/bghgary))
 - In multi-camera scenes the inspector would cause the camera's interaction events to get detached ([TrevorDev](https://github.com/TrevorDev))
+- Fix delete highlighted text after keyboard input, beat delay after double click event in InputText ([Saket Saurabh](https://github.com/ssaket))
 - SixDofDragBehavior will support when the camera is parented ([TrevorDev](https://github.com/TrevorDev))
+- Deactivate webvr lasers when not in vr ([TrevorDev](https://github.com/TrevorDev))
+- Update physics position using absolutePosition instead of pivotPosition ([TrevorDev](https://github.com/TrevorDev))
 
 ### Core Engine
 - Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))

+ 54 - 3
gui/src/2D/controls/colorpicker.ts

@@ -1,8 +1,10 @@
 import { Control } from "./control";
 import { Color3, Observable, Vector2 } from "babylonjs";
+import { Measure } from "2D";
 
 /** Class used to create color pickers */
 export class ColorPicker extends Control {
+    private static _Epsilon = 0.000001;
     private _colorWheelCanvas: HTMLCanvasElement;
 
     private _value: Color3 = Color3.Red();
@@ -44,10 +46,41 @@ export class ColorPicker extends Control {
 
         this._markAsDirty();
 
+        if (this._value.r <= ColorPicker._Epsilon) {
+            this._value.r = 0;
+        }
+
+        if (this._value.g <= ColorPicker._Epsilon) {
+            this._value.g = 0;
+        }
+
+        if (this._value.b <= ColorPicker._Epsilon) {
+            this._value.b = 0;
+        }
+
+        if (this._value.r >= 1.0 - ColorPicker._Epsilon) {
+            this._value.r = 1.0;
+        }
+
+        if (this._value.g >= 1.0 - ColorPicker._Epsilon) {
+            this._value.g = 1.0;
+        }
+
+        if (this._value.b >= 1.0 - ColorPicker._Epsilon) {
+            this._value.b = 1.0;
+        }
+
         this.onValueChangedObservable.notifyObservers(this._value);
     }
 
-    /** Gets or sets control width */
+    /**
+     * Gets or sets control width
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get width(): string | number {
+        return this._width.toString(this._host);
+    }
+
     public set width(value: string | number) {
         if (this._width.toString(this._host) === value) {
             return;
@@ -59,6 +92,14 @@ export class ColorPicker extends Control {
         }
     }
 
+    /**
+     * Gets or sets control height
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get height(): string | number {
+        return this._height.toString(this._host);
+    }
+
     /** Gets or sets control height */
     public set height(value: string | number) {
         if (this._height.toString(this._host) === value) {
@@ -95,6 +136,16 @@ export class ColorPicker extends Control {
         return "ColorPicker";
     }
 
+    /** @hidden */
+    protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+
+        if (parentMeasure.width < parentMeasure.height) {
+            this._currentMeasure.height = parentMeasure.width;
+        } else {
+            this._currentMeasure.width = parentMeasure.height;
+        }
+    }
+
     private _updateSquareProps(): void {
         var radius = Math.min(this._currentMeasure.width, this._currentMeasure.height) * .5;
         var wheelThickness = radius * .2;
@@ -340,9 +391,9 @@ export class ColorPicker extends Control {
             this._s = (x - this._squareLeft) / this._squareSize;
             this._v = 1 - (y - this._squareTop) / this._squareSize;
             this._s = Math.min(this._s, 1);
-            this._s = Math.max(this._s, 0.00001);
+            this._s = Math.max(this._s, ColorPicker._Epsilon);
             this._v = Math.min(this._v, 1);
-            this._v = Math.max(this._v, 0.00001);
+            this._v = Math.max(this._v, ColorPicker._Epsilon);
         }
 
         this._HSVtoRGB(this._h, this._s, this._v, this._tmpColor);

+ 2 - 8
gui/src/2D/controls/container.ts

@@ -18,8 +18,6 @@ export class Container extends Control {
     protected _adaptWidthToChildren = false;
     /** @hidden */
     protected _adaptHeightToChildren = false;
-    /** @hidden */
-    protected _rebuildLayout = false;
 
     /** Gets or sets a boolean indicating if the container should try to adapt to its children height */
     public get adaptHeightToChildren(): boolean {
@@ -247,6 +245,7 @@ export class Container extends Control {
     /** @hidden */
     protected _localDraw(context: CanvasRenderingContext2D): void {
         if (this._background) {
+            context.save();
             if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                 context.shadowColor = this.shadowColor;
                 context.shadowBlur = this.shadowBlur;
@@ -256,12 +255,7 @@ export class Container extends Control {
 
             context.fillStyle = this._background;
             context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
-
-            if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
-                context.shadowBlur = 0;
-                context.shadowOffsetX = 0;
-                context.shadowOffsetY = 0;
-            }
+            context.restore();
         }
     }
 

+ 20 - 1
gui/src/2D/controls/control.ts

@@ -82,6 +82,8 @@ export class Control {
     private _downPointerIds: { [id: number]: boolean } = {};
     protected _isEnabled = true;
     protected _disabledColor = "#9a9a9a";
+    /** @hidden */
+    protected _rebuildLayout = false;
 
     /** @hidden */
     public _isClipped = false;
@@ -237,6 +239,13 @@ export class Control {
      */
     public onAfterDrawObservable = new Observable<Control>();
 
+    /**
+     * Get the hosting AdvancedDynamicTexture
+     */
+    public get host(): AdvancedDynamicTexture {
+        return this._host;
+    }
+
     /** Gets or set information about font offsets (used to render and align text) */
     public get fontOffset(): { ascent: number, height: number, descent: number } {
         return this._fontOffset;
@@ -1170,7 +1179,17 @@ export class Control {
 
         this._applyStates(context);
 
-        this._processMeasures(parentMeasure, context);
+        let rebuildCount = 0;
+        do {
+            this._rebuildLayout = false;
+            this._processMeasures(parentMeasure, context);
+            rebuildCount++;
+        }
+        while (this._rebuildLayout && rebuildCount < 3);
+
+        if (rebuildCount >= 3) {
+            BABYLON.Tools.Error(`Layout cycle detected in GUI (Control uniqueId=${this.uniqueId})`);
+        }
 
         context.restore();
 

+ 9 - 0
gui/src/2D/controls/grid.ts

@@ -150,6 +150,15 @@ export class Grid extends Container {
         return cell.children;
     }
 
+    /**
+     * Gets a string representing the child cell info (row x column)
+     * @param child defines the control to get info from
+     * @returns a string containing the child cell info (row x column)
+     */
+    public getChildCellInfo(child: Control): string {
+        return child._tag;
+    }
+
     private _removeCell(cell: Container, key: string) {
         if (!cell) {
             return;

+ 194 - 28
gui/src/2D/controls/inputText.ts

@@ -33,7 +33,9 @@ export class InputText extends Control implements IFocusableControl {
     private _highlightedText = "";
     private _startHighlightIndex = 0;
     private _endHighlightIndex = 0;
+    private _cursorIndex = -1;
     private _onFocusSelectAll = false;
+    private _isPointerDown = false;
     private _onClipboardObserver: Nullable<Observer<ClipboardInfo>>;
     private _onPointerDblTapObserver: Nullable<Observer<PointerInfo>>;
 
@@ -304,6 +306,7 @@ export class InputText extends Control implements IFocusableControl {
         super(name);
 
         this.text = text;
+        this.isPointerBlocker = true;
     }
 
     /** @hidden */
@@ -480,58 +483,156 @@ export class InputText extends Control implements IFocusableControl {
                 return;
             case 13: // RETURN
                 this._host.focusedControl = null;
+                this._isTextHighlightOn = false;
                 return;
             case 35: // END
                 this._cursorOffset = 0;
                 this._blinkIsEven = false;
+                this._isTextHighlightOn = false;
                 this._markAsDirty();
                 return;
             case 36: // HOME
                 this._cursorOffset = this._text.length;
                 this._blinkIsEven = false;
+                this._isTextHighlightOn = false;
                 this._markAsDirty();
                 return;
             case 37: // LEFT
+                this._cursorOffset++;
+                if (this._cursorOffset > this._text.length) {
+                    this._cursorOffset = this._text.length;
+                }
+
                 if (evt && evt.shiftKey) {
+                    // update the cursor
+                    this._blinkIsEven = false;
+                    // shift + ctrl/cmd + <-
+                    if (evt.ctrlKey || evt.metaKey) {
+                        if (!this._isTextHighlightOn) {
+                            if (this._text.length === this._cursorOffset) {
+                                return;
+                            }
+                            else {
+                                this._endHighlightIndex = this._text.length - this._cursorOffset + 1;
+                            }
+                        }
+                        this._startHighlightIndex = 0;
+                        this._cursorIndex = this._text.length - this._endHighlightIndex;
+                        this._cursorOffset = this._text.length;
+                        this._isTextHighlightOn = true;
+                        this._markAsDirty();
+                        return;
+                    }
+                    //store the starting point
                     if (!this._isTextHighlightOn) {
                         this._isTextHighlightOn = true;
+                        this._cursorIndex = (this._cursorOffset >= this._text.length) ? this._text.length : this._cursorOffset - 1;
+                    }
+                    //if text is already highlighted
+                    else if (this._cursorIndex === -1) {
+                        this._cursorIndex = this._text.length - this._endHighlightIndex;
+                        this._cursorOffset = (this._startHighlightIndex === 0) ? this._text.length : this._text.length - this._startHighlightIndex + 1;
+                    }
+                    //set the highlight indexes
+                    if (this._cursorIndex < this._cursorOffset) {
+                        this._endHighlightIndex = this._text.length - this._cursorIndex;
+                        this._startHighlightIndex = this._text.length - this._cursorOffset;
+                    }
+                    else if (this._cursorIndex > this._cursorOffset) {
                         this._endHighlightIndex = this._text.length - this._cursorOffset;
-                        this._startHighlightIndex = this._endHighlightIndex;
+                        this._startHighlightIndex = this._text.length - this._cursorIndex;
+                    }
+                    else {
+                        this._isTextHighlightOn = false;
                     }
-                    (this._startHighlightIndex < 0) ? 0 : --this._startHighlightIndex;
+                    this._markAsDirty();
+                    return;
                 }
-                this._cursorOffset++;
-                if (this._cursorOffset > this._text.length) {
-                    this._cursorOffset = this._text.length;
+                if (this._isTextHighlightOn) {
+                    this._cursorOffset = this._text.length - this._startHighlightIndex;
+                    this._isTextHighlightOn = false;
+                }
+                if (evt && (evt.ctrlKey || evt.metaKey)) {
+                    this._cursorOffset = this.text.length;
+                    evt.preventDefault();
                 }
                 this._blinkIsEven = false;
+                this._isTextHighlightOn = false;
+                this._cursorIndex = -1;
                 this._markAsDirty();
                 return;
             case 39: // RIGHT
+                this._cursorOffset--;
+                if (this._cursorOffset < 0) {
+                    this._cursorOffset = 0;
+                }
                 if (evt && evt.shiftKey) {
+                    //update the cursor
+                    this._blinkIsEven = false;
+                    //shift + ctrl/cmd + ->
+                    if (evt.ctrlKey || evt.metaKey) {
+                        if (!this._isTextHighlightOn) {
+                            if (this._cursorOffset === 0) {
+                                return;
+                            }
+                            else {
+                                this._startHighlightIndex = this._text.length - this._cursorOffset - 1;
+                            }
+                        }
+                        this._endHighlightIndex = this._text.length;
+                        this._isTextHighlightOn = true;
+                        this._cursorIndex = this._text.length - this._startHighlightIndex;
+                        this._cursorOffset = 0;
+                        this._markAsDirty();
+                        return;
+                    }
+
                     if (!this._isTextHighlightOn) {
                         this._isTextHighlightOn = true;
+                        this._cursorIndex = (this._cursorOffset <= 0) ? 0 : this._cursorOffset + 1;
+                    }
+                    //if text is already highlighted
+                    else if (this._cursorIndex === -1) {
+                        this._cursorIndex = this._text.length - this._startHighlightIndex;
+                        this._cursorOffset = (this._text.length === this._endHighlightIndex) ? 0 : this._text.length - this._endHighlightIndex - 1;
+                    }
+                    //set the highlight indexes
+                    if (this._cursorIndex < this._cursorOffset) {
+                        this._endHighlightIndex = this._text.length - this._cursorIndex;
                         this._startHighlightIndex = this._text.length - this._cursorOffset;
-                        this._endHighlightIndex = this._startHighlightIndex;
                     }
-                    (this._endHighlightIndex > this._text.length) ? this._text.length - 1 : ++this._endHighlightIndex;
+                    else if (this._cursorIndex > this._cursorOffset) {
+                        this._endHighlightIndex = this._text.length - this._cursorOffset;
+                        this._startHighlightIndex = this._text.length - this._cursorIndex;
+                    }
+                    else {
+                        this._isTextHighlightOn = false;
+                    }
+                    this._markAsDirty();
+                    return;
                 }
-                this._cursorOffset--;
-                if (this._cursorOffset < 0) {
+                if (this._isTextHighlightOn) {
+                    this._cursorOffset = this._text.length - this._endHighlightIndex;
+                    this._isTextHighlightOn = false;
+                }
+                //ctr + ->
+                if (evt && (evt.ctrlKey || evt.metaKey)) {
                     this._cursorOffset = 0;
+                    evt.preventDefault();
                 }
                 this._blinkIsEven = false;
+                this._isTextHighlightOn = false;
+                this._cursorIndex = -1;
                 this._markAsDirty();
                 return;
             case 222: // Dead
                 if (evt) {
                     evt.preventDefault();
                 }
+                this._cursorIndex = -1;
                 this.deadKey = true;
                 break;
         }
-        this._isTextHighlightOn = false;
-
         // Printable characters
         if (key &&
             ((keyCode === -1) ||                     // Direct access
@@ -545,42 +646,78 @@ export class InputText extends Control implements IFocusableControl {
             this.onBeforeKeyAddObservable.notifyObservers(this);
             key = this._currentKey;
             if (this._addKey) {
-                if (this._cursorOffset === 0) {
+                if (this._isTextHighlightOn) {
+                    this.text = this._text.slice(0, this._startHighlightIndex) + key + this._text.slice(this._endHighlightIndex);
+                    this._cursorOffset = this.text.length - (this._startHighlightIndex + 1);
+                    this._isTextHighlightOn = false;
+                    this._blinkIsEven = false;
+                    this._markAsDirty();
+                }
+                else if (this._cursorOffset === 0) {
                     this.text += key;
                 } else {
                     let insertPosition = this._text.length - this._cursorOffset;
-
                     this.text = this._text.slice(0, insertPosition) + key + this._text.slice(insertPosition);
                 }
             }
         }
     }
+
+    /** @hidden */
+    private _updateValueFromCursorIndex(offset: number) {
+        //update the cursor
+        this._blinkIsEven = false;
+
+        if (this._cursorIndex === -1) {
+            this._cursorIndex = offset;
+        } else {
+            if (this._cursorIndex < this._cursorOffset) {
+                this._endHighlightIndex = this._text.length - this._cursorIndex;
+                this._startHighlightIndex = this._text.length - this._cursorOffset;
+            }
+            else if (this._cursorIndex > this._cursorOffset) {
+                this._endHighlightIndex = this._text.length - this._cursorOffset;
+                this._startHighlightIndex = this._text.length - this._cursorIndex;
+            }
+            else {
+                this._isTextHighlightOn = false;
+                this._markAsDirty();
+                return;
+            }
+        }
+        this._isTextHighlightOn = true;
+        this._markAsDirty();
+    }
     /** @hidden */
     private _processDblClick(evt: PointerInfo) {
         //pre-find the start and end index of the word under cursor, speeds up the rendering
         this._startHighlightIndex = this._text.length - this._cursorOffset;
         this._endHighlightIndex = this._startHighlightIndex;
-        for (let rWord = /\w+/g, left = 1, right = 1; this._startHighlightIndex > 0 && this._endHighlightIndex < this._text.length && (left || right);) {
-            right = (this._text[this._endHighlightIndex].search(rWord) !== -1) ? ++this._endHighlightIndex : 0;
-            left = (this._text[this._startHighlightIndex - 1].search(rWord) !== -1) ? --this._startHighlightIndex : 0;
-        }
+        let rWord = /\w+/g, moveLeft, moveRight;
+        do {
+            moveRight = this._endHighlightIndex < this._text.length && (this._text[this._endHighlightIndex].search(rWord) !== -1) ? ++this._endHighlightIndex : 0;
+            moveLeft = this._startHighlightIndex > 0 && (this._text[this._startHighlightIndex - 1].search(rWord) !== -1) ? --this._startHighlightIndex : 0;
+        } while (moveLeft || moveRight);
+
+        this._cursorOffset = this.text.length - this._startHighlightIndex;
         this.onTextHighlightObservable.notifyObservers(this);
+
         this._isTextHighlightOn = true;
-        this._blinkIsEven = false;
+        this._clickedCoordinate = null;
+        this._blinkIsEven = true;
+        this._cursorIndex = -1;
+        this._markAsDirty();
     }
     /** @hidden */
     private _selectAllText() {
-        this._blinkIsEven = false;
+        this._blinkIsEven = true;
         this._isTextHighlightOn = true;
 
-        //if already highlighted pass
-        if (this._highlightedText) {
-            return;
-        }
-
         this._startHighlightIndex = 0;
         this._endHighlightIndex = this._text.length;
-        this._cursorOffset = 0;
+        this._cursorOffset = this._text.length;
+        this._cursorIndex = -1;
+        this._markAsDirty();
     }
 
     /**
@@ -691,7 +828,10 @@ export class InputText extends Control implements IFocusableControl {
 
         let rootY = this._fontOffset.ascent + (this._currentMeasure.height - this._fontOffset.height) / 2;
         let availableWidth = this._width.getValueInPixel(this._host, this._tempParentMeasure.width) - marginWidth;
-        context.save();
+
+        if (this._isFocused) {
+            context.save();
+        }
         context.beginPath();
         context.rect(clipTextLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, availableWidth + 2, this._currentMeasure.height);
         context.clip();
@@ -750,7 +890,9 @@ export class InputText extends Control implements IFocusableControl {
                     cursorLeft = clipTextLeft + availableWidth;
                     this._markAsDirty();
                 }
-                context.fillRect(cursorLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, 2, this._fontOffset.height);
+                if (!this._isTextHighlightOn) {
+                    context.fillRect(cursorLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, 2, this._fontOffset.height);
+                }
             }
 
             clearTimeout(this._blinkTimeout);
@@ -765,10 +907,20 @@ export class InputText extends Control implements IFocusableControl {
                 let highlightCursorOffsetWidth = context.measureText(this.text.substring(this._startHighlightIndex)).width;
                 let highlightCursorLeft = this._scrollLeft + this._textWidth - highlightCursorOffsetWidth;
                 this._highlightedText = this.text.substring(this._startHighlightIndex, this._endHighlightIndex);
+                let width = context.measureText(this.text.substring(this._startHighlightIndex, this._endHighlightIndex)).width;
+                if (highlightCursorLeft < clipTextLeft) {
+                    width = width - (clipTextLeft - highlightCursorLeft);
+                    if (!width) {
+                        // when using left arrow on text.length > availableWidth;
+                        // assigns the width of the first letter after clipTextLeft
+                        width = context.measureText(this.text.charAt(this.text.length - this._cursorOffset)).width;
+                    }
+                    highlightCursorLeft = clipTextLeft;
+                }
                 //for transparancy
                 context.globalAlpha = this._highligherOpacity;
                 context.fillStyle = this._textHighlightColor;
-                context.fillRect(highlightCursorLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, context.measureText(this.text.substring(this._startHighlightIndex, this._endHighlightIndex)).width, this._fontOffset.height);
+                context.fillRect(highlightCursorLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, width, this._fontOffset.height);
                 context.globalAlpha = 1.0;
             }
 
@@ -796,6 +948,9 @@ export class InputText extends Control implements IFocusableControl {
         this._clickedCoordinate = coordinates.x;
         this._isTextHighlightOn = false;
         this._highlightedText = "";
+        this._cursorIndex = -1;
+        this._isPointerDown = true;
+        this._host._capturingControl[pointerId] = this;
         if (this._host.focusedControl === this) {
             // Move cursor
             clearTimeout(this._blinkTimeout);
@@ -809,8 +964,19 @@ export class InputText extends Control implements IFocusableControl {
 
         return true;
     }
+    public _onPointerMove(target: Control, coordinates: Vector2): void {
+        if (this._host.focusedControl === this && this._isPointerDown) {
+            this._clickedCoordinate = coordinates.x;
+            this._markAsDirty();
+            this._updateValueFromCursorIndex(this._cursorOffset);
+        }
+        super._onPointerMove(target, coordinates);
+    }
 
     public _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void {
+
+        this._isPointerDown = false;
+        delete this._host._capturingControl[pointerId];
         super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
     }
 

+ 2 - 18
gui/src/2D/controls/scrollViewers/scrollViewer.ts

@@ -18,8 +18,7 @@ export class ScrollViewer extends Rectangle {
     private _horizontalBar: ScrollBar;
     private _verticalBar: ScrollBar;
     private _barColor: string;
-    private _barBorderColor: string;
-    private _barBackground: string ;
+    private _barBackground: string;
     private _barSize: number = 20;
     private _endLeft: number;
     private _endTop: number;
@@ -246,21 +245,6 @@ export class ScrollViewer extends Rectangle {
         }
     }
 
-    /** Gets or sets the bar color */
-    public get barBorderColor(): string {
-        return this._barBorderColor;
-    }
-
-    public set barBorderColor(color: string) {
-        if (this._barBorderColor === color) {
-            return;
-        }
-
-        this._barBorderColor = color;
-        this._horizontalBar.borderColor = color;
-        this._verticalBar.borderColor = color;
-    }
-
     /** Gets or sets the bar background */
     public get barBackground(): string {
         return this._barBackground;
@@ -368,7 +352,7 @@ export class ScrollViewer extends Rectangle {
         let scene = this._host.getScene();
         if (scene && this._onPointerObserver) {
             scene.onPointerObservable.remove(this._onPointerObserver);
-            this._onPointerObserver  = null;
+            this._onPointerObserver = null;
         }
         super.dispose();
     }

+ 2 - 10
gui/src/2D/controls/sliders/scrollBar.ts

@@ -68,19 +68,11 @@ export class ScrollBar extends BaseSlider {
         this._applyStates(context);
         this._prepareRenderingData("rectangle");
         var left = this._renderLeft;
-        var top = this._renderTop;
-        var width = this._renderWidth;
-        var height = this._renderHeight;
 
         const thumbPosition = this._getThumbPosition();
         context.fillStyle = this._background;
 
-        if (this.isVertical) {
-            context.fillRect(left, top, width, height + this._effectiveThumbThickness);
-        }
-        else {
-            context.fillRect(left, top, width + this._effectiveThumbThickness, height);
-        }
+        context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
 
         // Value bar
         context.fillStyle = this.color;
@@ -99,7 +91,7 @@ export class ScrollBar extends BaseSlider {
             this._thumbMeasure.height = this._currentMeasure.height;
         }
 
-        context.fillRect(this._thumbMeasure.left, this._thumbMeasure.top, this._thumbMeasure.width , this._thumbMeasure.height);
+        context.fillRect(this._thumbMeasure.left, this._thumbMeasure.top, this._thumbMeasure.width, this._thumbMeasure.height);
 
         context.restore();
     }

+ 4 - 4
gui/src/2D/controls/textBlock.ts

@@ -231,6 +231,8 @@ export class TextBlock extends Control {
             this._fontOffset = Control._GetFontOffset(context.font);
         }
 
+        super._processMeasures(parentMeasure, context);
+
         // Prepare lines
         this._lines = this._breakLines(this._currentMeasure.width, context);
         this.onLinesReadyObservable.notifyObservers(this);
@@ -250,18 +252,16 @@ export class TextBlock extends Control {
                 let newWidth = this.paddingLeftInPixels + this.paddingRightInPixels + maxLineWidth;
                 if (newWidth !== this._width.internalValue) {
                     this._width.updateInPlace(newWidth, ValueAndUnit.UNITMODE_PIXEL);
-                    this._isDirty = true;
+                    this._rebuildLayout = true;
                 }
             }
             let newHeight = this.paddingTopInPixels + this.paddingBottomInPixels + this._fontOffset.height * this._lines.length;
 
             if (newHeight !== this._height.internalValue) {
                 this._height.updateInPlace(newHeight, ValueAndUnit.UNITMODE_PIXEL);
-                this._isDirty = true;
+                this._rebuildLayout = true;
             }
         }
-
-        super._processMeasures(parentMeasure, context);
     }
 
     private _drawText(text: string, textWidth: number, y: number, context: CanvasRenderingContext2D): void {

+ 2 - 2
gui/src/3D/controls/cylinderPanel.ts

@@ -39,10 +39,10 @@ export class CylinderPanel extends VolumeBasedPanel {
 
         switch (this.orientation) {
             case Container3D.FACEORIGIN_ORIENTATION:
-                mesh.lookAt(new Vector3(-newPos.x, newPos.y, -newPos.z));
+                mesh.lookAt(new Vector3(2 * newPos.x, newPos.y, 2 * newPos.z));
                 break;
             case Container3D.FACEORIGINREVERSED_ORIENTATION:
-                mesh.lookAt(new Vector3(2 * newPos.x, newPos.y, 2 * newPos.z));
+                mesh.lookAt(new Vector3(-newPos.x, newPos.y, -newPos.z));
                 break;
             case Container3D.FACEFORWARD_ORIENTATION:
                 break;

+ 2 - 2
gui/src/3D/controls/planePanel.ts

@@ -22,12 +22,12 @@ export class PlanePanel extends VolumeBasedPanel {
         switch (this.orientation) {
             case Container3D.FACEORIGIN_ORIENTATION:
             case Container3D.FACEFORWARD_ORIENTATION:
-                target.addInPlace(new Vector3(0, 0, -1));
+                target.addInPlace(new Vector3(0, 0, 1));
                 mesh.lookAt(target);
                 break;
             case Container3D.FACEFORWARDREVERSED_ORIENTATION:
             case Container3D.FACEORIGINREVERSED_ORIENTATION:
-                target.addInPlace(new Vector3(0, 0, 1));
+                target.addInPlace(new Vector3(0, 0, -1));
                 mesh.lookAt(target);
                 break;
         }

+ 2 - 2
gui/src/3D/controls/scatterPanel.ts

@@ -39,11 +39,11 @@ export class ScatterPanel extends VolumeBasedPanel {
         switch (this.orientation) {
             case Container3D.FACEORIGIN_ORIENTATION:
             case Container3D.FACEFORWARD_ORIENTATION:
-                mesh.lookAt(new Vector3(0, 0, -1));
+                mesh.lookAt(new Vector3(0, 0, 1));
                 break;
             case Container3D.FACEFORWARDREVERSED_ORIENTATION:
             case Container3D.FACEORIGINREVERSED_ORIENTATION:
-                mesh.lookAt(new Vector3(0, 0, 1));
+                mesh.lookAt(new Vector3(0, 0, -1));
                 break;
         }
 

+ 2 - 2
gui/src/3D/controls/spherePanel.ts

@@ -40,10 +40,10 @@ export class SpherePanel extends VolumeBasedPanel {
 
         switch (this.orientation) {
             case Container3D.FACEORIGIN_ORIENTATION:
-                mesh.lookAt(new Vector3(-newPos.x, -newPos.y, -newPos.z));
+                mesh.lookAt(new Vector3(2 * newPos.x, 2 * newPos.y, 2 * newPos.z));
                 break;
             case Container3D.FACEORIGINREVERSED_ORIENTATION:
-                mesh.lookAt(new Vector3(2 * newPos.x, 2 * newPos.y, 2 * newPos.z));
+                mesh.lookAt(new Vector3(-newPos.x, -newPos.y, -newPos.z));
                 break;
             case Container3D.FACEFORWARD_ORIENTATION:
                 break;

+ 4 - 0
inspector/src/components/actionTabs/actionTabs.scss

@@ -144,6 +144,10 @@
                 -moz-user-select: none;   
                 -ms-user-select: none;    
                 user-select: none;     
+
+                .underline {
+                    border-bottom: 0.5px solid rgba(255, 255, 255, 0.5);
+                }
                 
                 .textureLinkLine {
                     display: grid;

+ 2 - 1
inspector/src/components/actionTabs/lines/textLineComponent.tsx

@@ -4,6 +4,7 @@ interface ITextLineComponentProps {
     label: string,
     value: string,
     color?: string,
+    underline?: boolean,
     onLink?: () => void
 }
 
@@ -37,7 +38,7 @@ export class TextLineComponent extends React.Component<ITextLineComponentProps>
 
     render() {
         return (
-            <div className="textLine">
+            <div className={this.props.underline ? "textLine underline" : "textLine"}>
                 <div className="label">
                     {this.props.label}
                 </div>

+ 2 - 3
inspector/src/components/actionTabs/tabs/debugTabComponent.tsx

@@ -2,8 +2,7 @@ import * as React from "react";
 import { PaneComponent, IPaneComponentProps } from "../paneComponent";
 import { LineContainerComponent } from "../lineContainerComponent";
 import { CheckBoxLineComponent } from "../lines/checkBoxLineComponent";
-import { GridPropertyGridComponent } from "./propertyGrids/gridPropertyGridComponent";
-import { SkeletonViewer, PhysicsViewer, StandardMaterial } from "babylonjs";
+import { RenderGridPropertyGridComponent } from "./propertyGrids/renderGridPropertyGridComponent";
 
 export class DebugTabComponent extends PaneComponent {
     private _skeletonViewersEnabled = false;
@@ -108,7 +107,7 @@ export class DebugTabComponent extends PaneComponent {
         return (
             <div className="pane">
                 <LineContainerComponent title="HELPERS">
-                    <GridPropertyGridComponent scene={scene} />
+                    <RenderGridPropertyGridComponent scene={scene} />
                     <CheckBoxLineComponent label="Bones" isSelected={() => this._skeletonViewersEnabled} onSelect={() => this.switchSkeletonViewers()} />
                     <CheckBoxLineComponent label="Physics" isSelected={() => this._physicsViewersEnabled} onSelect={() => this.switchPhysicsViewers()} />
                 </LineContainerComponent>

+ 10 - 2
inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx

@@ -19,7 +19,7 @@ import { TextBlockPropertyGridComponent } from "./propertyGrids/gui/textBlockPro
 import { TextBlock } from "babylonjs-gui/2D/controls/textBlock";
 import { InputText } from "babylonjs-gui/2D/controls/inputText";
 import { InputTextPropertyGridComponent } from "./propertyGrids/gui/inputTextPropertyGridComponent";
-import { ColorPicker, Image, Slider, ImageBasedSlider, Rectangle, Ellipse, Checkbox, RadioButton, Line, ScrollViewer } from "babylonjs-gui";
+import { ColorPicker, Image, Slider, ImageBasedSlider, Rectangle, Ellipse, Checkbox, RadioButton, Line, ScrollViewer, Grid } from "babylonjs-gui";
 import { ColorPickerPropertyGridComponent } from "./propertyGrids/gui/colorPickerPropertyGridComponent";
 import { AnimationGroupGridComponent } from "./propertyGrids/animationGroupPropertyGridComponent";
 import { LockObject } from "./propertyGrids/lockObject";
@@ -32,6 +32,7 @@ import { CheckboxPropertyGridComponent } from "./propertyGrids/gui/checkboxPrope
 import { RadioButtonPropertyGridComponent } from "./propertyGrids/gui/radioButtonPropertyGridComponent";
 import { LinePropertyGridComponent } from "./propertyGrids/gui/linePropertyGridComponent";
 import { ScrollViewerPropertyGridComponent } from "./propertyGrids/gui/scrollViewerPropertyGridComponent";
+import { GridPropertyGridComponent } from "./propertyGrids/gui/gridPropertyGridComponent";
 
 export class PropertyGridTabComponent extends PaneComponent {
     private _timerIntervalId: number;
@@ -215,12 +216,19 @@ export class PropertyGridTabComponent extends PaneComponent {
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
+            if (className === "Grid") {
+                const grid = entity as Grid;
+                return (<GridPropertyGridComponent grid={grid}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
             if (className === "ScrollViewer") {
                 const scrollViewer = entity as ScrollViewer;
                 return (<ScrollViewerPropertyGridComponent scrollViewer={scrollViewer}
                     lockObject={this._lockObject}
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }            
+            }
 
             if (className === "Ellipse") {
                 const ellipse = entity as Ellipse;

+ 2 - 4
inspector/src/components/actionTabs/tabs/propertyGrids/animationGroupPropertyGridComponent.tsx

@@ -75,9 +75,7 @@ export class AnimationGroupGridComponent extends React.Component<IAnimationGroup
         this.connect(this.props.animationGroup);
 
         this._onBeforeRenderObserver = this.props.scene.onBeforeRenderObservable.add(() => {
-            if (this.props.animationGroup.isPlaying) {
-                this.updateCurrentFrame(this.props.animationGroup);
-            }
+            this.updateCurrentFrame(this.props.animationGroup);
         });
     }
 
@@ -127,7 +125,7 @@ export class AnimationGroupGridComponent extends React.Component<IAnimationGroup
                 <LineContainerComponent title="CONTROLS">
                     <ButtonLineComponent label={playButtonText} onClick={() => this.playOrPause()} />
                     <SliderLineComponent label="Speed ratio" minimum={0} maximum={10} step={0.1} target={animationGroup} propertyName="speedRatio" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <SliderLineComponent ref="timeline" label="Current frame" minimum={animationGroup.from} maximum={animationGroup.to} step={(animationGroup.to - animationGroup.from) / 100.0} directValue={this.state.currentFrame} onInput={value => this.onCurrentFrameChange(value)} />
+                    <SliderLineComponent ref="timeline" label="Current frame" minimum={animationGroup.from} maximum={animationGroup.to} step={(animationGroup.to - animationGroup.from) / 1000.0} directValue={this.state.currentFrame} onInput={value => this.onCurrentFrameChange(value)} />
                 </LineContainerComponent>
                 <LineContainerComponent title="INFOS">
                     <TextLineComponent label="Animation count" value={animationGroup.targetedAnimations.length.toString()} />

+ 28 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx

@@ -9,6 +9,7 @@ import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
 import { LockObject } from "../lockObject";
 import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
+import { Grid } from "babylonjs-gui";
 
 interface ICommonControlPropertyGridComponentProps {
     control: Control;
@@ -21,6 +22,30 @@ export class CommonControlPropertyGridComponent extends React.Component<ICommonC
         super(props);
     }
 
+    renderGridInformation() {
+        const control = this.props.control;
+
+        if (!control.parent || !control.parent.parent) {
+            return null;
+        }
+
+        const gridParent = control.parent.parent;
+
+        if ((gridParent as any).rowCount === undefined) {
+            return null;
+        }
+
+        const grid = gridParent as Grid;
+        const cellInfos = grid.getChildCellInfo(control).split(":");
+
+        return (
+            <LineContainerComponent title="GRID">
+                <TextLineComponent label={"Row"} value={cellInfos[0]} />
+                <TextLineComponent label={"Column"} value={cellInfos[1]} />
+            </LineContainerComponent>
+        );
+    }
+
     render() {
         const control = this.props.control;
 
@@ -50,6 +75,9 @@ export class CommonControlPropertyGridComponent extends React.Component<ICommonC
                         <TextInputLineComponent lockObject={this.props.lockObject} label="Background" target={control} propertyName="background" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     }
                 </LineContainerComponent>
+                {
+                    this.renderGridInformation()
+                }
                 <LineContainerComponent title="ALIGNMENT">
                     <OptionsLineComponent label="Horizontal" options={horizontalOptions} target={control} propertyName="horizontalAlignment" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <OptionsLineComponent label="Vertical" options={verticalOptions} target={control} propertyName="verticalAlignment" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 80 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/gridPropertyGridComponent.tsx

@@ -0,0 +1,80 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LockObject } from "../lockObject";
+import { Grid } from "babylonjs-gui/2D/controls/grid";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { TextLineComponent } from "../../../lines/textLineComponent";
+
+interface IGridPropertyGridComponentProps {
+    grid: Grid,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class GridPropertyGridComponent extends React.Component<IGridPropertyGridComponentProps> {
+    constructor(props: IGridPropertyGridComponentProps) {
+        super(props);
+    }
+
+    renderRows() {
+        const grid = this.props.grid;
+        const rows = [];
+
+        for (var index = 0; index < grid.rowCount; index++) {
+            rows.push(grid.getRowDefinition(index)!);
+        }
+
+        return (
+            rows.map((rd, i) => {
+                return (
+                    <TextLineComponent key={`r${i}`} label={`Row ${i}`} value={rd.toString(grid.host)} underline={i === grid.rowCount - 1} />
+                )
+            })
+        );
+    }
+
+    renderColumns() {
+        const grid = this.props.grid;
+        const cols = [];
+
+        for (var index = 0; index < grid.columnCount; index++) {
+            cols.push(grid.getColumnDefinition(index)!);
+        }
+
+        return (
+            cols.map((cd, i) => {
+                return (
+                    <TextLineComponent key={`c${i}`} label={`Column ${i}`} value={cd.toString(grid.host)} />
+                )
+            })
+        );
+    }
+
+    render() {
+        const grid = this.props.grid;
+
+        const cols = [];
+
+
+
+        for (var index = 0; index < grid.rowCount; index++) {
+            cols.push(grid.getColumnDefinition(index));
+        }
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={grid} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="GRID">
+                    {
+                        this.renderRows()
+                    }
+                    {
+                        this.renderColumns()
+                    }
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 0 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/gui/scrollViewerPropertyGridComponent.tsx

@@ -32,7 +32,6 @@ export class ScrollViewerPropertyGridComponent extends React.Component<IScrollVi
                 <LineContainerComponent title="SCROLLVIEWER">
                     <FloatLineComponent lockObject={this.props.lockObject} label="Bar size" target={scrollViewer} propertyName="barSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <TextInputLineComponent lockObject={this.props.lockObject} label="Bar color" target={scrollViewer} propertyName="barColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent lockObject={this.props.lockObject} label="Bar border color" target={scrollViewer} propertyName="barBorderColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <TextInputLineComponent lockObject={this.props.lockObject} label="Bar background" target={scrollViewer} propertyName="barBackground" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Wheel precision" target={scrollViewer} propertyName="wheelPrecision" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>

+ 4 - 4
inspector/src/components/actionTabs/tabs/propertyGrids/gridPropertyGridComponent.tsx

@@ -2,14 +2,14 @@ import * as React from "react";
 import { Scene, AbstractMesh, Nullable, UtilityLayerRenderer, Tools, Mesh, Color3, Texture } from "babylonjs";
 import { CheckBoxLineComponent } from "../../lines/checkBoxLineComponent";
 
-interface IGridPropertyGridComponentProps {
-    scene: Scene;
+interface IRenderGridPropertyGridComponentProps {
+    scene: Scene
 }
 
-export class GridPropertyGridComponent extends React.Component<IGridPropertyGridComponentProps, { isEnabled: boolean }> {
+export class RenderGridPropertyGridComponent extends React.Component<IRenderGridPropertyGridComponentProps, { isEnabled: boolean }> {
     private _gridMesh: Nullable<AbstractMesh>;
 
-    constructor(props: IGridPropertyGridComponentProps) {
+    constructor(props: IRenderGridPropertyGridComponentProps) {
         super(props);
         this.state = { isEnabled: false };
     }

+ 4 - 4
inspector/src/inspector.ts

@@ -207,9 +207,9 @@ export class Inspector {
             this._OpenedPane++;
             const embedHostElement = React.createElement(EmbedHostComponent, {
                 globalState: this._GlobalState, scene: scene,
-                    noExpand: !options.enablePopup,
-                    noClose: !options.enableClose,
-                    popupMode: options.popup, onPopup: () => {
+                noExpand: !options.enablePopup,
+                noClose: !options.enableClose,
+                popupMode: options.popup, onPopup: () => {
                     ReactDOM.unmountComponentAtNode(this._EmbedHost!);
 
                     if (options.popup) {
@@ -432,7 +432,7 @@ export class Inspector {
     }
 
     private static _Cleanup() {
-        if (!this._NewCanvasContainer) {
+        if (this._NewCanvasContainer) {
             this._DestroyCanvasContainer();
         }
 

+ 25 - 25
src/Behaviors/Meshes/pointerDragBehavior.ts

@@ -58,15 +58,15 @@ import { Ray } from "Culling/ray";
          *  * 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, dragPlaneNormal: Vector3, dragDistance: number, pointerId: number}>();
+        public onDragObservable = new Observable<{ delta: Vector3, dragPlanePoint: Vector3, dragPlaneNormal: Vector3, dragDistance: number, pointerId: number }>();
         /**
          *  Fires each time a drag begins (eg. mouse down on mesh)
          */
-        public onDragStartObservable = new Observable<{dragPlanePoint: Vector3, pointerId: number}>();
+        public onDragStartObservable = new Observable<{ dragPlanePoint: Vector3, pointerId: number }>();
         /**
          *  Fires each time a drag ends (eg. mouse release after drag)
          */
-        public onDragEndObservable = new Observable<{dragPlanePoint: Vector3, pointerId: number}>();
+        public onDragEndObservable = new Observable<{ dragPlanePoint: Vector3, pointerId: number }>();
         /**
          *  If the attached mesh should be moved when dragged
          */
@@ -86,12 +86,12 @@ import { Ray } from "Culling/ray";
          */
         public useObjectOrienationForDragging = true;
 
-        private _options: {dragAxis?: Vector3, dragPlaneNormal?: Vector3};
+        private _options: { dragAxis?: Vector3, dragPlaneNormal?: Vector3 };
         /**
          * 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. If no options are specified the drag plane will always face the ray's origin (eg. camera)
          */
-        constructor(options?: {dragAxis?: Vector3, dragPlaneNormal?: Vector3}) {
+        constructor(options?: { dragAxis?: Vector3, dragPlaneNormal?: Vector3 }) {
             this._options = options ? options : {};
 
             var optionCount = 0;
@@ -116,7 +116,7 @@ import { Ray } from "Culling/ray";
         /**
          *  Initializes the behavior
          */
-        public init() {}
+        public init() { }
 
         private _tmpVector = new Vector3(0, 0, 0);
         private _alternatePickedPoint = new Vector3(0, 0, 0);
@@ -135,7 +135,7 @@ import { Ray } from "Culling/ray";
             if (!PointerDragBehavior._planeScene) {
                 if (this._debugMode) {
                     PointerDragBehavior._planeScene = this._scene;
-                }else {
+                } else {
                     PointerDragBehavior._planeScene = new Scene(this._scene.getEngine());
                     PointerDragBehavior._planeScene.detachControl();
                     this._scene.getEngine().scenes.pop();
@@ -164,11 +164,11 @@ import { Ray } from "Culling/ray";
                     if (!this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.hit && pointerInfo.pickInfo.pickedMesh && pointerInfo.pickInfo.pickedPoint && pointerInfo.pickInfo.ray && pickPredicate(pointerInfo.pickInfo.pickedMesh)) {
                         this._startDrag((<PointerEvent>pointerInfo.event).pointerId, pointerInfo.pickInfo.ray, pointerInfo.pickInfo.pickedPoint);
                     }
-                }else if (pointerInfo.type == PointerEventTypes.POINTERUP) {
+                } else if (pointerInfo.type == PointerEventTypes.POINTERUP) {
                     if (this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId) {
                         this.releaseDrag();
                     }
-                }else if (pointerInfo.type == PointerEventTypes.POINTERMOVE) {
+                } else if (pointerInfo.type == PointerEventTypes.POINTERMOVE) {
                     var pointerId = (<PointerEvent>pointerInfo.event).pointerId;
 
                     // If drag was started with anyMouseID specified, set pointerID to the next mouse that moved
@@ -190,7 +190,7 @@ import { Ray } from "Culling/ray";
 
                         if (this.currentDraggingPointerID == pointerId && this.dragging) {
                             this._moveDrag(pointerInfo.pickInfo.ray);
-                         }
+                        }
                     }
                 }
             });
@@ -213,7 +213,7 @@ import { Ray } from "Culling/ray";
          */
         public releaseDrag() {
             this.dragging = false;
-            this.onDragEndObservable.notifyObservers({dragPlanePoint: this.lastDragPosition, pointerId: this.currentDraggingPointerID});
+            this.onDragEndObservable.notifyObservers({ dragPlanePoint: this.lastDragPosition, pointerId: this.currentDraggingPointerID });
             this.currentDraggingPointerID = -1;
             this._moving = false;
 
@@ -224,7 +224,7 @@ import { Ray } from "Culling/ray";
         }
 
         private _startDragRay = new Ray(new Vector3(), new Vector3());
-        private _lastPointerRay: {[key: number]: Ray} = {};
+        private _lastPointerRay: { [key: number]: Ray } = {};
         /**
          * Simulates the start of a pointer drag event on the behavior
          * @param pointerId pointerID of the pointer that should be simulated (Default: Any mouse pointer ID)
@@ -234,7 +234,7 @@ import { Ray } from "Culling/ray";
         public startDrag(pointerId: number = PointerDragBehavior._AnyMouseID, fromRay?: Ray, startPickedPoint?: Vector3) {
             this._startDrag(pointerId, fromRay, startPickedPoint);
 
-            var lastRay =  this._lastPointerRay[pointerId];
+            var lastRay = this._lastPointerRay[pointerId];
             if (pointerId === PointerDragBehavior._AnyMouseID) {
                 lastRay = this._lastPointerRay[<any>Object.keys(this._lastPointerRay)[0]];
             }
@@ -255,7 +255,7 @@ import { Ray } from "Culling/ray";
             if (fromRay) {
                 this._startDragRay.direction.copyFrom(fromRay.direction);
                 this._startDragRay.origin.copyFrom(fromRay.origin);
-            }else {
+            } else {
                 this._startDragRay.origin.copyFrom(this._scene.activeCamera.position);
                 this._attachedNode.getWorldMatrix().getTranslationToRef(this._tmpVector);
                 this._tmpVector.subtractToRef(this._scene.activeCamera.position, this._startDragRay.direction);
@@ -268,7 +268,7 @@ import { Ray } from "Culling/ray";
                 this.dragging = true;
                 this.currentDraggingPointerID = pointerId;
                 this.lastDragPosition.copyFrom(pickedPoint);
-                this.onDragStartObservable.notifyObservers({dragPlanePoint: pickedPoint, pointerId: this.currentDraggingPointerID});
+                this.onDragStartObservable.notifyObservers({ dragPlanePoint: pickedPoint, pointerId: this.currentDraggingPointerID });
                 this._targetPosition.copyFrom((this._attachedNode).absolutePosition);
 
                 // Detatch camera controls
@@ -276,7 +276,7 @@ import { Ray } from "Culling/ray";
                     if (this._scene.activeCamera.inputs.attachedElement) {
                         this._attachedElement = this._scene.activeCamera.inputs.attachedElement;
                         this._scene.activeCamera.detachControl(this._scene.activeCamera.inputs.attachedElement);
-                    }else {
+                    } else {
                         this._attachedElement = null;
                     }
                 }
@@ -304,12 +304,12 @@ import { Ray } from "Culling/ray";
                     pickedPoint.subtractToRef(this.lastDragPosition, this._tmpVector);
                     dragLength = Vector3.Dot(this._tmpVector, this._worldDragAxis);
                     this._worldDragAxis.scaleToRef(dragLength, this._dragDelta);
-                }else {
+                } else {
                     dragLength = this._dragDelta.length();
                     pickedPoint.subtractToRef(this.lastDragPosition, this._dragDelta);
                 }
                 this._targetPosition.addInPlace(this._dragDelta);
-                this.onDragObservable.notifyObservers({dragDistance: dragLength, delta: this._dragDelta, dragPlanePoint: pickedPoint, dragPlaneNormal: this._dragPlane.forward, pointerId: this.currentDraggingPointerID});
+                this.onDragObservable.notifyObservers({ dragDistance: dragLength, delta: this._dragDelta, dragPlanePoint: pickedPoint, dragPlaneNormal: this._dragPlane.forward, pointerId: this.currentDraggingPointerID });
                 this.lastDragPosition.copyFrom(pickedPoint);
             }
         }
@@ -342,15 +342,15 @@ import { Ray } from "Culling/ray";
                     this._alternatePickedPoint.addInPlace(this._tmpVector);
                     this._alternatePickedPoint.addInPlace((this._attachedNode).absolutePosition);
                     return this._alternatePickedPoint;
-                }else {
+                } else {
                     return null;
                 }
             }
 
-            var pickResult = PointerDragBehavior._planeScene.pickWithRay(ray, (m) => {return m == this._dragPlane; });
+            var pickResult = PointerDragBehavior._planeScene.pickWithRay(ray, (m) => { return m == this._dragPlane; });
             if (pickResult && pickResult.hit && pickResult.pickedMesh && pickResult.pickedPoint) {
                 return pickResult.pickedPoint;
-            }else {
+            } else {
                 return null;
             }
         }
@@ -382,14 +382,14 @@ import { Ray } from "Culling/ray";
                 this._lookAt.normalize();
 
                 this._dragPlane.position.copyFrom(this._pointA);
-                this._pointA.subtractToRef(this._lookAt, this._lookAt);
+                this._pointA.addToRef(this._lookAt, this._lookAt);
                 this._dragPlane.lookAt(this._lookAt);
-            }else if (this._options.dragPlaneNormal) {
+            } else if (this._options.dragPlaneNormal) {
                 this.useObjectOrienationForDragging ? Vector3.TransformCoordinatesToRef(this._options.dragPlaneNormal, this._attachedNode.getWorldMatrix().getRotationMatrix(), this._localAxis) : this._localAxis.copyFrom(this._options.dragPlaneNormal);
                 this._dragPlane.position.copyFrom(this._pointA);
-                this._pointA.subtractToRef(this._localAxis, this._lookAt);
+                this._pointA.addToRef(this._localAxis, this._lookAt);
                 this._dragPlane.lookAt(this._lookAt);
-            }else {
+            } else {
                 this._dragPlane.position.copyFrom(this._pointA);
                 this._dragPlane.lookAt(ray.origin);
             }

+ 6 - 6
src/Behaviors/Meshes/sixDofDragBehavior.ts

@@ -71,7 +71,7 @@ import { Camera } from "Cameras/camera";
         /**
          *  Initializes the behavior
          */
-        public init() {}
+        public init() { }
 
         /**
          * Attaches the scale behavior the passed in mesh
@@ -112,7 +112,7 @@ import { Camera } from "Cameras/camera";
 
                         // Set position and orientation of the controller
                         this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
-                        this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
+                        this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.add(pointerInfo.pickInfo.ray.direction));
 
                         // Attach the virtual drag mesh to the virtual origin mesh so it can be dragged
                         this._virtualOriginMesh.removeChild(this._virtualDragMesh);
@@ -137,14 +137,14 @@ import { Camera } from "Cameras/camera";
                             if (this._scene.activeCamera.inputs.attachedElement) {
                                 attachedElement = this._scene.activeCamera.inputs.attachedElement;
                                 this._scene.activeCamera.detachControl(this._scene.activeCamera.inputs.attachedElement);
-                            }else {
+                            } else {
                                 attachedElement = null;
                             }
                         }
                         BoundingBoxGizmo._RestorePivotPoint(pickedMesh);
                         this.onDragStartObservable.notifyObservers({});
                     }
-                }else if (pointerInfo.type == PointerEventTypes.POINTERUP) {
+                } else if (pointerInfo.type == PointerEventTypes.POINTERUP) {
                     if (this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId) {
                         this.dragging = false;
                         this._moving = false;
@@ -158,7 +158,7 @@ import { Camera } from "Cameras/camera";
                         }
                         this.onDragEndObservable.notifyObservers({});
                     }
-                }else if (pointerInfo.type == PointerEventTypes.POINTERMOVE) {
+                } else if (pointerInfo.type == PointerEventTypes.POINTERMOVE) {
                     if (this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId && this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.ray && pickedMesh) {
                         var zDragFactor = this.zDragFactor;
                         if (this._scene.activeCamera && this._scene.activeCamera.cameraRigMode == Camera.RIG_MODE_NONE) {
@@ -180,7 +180,7 @@ import { Camera } from "Cameras/camera";
 
                         // Update the controller position
                         this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
-                        this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
+                        this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.add(pointerInfo.pickInfo.ray.direction));
                         this._virtualOriginMesh.removeChild(this._virtualDragMesh);
 
                         // Move the virtualObjectsPosition into the picked mesh's space if needed

+ 17 - 1
src/Cameras/VR/vrExperienceHelper.ts

@@ -966,6 +966,14 @@ import { Animation } from "Animations/animation";
                 this._scene.registerBeforeRender(this.beforeRender);
             }
 
+            if (this._displayLaserPointer) {
+                [this._leftController, this._rightController].forEach((controller) => {
+                    if (controller) {
+                        controller._activatePointer();
+                    }
+                });
+            }
+
             this._hasEnteredVR = true;
         }
 
@@ -1049,6 +1057,12 @@ import { Animation } from "Animations/animation";
                 // resize to update width and height when exiting vr exits fullscreen
                 this._scene.getEngine().resize();
 
+                [this._leftController, this._rightController].forEach((controller) => {
+                    if (controller) {
+                        controller._deactivatePointer();
+                    }
+                });
+
                 this._hasEnteredVR = false;
             }
         }
@@ -1296,7 +1310,9 @@ import { Animation } from "Animations/animation";
             if (controllerMesh) {
 
                 controller._interactionsEnabled = true;
-                controller._activatePointer();
+                if (this.isInVRMode && this._displayLaserPointer) {
+                    controller._activatePointer();
+                }
                 if (this.webVROptions.laserToggle) {
                     controller.webVRController.onMainButtonStateChangedObservable.add((stateObject) => {
                         // Enabling / disabling laserPointer

+ 3 - 10
src/Debug/axesViewer.ts

@@ -12,7 +12,6 @@ import { AxisDragGizmo } from "Gizmos/axisDragGizmo";
         private _xAxis: TransformNode;
         private _yAxis: TransformNode;
         private _zAxis: TransformNode;
-        private _tmpVector = new Vector3();
         private _scaleLinesFactor = 4;
         private _instanced = false;
 
@@ -75,13 +74,10 @@ import { AxisDragGizmo } from "Gizmos/axisDragGizmo";
             }
 
             this._xAxis = xAxis;
-            this._xAxis.rotationQuaternion = new Quaternion();
             this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
             this._yAxis = yAxis;
-            this._yAxis.rotationQuaternion = new Quaternion();
             this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
             this._zAxis = zAxis;
-            this._zAxis.rotationQuaternion = new Quaternion();
             this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
 
             if (renderingGroupId != null) {
@@ -103,18 +99,15 @@ import { AxisDragGizmo } from "Gizmos/axisDragGizmo";
          */
         public update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void {
             this._xAxis.position.copyFrom(position);
-            xaxis.scaleToRef(-1, this._tmpVector);
-            this._xAxis.setDirection(this._tmpVector);
+            this._xAxis.setDirection(xaxis);
             this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
 
             this._yAxis.position.copyFrom(position);
-            yaxis.scaleToRef(-1, this._tmpVector);
-            this._yAxis.setDirection(this._tmpVector);
+            this._yAxis.setDirection(yaxis);
             this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
 
             this._zAxis.position.copyFrom(position);
-            zaxis.scaleToRef(-1, this._tmpVector);
-            this._zAxis.setDirection(this._tmpVector);
+            this._zAxis.setDirection(zaxis);
             this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
         }
 

+ 20 - 14
src/Engines/engine.ts

@@ -2027,27 +2027,33 @@ declare type RenderTargetTexture = import("Materials/Textures/renderTargetTextur
          * @param clearColor defines the clear color
          */
         public scissorClear(x: number, y: number, width: number, height: number, clearColor: Color4): void {
-            let gl = this._gl;
+            this.enableScissor(x, y, width, height);
+            this.clear(clearColor, true, true, true);
+            this.disableScissor();
+        }
 
-            // Save state
-            var curScissor = gl.getParameter(gl.SCISSOR_TEST);
-            var curScissorBox = gl.getParameter(gl.SCISSOR_BOX);
+        /**
+         * Enable scissor test on a specific rectangle (ie. render will only be executed on a specific portion of the screen)
+         * @param x defines the x-coordinate of the top left corner of the clear rectangle
+         * @param y defines the y-coordinate of the corner of the clear rectangle
+         * @param width defines the width of the clear rectangle
+         * @param height defines the height of the clear rectangle
+         */
+        public enableScissor(x: number, y: number, width: number, height: number): void {
+            let gl = this._gl;
 
             // Change state
             gl.enable(gl.SCISSOR_TEST);
             gl.scissor(x, y, width, height);
+        }
 
-            // Clear
-            this.clear(clearColor, true, true, true);
-
-            // Restore state
-            gl.scissor(curScissorBox[0], curScissorBox[1], curScissorBox[2], curScissorBox[3]);
+        /**
+         * Disable previously set scissor test rectangle
+         */
+        public disableScissor() {
+            let gl = this._gl;
 
-            if (curScissor === true) {
-                gl.enable(gl.SCISSOR_TEST);
-            } else {
-                gl.disable(gl.SCISSOR_TEST);
-            }
+            gl.disable(gl.SCISSOR_TEST);
         }
 
         private _viewportCached = new Vector4(0, 0, 0, 0);

+ 1 - 1
src/Gizmos/axisDragGizmo.ts

@@ -84,7 +84,7 @@ import { Scene } from "scene";
             // Build mesh on root node
             var arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, coloredMaterial);
 
-            arrow.lookAt(this._rootMesh.position.subtract(dragAxis));
+            arrow.lookAt(this._rootMesh.position.add(dragAxis));
             arrow.scaling.scaleInPlace(1 / 3);
             arrow.parent = this._rootMesh;
 

+ 9 - 9
src/Gizmos/axisScaleGizmo.ts

@@ -30,7 +30,7 @@ import { UtilityLayerRenderer } from "Rendering/utilityLayerRenderer";
          * Event that fires each time the gizmo snaps to a new location.
          * * snapDistance is the the change in distance
          */
-        public onSnapObservable = new Observable<{snapDistance: number}>();
+        public onSnapObservable = new Observable<{ snapDistance: number }>();
         /**
          * If the scaling operation should be done on all axis (default: false)
          */
@@ -55,8 +55,8 @@ import { UtilityLayerRenderer } from "Rendering/utilityLayerRenderer";
 
             // Build mesh on root node
             var arrow = new AbstractMesh("", gizmoLayer.utilityLayerScene);
-            var arrowMesh = MeshBuilder.CreateBox("yPosMesh", {size: 0.4}, gizmoLayer.utilityLayerScene);
-            var arrowTail = MeshBuilder.CreateLines("yPosMesh", {points: [new Vector3(0, 0, 0), new Vector3(0, 1.1, 0)]}, gizmoLayer.utilityLayerScene);
+            var arrowMesh = MeshBuilder.CreateBox("yPosMesh", { size: 0.4 }, gizmoLayer.utilityLayerScene);
+            var arrowTail = MeshBuilder.CreateLines("yPosMesh", { points: [new Vector3(0, 0, 0), new Vector3(0, 1.1, 0)] }, gizmoLayer.utilityLayerScene);
             arrowTail.color = this._coloredMaterial.emissiveColor;
             arrow.addChild(arrowMesh);
             arrow.addChild(arrowTail);
@@ -69,18 +69,18 @@ import { UtilityLayerRenderer } from "Rendering/utilityLayerRenderer";
             arrowTail.scaling.scaleInPlace(0.26);
             arrowTail.rotation.x = Math.PI / 2;
             arrowTail.material = this._coloredMaterial;
-            arrow.lookAt(this._rootMesh.position.subtract(dragAxis));
+            arrow.lookAt(this._rootMesh.position.add(dragAxis));
             this._rootMesh.addChild(arrow);
             arrow.scaling.scaleInPlace(1 / 3);
 
             // Add drag behavior to handle events when the gizmo is dragged
-            this.dragBehavior = new PointerDragBehavior({dragAxis: dragAxis});
+            this.dragBehavior = new PointerDragBehavior({ dragAxis: dragAxis });
             this.dragBehavior.moveAttached = false;
             this._rootMesh.addBehavior(this.dragBehavior);
 
             var currentSnapDragDistance = 0;
             var tmpVector = new Vector3();
-            var tmpSnapEvent = {snapDistance: 0};
+            var tmpSnapEvent = { snapDistance: 0 };
             this.dragBehavior.onDragObservable.add((event) => {
                 if (this.attachedMesh) {
                     // Snapping logic
@@ -91,19 +91,19 @@ import { UtilityLayerRenderer } from "Rendering/utilityLayerRenderer";
                         if (tmpVector.y < 0) {
                             tmpVector.scaleInPlace(-1);
                         }
-                    }else {
+                    } else {
                         tmpVector.copyFrom(dragAxis);
                     }
                     if (this.snapDistance == 0) {
                         tmpVector.scaleToRef(event.dragDistance, tmpVector);
-                    }else {
+                    } else {
                         currentSnapDragDistance += event.dragDistance;
                         if (Math.abs(currentSnapDragDistance) > this.snapDistance) {
                             dragSteps = Math.floor(currentSnapDragDistance / this.snapDistance);
                             currentSnapDragDistance = currentSnapDragDistance % this.snapDistance;
                             tmpVector.scaleToRef(this.snapDistance * dragSteps, tmpVector);
                             snapped = true;
-                        }else {
+                        } else {
                             tmpVector.scaleInPlace(0);
                         }
                     }

+ 5 - 5
src/Gizmos/boundingBoxGizmo.ts

@@ -270,7 +270,7 @@ import { StandardMaterial } from "Materials/standardMaterial";
                                     this._boundingDimensions.multiplyToRef(this.scalePivot, this._tmpVector);
                                     Vector3.TransformCoordinatesToRef(this._tmpVector, this._tmpRotationMatrix, this._tmpVector);
                                     this._anchorMesh.position.addInPlace(this._tmpVector);
-                                }else {
+                                } else {
                                     // Scale from the position of the opposite corner
                                     box.absolutePosition.subtractToRef(this._anchorMesh.position, this._tmpVector);
                                     this._anchorMesh.position.subtractInPlace(this._tmpVector);
@@ -326,7 +326,7 @@ import { StandardMaterial } from "Materials/standardMaterial";
                 // Only update the bouding box if scaling has changed
                 if (this.attachedMesh && !this._existingMeshScale.equals(this.attachedMesh.scaling)) {
                     this.updateBoundingBox();
-                }else if (this.fixedDragMeshScreenSize) {
+                } else if (this.fixedDragMeshScreenSize) {
                     this._updateRotationSpheres();
                     this._updateScaleBoxes();
                 }
@@ -410,17 +410,17 @@ import { StandardMaterial } from "Materials/standardMaterial";
                         if (i == 0) {
                             rotateSpheres[index].position.set(this._boundingDimensions.x / 2, this._boundingDimensions.y * j, this._boundingDimensions.z * k);
                             rotateSpheres[index].position.addInPlace(new 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));
+                            rotateSpheres[index].lookAt(Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), Vector3.Right()).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 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));
+                            rotateSpheres[index].lookAt(Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), Vector3.Up()).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 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));
+                            rotateSpheres[index].lookAt(Vector3.Cross(rotateSpheres[index].position.normalizeToNew(), Vector3.Forward()).normalizeToNew().add(rotateSpheres[index].position));
                         }
                         if (this.fixedDragMeshScreenSize && this.gizmoLayer.utilityLayerScene.activeCamera) {
                             rotateSpheres[index].absolutePosition.subtractToRef(this.gizmoLayer.utilityLayerScene.activeCamera.position, this._tmpVector);

+ 10 - 10
src/Gizmos/planeRotationGizmo.ts

@@ -29,7 +29,7 @@ import { StandardMaterial } from "Materials/standardMaterial";
          * Event that fires each time the gizmo snaps to a new location.
          * * snapDistance is the the change in distance
          */
-        public onSnapObservable = new Observable<{snapDistance: number}>();
+        public onSnapObservable = new Observable<{ snapDistance: number }>();
 
         /**
          * Creates a PlaneRotationGizmo
@@ -68,14 +68,14 @@ import { StandardMaterial } from "Materials/standardMaterial";
             rotationMesh.material = coloredMaterial;
             rotationMesh.rotation.x = Math.PI / 2;
             parentMesh.addChild(rotationMesh);
-            parentMesh.lookAt(this._rootMesh.position.subtract(planeNormal));
+            parentMesh.lookAt(this._rootMesh.position.add(planeNormal));
 
             this._rootMesh.addChild(parentMesh);
             parentMesh.scaling.scaleInPlace(1 / 3);
             // Add drag behavior to handle events when the gizmo is dragged
-            this.dragBehavior = new PointerDragBehavior({dragPlaneNormal: planeNormal});
+            this.dragBehavior = new PointerDragBehavior({ dragPlaneNormal: planeNormal });
             this.dragBehavior.moveAttached = false;
-            this.dragBehavior.maxDragAngle =  Math.PI * 9 / 20;
+            this.dragBehavior.maxDragAngle = Math.PI * 9 / 20;
             this.dragBehavior._useAlternatePickedPointAboveMaxDragAngle = true;
             this._rootMesh.addBehavior(this.dragBehavior);
 
@@ -91,7 +91,7 @@ import { StandardMaterial } from "Materials/standardMaterial";
             var planeNormalTowardsCamera = new Vector3();
             var localPlaneNormalTowardsCamera = new Vector3();
 
-            var tmpSnapEvent = {snapDistance: 0};
+            var tmpSnapEvent = { snapDistance: 0 };
             var currentSnapDragDistance = 0;
             var tmpMatrix = new Matrix();
             var tmpVector = new Vector3();
@@ -133,7 +133,7 @@ import { StandardMaterial } from "Materials/standardMaterial";
                             currentSnapDragDistance = currentSnapDragDistance % this.snapDistance;
                             angle = this.snapDistance * dragSteps;
                             snapped = true;
-                        }else {
+                        } else {
                             angle = 0;
                         }
                     }
@@ -156,13 +156,13 @@ import { StandardMaterial } from "Materials/standardMaterial";
                         Quaternion.RotationYawPitchRollToRef(tmpVector.y, -tmpVector.x, -tmpVector.z, amountToRotate);
                     }
 
-                     if (this.updateGizmoRotationToMatchAttachedMesh) {
+                    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
+                    } else {
+                        // Rotate selected mesh quaternion over rotated axis
                         amountToRotate.multiplyToRef(this.attachedMesh.rotationQuaternion, this.attachedMesh.rotationQuaternion);
-                     }
+                    }
 
                     lastDragPosition.copyFrom(event.dragPlanePoint);
                     if (snapped) {

+ 1 - 1
src/Meshes/meshBuilder.ts

@@ -975,7 +975,7 @@ Mesh.CreateDecal = (name: string, sourceMesh: AbstractMesh, position: Vector3, n
 
             if (options.sourcePlane) {
                 plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
-                plane.setDirection(options.sourcePlane.normal);
+                plane.setDirection(options.sourcePlane.normal.scale(-1));
             }
 
             return plane;

+ 2 - 2
src/Meshes/transformNode.ts

@@ -536,9 +536,9 @@ import { Bone } from "Bones/bone";
          * @returns this TransformNode
          */
         public setDirection(localAxis: Vector3, yawCor: number = 0, pitchCor: number = 0, rollCor: number = 0): TransformNode {
-            var yaw = -Math.atan2(localAxis.z, localAxis.x) - Math.PI / 2;
+            var yaw = -Math.atan2(localAxis.z, localAxis.x) + Math.PI / 2;
             var len = Math.sqrt(localAxis.x * localAxis.x + localAxis.z * localAxis.z);
-            var pitch = Math.atan2(localAxis.y, len);
+            var pitch = -Math.atan2(localAxis.y, len);
             if (this.rotationQuaternion) {
                 Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
             }

+ 38 - 28
src/Physics/Plugins/ammoJSPlugin.ts

@@ -387,39 +387,46 @@ import { AbstractMesh } from "Meshes/abstractMesh";
 
             if (!ignoreChildren) {
                 var meshChildren = impostor.object.getChildMeshes ? impostor.object.getChildMeshes(true) : [];
-                if (meshChildren.length > 0) {
-                    returnValue = new Ammo.btCompoundShape();
-
-                    // Add shape of all children to the compound shape
-                    meshChildren.forEach((childMesh) => {
-                        var childImpostor = childMesh.getPhysicsImpostor();
-                        if (childImpostor) {
-                            var shape = this._createShape(childImpostor);
-
-                            // Position needs to be scaled based on parent's scaling
-                            var parentMat = childMesh.parent!.getWorldMatrix().clone();
-                            var s = new Vector3();
-                            parentMat.decompose(s);
-                            this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
-
-                            this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion!.x, childMesh.rotationQuaternion!.y, childMesh.rotationQuaternion!.z, childMesh.rotationQuaternion!.w);
-                            this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
-                            returnValue.addChildShape(this._tmpAmmoTransform, shape);
-                            childImpostor.dispose();
-                        }
-                    });
-
-                    // Add parents shape as a child if present
-                    var shape = this._createShape(impostor, true);
-                    if (shape) {
-                        this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
-                        this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
+                returnValue = new Ammo.btCompoundShape();
+
+                // Add shape of all children to the compound shape
+                var childrenAdded = 0;
+                meshChildren.forEach((childMesh) => {
+                    var childImpostor = childMesh.getPhysicsImpostor();
+                    if (childImpostor) {
+                        var shape = this._createShape(childImpostor);
+
+                        // Position needs to be scaled based on parent's scaling
+                        var parentMat = childMesh.parent!.getWorldMatrix().clone();
+                        var s = new Vector3();
+                        parentMat.decompose(s);
+                        this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
+
+                        this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion!.x, childMesh.rotationQuaternion!.y, childMesh.rotationQuaternion!.z, childMesh.rotationQuaternion!.w);
                         this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
-
                         returnValue.addChildShape(this._tmpAmmoTransform, shape);
+                        childImpostor.dispose();
+                        childrenAdded++;
                     }
+                });
+
+                if (childrenAdded > 0) {
+                    // Add parents shape as a child if present
+                    if (impostor.type != PhysicsImpostor.NoImpostor) {
+                        var shape = this._createShape(impostor, true);
+                        if (shape) {
+                            this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
+                            this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
+                            this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
 
+                            returnValue.addChildShape(this._tmpAmmoTransform, shape);
+                        }
+                    }
                     return returnValue;
+                }else {
+                    // If no children with impostors create the actual shape below instead
+                    Ammo.destroy(returnValue);
+                    returnValue = null;
                 }
             }
 
@@ -450,6 +457,9 @@ import { AbstractMesh } from "Meshes/abstractMesh";
                     // Fill with sphere but collision is disabled on the rigid body in generatePhysicsBody, using an empty shape caused unexpected movement with joints
                     returnValue = new Ammo.btSphereShape(extendSize.x / 2);
                     break;
+                default:
+                    Tools.Warn("The impostor type is not currently supported by the ammo plugin.");
+                    break;
             }
 
             return returnValue;

+ 1 - 1
src/Physics/physicsImpostor.ts

@@ -647,7 +647,7 @@ import { PhysicsJoint, PhysicsJointData } from "./physicsJoint";
                 this._tmpQuat.copyFrom(this.object.rotationQuaternion || new Quaternion());
             }
             if (!this._options.disableBidirectionalTransformation) {
-                this.object.rotationQuaternion && this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(this, /*bInfo.boundingBox.centerWorld*/ this.object.getAbsolutePivotPoint(), this._tmpQuat);
+                this.object.rotationQuaternion && this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(this, /*bInfo.boundingBox.centerWorld*/ this.object.getAbsolutePosition(), this._tmpQuat);
             }
 
             this._onBeforePhysicsStepCallbacks.forEach((func) => {