Selaa lähdekoodia

Merge remote-tracking branch 'upstream/master' into sceneOptimization

# Conflicts:
#	dist/preview release/what's new.md
#	src/Materials/babylon.material.ts
Julien Barrois 6 vuotta sitten
vanhempi
commit
abc14105ec
30 muutettua tiedostoa jossa 10035 lisäystä ja 9290 poistoa
  1. 4227 4190
      Playground/babylon.d.txt
  2. 4225 4190
      dist/preview release/babylon.d.ts
  3. 1 1
      dist/preview release/babylon.js
  4. 125 100
      dist/preview release/babylon.max.js
  5. 125 100
      dist/preview release/babylon.no-module.max.js
  6. 1 1
      dist/preview release/babylon.worker.js
  7. 125 100
      dist/preview release/es6.js
  8. 2 0
      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. 4 0
      dist/preview release/gui/babylon.gui.module.d.ts
  13. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  14. 459 202
      dist/preview release/viewer/babylon.viewer.d.ts
  15. 1 1
      dist/preview release/viewer/babylon.viewer.js
  16. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  17. 493 204
      dist/preview release/viewer/babylon.viewer.module.d.ts
  18. 6 2
      dist/preview release/what's new.md
  19. 12 4
      src/Engine/babylon.engine.ts
  20. 7 6
      src/Materials/babylon.material.ts
  21. 2 2
      src/Materials/babylon.multiMaterial.ts
  22. 1 1
      src/Materials/babylon.pushMaterial.ts
  23. 1 0
      src/Materials/babylon.shaderMaterial.ts
  24. 5 5
      src/Mesh/babylon.mesh.ts
  25. 19 20
      src/Particles/babylon.gpuParticleSystem.ts
  26. 149 149
      src/Particles/babylon.particleSystem.ts
  27. 20 0
      src/Tools/babylon.tools.ts
  28. 16 3
      src/babylon.scene.ts
  29. 1 1
      src/babylon.sceneComponent.ts
  30. 2 2
      tests/validation/validation.js

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 4227 - 4190
Playground/babylon.d.txt


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 4225 - 4190
dist/preview release/babylon.d.ts


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/babylon.js


+ 125 - 100
dist/preview release/babylon.max.js

@@ -12272,6 +12272,10 @@ var BABYLON;
              */
             this.onBeginFrameObservable = new BABYLON.Observable();
             /**
+             * If set, will be used to request the next animation frame for the render loop
+             */
+            this.customAnimationFrameRequester = null;
+            /**
              * Observable raised when the engine ends the current frame
              */
             this.onEndFrameObservable = new BABYLON.Observable();
@@ -13434,11 +13438,16 @@ var BABYLON;
             }
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
-                var requester = null;
-                if (this._vrDisplay && this._vrDisplay.isPresenting) {
-                    requester = this._vrDisplay;
+                if (this.customAnimationFrameRequester) {
+                    this.customAnimationFrameRequester.requestID = BABYLON.Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
+                    this._frameHandler = this.customAnimationFrameRequester.requestID;
+                }
+                else if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+                }
+                else {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction);
                 }
-                this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, requester);
             }
             else {
                 this._renderingQueueLaunched = false;
@@ -19208,7 +19217,7 @@ var BABYLON;
             this.minimum.copyFrom(min);
             this.maximum.copyFrom(max);
             var distance = BABYLON.Vector3.Distance(min, max);
-            BABYLON.Vector3.LerpToRef(min, max, 0.5, this.center);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
             this.radius = distance * 0.5;
             this._update(worldMatrix || _identityMatrix);
         };
@@ -19219,8 +19228,8 @@ var BABYLON;
          */
         BoundingSphere.prototype.scale = function (factor) {
             var newRadius = this.radius * factor;
-            var tmpVectors = BABYLON.Tmp.Vector3;
-            var tempRadiusVector = tmpVectors[0].copyFromFloats(newRadius, newRadius, newRadius);
+            var tmpVectors = BoundingSphere.TmpVector3;
+            var tempRadiusVector = tmpVectors[0].setAll(newRadius);
             var min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
             var max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
             this.reConstruct(min, max);
@@ -19230,7 +19239,7 @@ var BABYLON;
         /** @hidden */
         BoundingSphere.prototype._update = function (world) {
             BABYLON.Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            var tempVector = BABYLON.Tmp.Vector3[0];
+            var tempVector = BoundingSphere.TmpVector3[0];
             BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, tempVector);
             this.radiusWorld = Math.max(Math.abs(tempVector.x), Math.abs(tempVector.y), Math.abs(tempVector.z)) * this.radius;
         };
@@ -19253,11 +19262,8 @@ var BABYLON;
          * @returns true if the point is inside the bounding sphere
          */
         BoundingSphere.prototype.intersectsPoint = function (point) {
-            var x = this.centerWorld.x - point.x;
-            var y = this.centerWorld.y - point.y;
-            var z = this.centerWorld.z - point.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (this.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(this.centerWorld, point);
+            if (this.radiusWorld * this.radiusWorld < squareDistance) {
                 return false;
             }
             return true;
@@ -19270,15 +19276,14 @@ var BABYLON;
          * @returns true if the speres intersect
          */
         BoundingSphere.Intersects = function (sphere0, sphere1) {
-            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
-            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
-            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (sphere0.radiusWorld + sphere1.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(sphere0.centerWorld, sphere1.centerWorld);
+            var radiusSum = sphere0.radiusWorld + sphere1.radiusWorld;
+            if (radiusSum * radiusSum < squareDistance) {
                 return false;
             }
             return true;
         };
+        BoundingSphere.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingSphere;
     }());
     BABYLON.BoundingSphere = BoundingSphere;
@@ -19366,8 +19371,8 @@ var BABYLON;
             vectors[6].copyFromFloats(minX, maxY, maxZ);
             vectors[7].copyFromFloats(maxX, minY, maxZ);
             // OBB
-            this.maximum.addToRef(min, this.center).scaleInPlace(0.5);
-            this.maximum.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
+            max.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
             this._update(worldMatrix || this._worldMatrix || BABYLON.Matrix.Identity());
         };
         /**
@@ -19376,7 +19381,7 @@ var BABYLON;
          * @returns the current bounding box
          */
         BoundingBox.prototype.scale = function (factor) {
-            var tmpVectors = BABYLON.Tmp.Vector3;
+            var tmpVectors = BoundingBox.TmpVector3;
             var diff = this.maximum.subtractToRef(this.minimum, tmpVectors[0]);
             var len = diff.length();
             diff.normalizeFromLength(len);
@@ -19557,6 +19562,7 @@ var BABYLON;
             }
             return true;
         };
+        BoundingBox.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingBox;
     }());
     BABYLON.BoundingBox = BoundingBox;
@@ -19866,6 +19872,8 @@ var BABYLON;
             _this._pivotMatrix = BABYLON.Matrix.Identity();
             _this._postMultiplyPivotMatrix = false;
             _this._isWorldMatrixFrozen = false;
+            /** @hidden */
+            _this._indexInSceneTransformNodesArray = -1;
             /**
             * An event triggered after the world matrix is updated
             */
@@ -19937,8 +19945,8 @@ var BABYLON;
             set: function (quaternion) {
                 this._rotationQuaternion = quaternion;
                 //reset the rotation vector.
-                if (quaternion && this.rotation.length()) {
-                    this.rotation.copyFromFloats(0.0, 0.0, 0.0);
+                if (quaternion) {
+                    this.rotation.setAll(0.0);
                 }
             },
             enumerable: true,
@@ -20070,7 +20078,7 @@ var BABYLON;
         */
         TransformNode.prototype.setPivotMatrix = function (matrix, postMultiplyPivotMatrix) {
             if (postMultiplyPivotMatrix === void 0) { postMultiplyPivotMatrix = true; }
-            this._pivotMatrix = matrix.clone();
+            this._pivotMatrix.copyFrom(matrix);
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
             if (this._postMultiplyPivotMatrix) {
@@ -20154,10 +20162,9 @@ var BABYLON;
                 absolutePositionZ = absolutePosition.z;
             }
             if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+                var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
+                BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(absolutePositionX, absolutePositionY, absolutePositionZ, invertParentWorldMatrix, this.position);
             }
             else {
                 this.position.x = absolutePositionX;
@@ -20182,8 +20189,8 @@ var BABYLON;
          */
         TransformNode.prototype.getPositionExpressedInLocalSpace = function () {
             this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
+            var invLocalWorldMatrix = BABYLON.Tmp.Matrix[0];
+            this._localWorld.invertToRef(invLocalWorldMatrix);
             return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         };
         /**
@@ -20320,52 +20327,33 @@ var BABYLON;
             if (!node && !this.parent) {
                 return this;
             }
+            var quatRotation = BABYLON.Tmp.Quaternion[0];
+            var position = BABYLON.Tmp.Vector3[0];
+            var scale = BABYLON.Tmp.Vector3[1];
             if (!node) {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 if (this.parent && this.parent.computeWorldMatrix) {
                     this.parent.computeWorldMatrix(true);
                 }
                 this.computeWorldMatrix(true);
-                this.getWorldMatrix().decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                this.getWorldMatrix().decompose(scale, quatRotation, position);
             }
             else {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 var diffMatrix = BABYLON.Tmp.Matrix[0];
                 var invParentMatrix = BABYLON.Tmp.Matrix[1];
                 this.computeWorldMatrix(true);
                 node.computeWorldMatrix(true);
                 node.getWorldMatrix().invertToRef(invParentMatrix);
                 this.getWorldMatrix().multiplyToRef(invParentMatrix, diffMatrix);
-                diffMatrix.decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
+                diffMatrix.decompose(scale, quatRotation, position);
+            }
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(quatRotation);
+            }
+            else {
+                quatRotation.toEulerAnglesToRef(this.rotation);
             }
+            this.scaling.copyFrom(scale);
+            this.position.copyFrom(position);
             this.parent = node;
             return this;
         };
@@ -20429,8 +20417,8 @@ var BABYLON;
         TransformNode.prototype.rotate = function (axis, amount, space) {
             axis.normalize();
             if (!this.rotationQuaternion) {
-                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = BABYLON.Vector3.Zero();
+                this.rotationQuaternion = this.rotation.toQuaternion();
+                this.rotation.setAll(0);
             }
             var rotationQuaternion;
             if (!space || space === BABYLON.Space.LOCAL) {
@@ -20439,8 +20427,8 @@ var BABYLON;
             }
             else {
                 if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
+                    var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                    this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
                     axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
                 }
                 rotationQuaternion = BABYLON.Quaternion.RotationAxisToRef(axis, amount, TransformNode._rotationAxisCache);
@@ -20462,17 +20450,25 @@ var BABYLON;
             axis.normalize();
             if (!this.rotationQuaternion) {
                 this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation.copyFromFloats(0, 0, 0);
-            }
-            point.subtractToRef(this.position, BABYLON.Tmp.Vector3[0]);
-            BABYLON.Matrix.TranslationToRef(BABYLON.Tmp.Vector3[0].x, BABYLON.Tmp.Vector3[0].y, BABYLON.Tmp.Vector3[0].z, BABYLON.Tmp.Matrix[0]);
-            BABYLON.Tmp.Matrix[0].invertToRef(BABYLON.Tmp.Matrix[2]);
-            BABYLON.Matrix.RotationAxisToRef(axis, amount, BABYLON.Tmp.Matrix[1]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[1], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[0], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].decompose(BABYLON.Tmp.Vector3[0], BABYLON.Tmp.Quaternion[0], BABYLON.Tmp.Vector3[1]);
-            this.position.addInPlace(BABYLON.Tmp.Vector3[1]);
-            BABYLON.Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+                this.rotation.setAll(0);
+            }
+            var tmpVector = BABYLON.Tmp.Vector3[0];
+            var finalScale = BABYLON.Tmp.Vector3[1];
+            var finalTranslation = BABYLON.Tmp.Vector3[2];
+            var finalRotation = BABYLON.Tmp.Quaternion[0];
+            var translationMatrix = BABYLON.Tmp.Matrix[0]; // T
+            var translationMatrixInv = BABYLON.Tmp.Matrix[1]; // T'
+            var rotationMatrix = BABYLON.Tmp.Matrix[2]; // R
+            var finalMatrix = BABYLON.Tmp.Matrix[3]; // T' x R x T
+            point.subtractToRef(this.position, tmpVector);
+            BABYLON.Matrix.TranslationToRef(tmpVector.x, tmpVector.y, tmpVector.z, translationMatrix); // T
+            BABYLON.Matrix.TranslationToRef(-tmpVector.x, -tmpVector.y, -tmpVector.z, translationMatrixInv); // T'
+            BABYLON.Matrix.RotationAxisToRef(axis, amount, rotationMatrix); // R
+            translationMatrixInv.multiplyToRef(rotationMatrix, finalMatrix); // T' x R
+            finalMatrix.multiplyToRef(translationMatrix, finalMatrix); // T' x R x T
+            finalMatrix.decompose(finalScale, finalRotation, finalTranslation);
+            this.position.addInPlace(finalTranslation);
+            finalRotation.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
             return this;
         };
         /**
@@ -25204,6 +25200,9 @@ var BABYLON;
             this.geometries = new Array();
             /**
             * All of the tranform nodes added to this scene
+            * In the context a the Scene, it is not supposed to be modified manually.
+            * Any addition or removal should be done using the addTransformNode and removeTransformNode Scene methods.
+            * Note also that the order of the TransformNode wihin the array is not significant and might change.
             * @see http://doc.babylonjs.com/how_to/transformnode
             */
             this.transformNodes = new Array();
@@ -25404,6 +25403,11 @@ var BABYLON;
              * in order to block unwanted artifacts like system double clicks
              */
             _this.preventDefaultOnPointerDown = true;
+            /**
+             * This is used to call preventDefault() on pointer up
+             * in order to block unwanted artifacts like system double clicks
+             */
+            _this.preventDefaultOnPointerUp = true;
             // Metadata
             /**
              * Gets or sets user defined metadata
@@ -27003,8 +27007,10 @@ var BABYLON;
                         }
                     }
                 }
-                clickInfo.ignore = true;
-                cb(clickInfo, _this._currentPickResult);
+                else {
+                    clickInfo.ignore = true;
+                    cb(clickInfo, _this._currentPickResult);
+                }
             };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
@@ -27060,6 +27066,10 @@ var BABYLON;
                 _this._pickedUpMesh = null;
                 _this._meshPickProceed = false;
                 _this._updatePointerPosition(evt);
+                if (_this.preventDefaultOnPointerUp && canvas) {
+                    evt.preventDefault();
+                    canvas.focus();
+                }
                 _this._initClickEvent(_this.onPrePointerObservable, _this.onPointerObservable, evt, function (clickInfo, pickResult) {
                     // PreObservable support
                     if (_this.onPrePointerObservable.hasObservers()) {
@@ -27908,6 +27918,7 @@ var BABYLON;
          * @param newTransformNode defines the transform node to add
          */
         Scene.prototype.addTransformNode = function (newTransformNode) {
+            newTransformNode._indexInSceneTransformNodesArray = this.transformNodes.length;
             this.transformNodes.push(newTransformNode);
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
         };
@@ -27917,10 +27928,15 @@ var BABYLON;
          * @returns the index where the transform node was in the transform node list
          */
         Scene.prototype.removeTransformNode = function (toRemove) {
-            var index = this.transformNodes.indexOf(toRemove);
+            var index = toRemove._indexInSceneTransformNodesArray;
             if (index !== -1) {
-                // Remove from the scene if found
-                this.transformNodes.splice(index, 1);
+                if (index !== this.transformNodes.length - 1) {
+                    var lastNode = this.transformNodes[this.transformNodes.length - 1];
+                    this.transformNodes[index] = lastNode;
+                    lastNode._indexInSceneTransformNodesArray = index;
+                }
+                toRemove._indexInSceneTransformNodesArray = -1;
+                this.transformNodes.pop();
             }
             this.onTransformNodeRemovedObservable.notifyObservers(toRemove);
             return index;
@@ -28899,7 +28915,7 @@ var BABYLON;
                     continue;
                 }
                 mesh._preActivate();
-                if (mesh.isVisible && mesh.visibility > 0 && (mesh.alwaysSelectAsActiveMesh || ((mesh.layerMask & this.activeCamera.layerMask) !== 0 && mesh.isInFrustum(this._frustumPlanes)))) {
+                if (mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && (mesh.alwaysSelectAsActiveMesh || mesh.isInFrustum(this._frustumPlanes))) {
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
@@ -33011,12 +33027,12 @@ var BABYLON;
             this.computeWorldMatrix();
             var mat = this.material || scene.defaultMaterial;
             if (mat) {
-                if (mat.storeEffectOnSubMeshes) {
+                if (mat._storeEffectOnSubMeshes) {
                     for (var _i = 0, _a = this.subMeshes; _i < _a.length; _i++) {
                         var subMesh = _a[_i];
                         var effectiveMaterial = subMesh.getMaterial();
                         if (effectiveMaterial) {
-                            if (effectiveMaterial.storeEffectOnSubMeshes) {
+                            if (effectiveMaterial._storeEffectOnSubMeshes) {
                                 if (!effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                                     return false;
                                 }
@@ -33693,7 +33709,7 @@ var BABYLON;
                 return this;
             }
             this._effectiveMaterial = material;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                     return this;
                 }
@@ -33710,7 +33726,7 @@ var BABYLON;
                 step.action(this, subMesh, batch);
             }
             var effect;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 effect = subMesh.effect;
             }
             else {
@@ -33736,7 +33752,7 @@ var BABYLON;
                 this._bind(subMesh, effect, fillMode);
             }
             var world = this.getWorldMatrix();
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             }
             else {
@@ -36378,9 +36394,9 @@ var BABYLON;
              */
             this.doNotSerialize = false;
             /**
-             * Specifies if the effect should be stored on sub meshes
+             * @hidden
              */
-            this.storeEffectOnSubMeshes = false;
+            this._storeEffectOnSubMeshes = false;
             /**
             * An event triggered when the material is disposed
             */
@@ -37066,7 +37082,7 @@ var BABYLON;
                 if (localOptions.clipPlane) {
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                 }
-                if (_this.storeEffectOnSubMeshes) {
+                if (_this._storeEffectOnSubMeshes) {
                     if (_this.isReadyForSubMesh(mesh, subMesh)) {
                         if (onCompiled) {
                             onCompiled(_this);
@@ -37226,7 +37242,7 @@ var BABYLON;
                     mesh.material = null;
                     if (mesh.geometry) {
                         var geometry = (mesh.geometry);
-                        if (this.storeEffectOnSubMeshes) {
+                        if (this._storeEffectOnSubMeshes) {
                             for (var _i = 0, _a = mesh.subMeshes; _i < _a.length; _i++) {
                                 var subMesh = _a[_i];
                                 geometry._releaseVertexArrayObject(subMesh._materialEffect);
@@ -37244,7 +37260,7 @@ var BABYLON;
             this._uniformBuffer.dispose();
             // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
             if (forceDisposeEffect && this._effect) {
-                if (!this.storeEffectOnSubMeshes) {
+                if (!this._storeEffectOnSubMeshes) {
                     this._scene.getEngine()._releaseEffect(this._effect);
                 }
                 this._effect = null;
@@ -43224,7 +43240,7 @@ var BABYLON;
              * This is mostly used when shader parallel compilation is supported (true by default)
              */
             _this.allowShaderHotSwapping = true;
-            _this.storeEffectOnSubMeshes = true;
+            _this._storeEffectOnSubMeshes = true;
             return _this;
         }
         PushMaterial.prototype.getEffect = function () {
@@ -68345,13 +68361,22 @@ var BABYLON;
             var index = 0;
             var idx = 0;
             var tmpNormal = BABYLON.Tmp.Vector3[0];
-            var rotMatrix = BABYLON.Tmp.Matrix[0];
-            var invertedRotMatrix = BABYLON.Tmp.Matrix[1];
+            var quaternion = BABYLON.Tmp.Quaternion[0];
+            var invertedRotMatrix = BABYLON.Tmp.Matrix[0];
             for (var p = 0; p < this.particles.length; p++) {
                 var particle = this.particles[p];
                 var shape = particle._model._shape;
-                particle.getRotationMatrix(rotMatrix);
-                rotMatrix.invertToRef(invertedRotMatrix);
+                // computing the inverse of the rotation matrix from the quaternion
+                // is equivalent to computing the matrix of the inverse quaternion, i.e of the conjugate quaternion
+                if (particle.rotationQuaternion) {
+                    particle.rotationQuaternion.conjugateToRef(quaternion);
+                }
+                else {
+                    var rotation = particle.rotation;
+                    BABYLON.Quaternion.RotationYawPitchRollToRef(rotation.y, rotation.x, rotation.z, quaternion);
+                    quaternion.conjugateInPlace();
+                }
+                quaternion.toRotationMatrix(invertedRotMatrix);
                 for (var pt = 0; pt < shape.length; pt++) {
                     idx = index + pt * 3;
                     BABYLON.Vector3.TransformNormalFromFloatsToRef(this._normals32[idx], this._normals32[idx + 1], this._normals32[idx + 2], invertedRotMatrix, tmpNormal);
@@ -80200,7 +80225,7 @@ var BABYLON;
             var _this = _super.call(this, name, scene, true) || this;
             scene.multiMaterials.push(_this);
             _this.subMaterials = new Array();
-            _this.storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
+            _this._storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
             return _this;
         }
         Object.defineProperty(MultiMaterial.prototype, "subMaterials", {
@@ -80282,7 +80307,7 @@ var BABYLON;
             for (var index = 0; index < this.subMaterials.length; index++) {
                 var subMaterial = this.subMaterials[index];
                 if (subMaterial) {
-                    if (subMaterial.storeEffectOnSubMeshes) {
+                    if (subMaterial._storeEffectOnSubMeshes) {
                         if (!subMaterial.isReadyForSubMesh(mesh, subMesh, useInstances)) {
                             return false;
                         }

+ 125 - 100
dist/preview release/babylon.no-module.max.js

@@ -12239,6 +12239,10 @@ var BABYLON;
              */
             this.onBeginFrameObservable = new BABYLON.Observable();
             /**
+             * If set, will be used to request the next animation frame for the render loop
+             */
+            this.customAnimationFrameRequester = null;
+            /**
              * Observable raised when the engine ends the current frame
              */
             this.onEndFrameObservable = new BABYLON.Observable();
@@ -13401,11 +13405,16 @@ var BABYLON;
             }
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
-                var requester = null;
-                if (this._vrDisplay && this._vrDisplay.isPresenting) {
-                    requester = this._vrDisplay;
+                if (this.customAnimationFrameRequester) {
+                    this.customAnimationFrameRequester.requestID = BABYLON.Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
+                    this._frameHandler = this.customAnimationFrameRequester.requestID;
+                }
+                else if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+                }
+                else {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction);
                 }
-                this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, requester);
             }
             else {
                 this._renderingQueueLaunched = false;
@@ -19175,7 +19184,7 @@ var BABYLON;
             this.minimum.copyFrom(min);
             this.maximum.copyFrom(max);
             var distance = BABYLON.Vector3.Distance(min, max);
-            BABYLON.Vector3.LerpToRef(min, max, 0.5, this.center);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
             this.radius = distance * 0.5;
             this._update(worldMatrix || _identityMatrix);
         };
@@ -19186,8 +19195,8 @@ var BABYLON;
          */
         BoundingSphere.prototype.scale = function (factor) {
             var newRadius = this.radius * factor;
-            var tmpVectors = BABYLON.Tmp.Vector3;
-            var tempRadiusVector = tmpVectors[0].copyFromFloats(newRadius, newRadius, newRadius);
+            var tmpVectors = BoundingSphere.TmpVector3;
+            var tempRadiusVector = tmpVectors[0].setAll(newRadius);
             var min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
             var max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
             this.reConstruct(min, max);
@@ -19197,7 +19206,7 @@ var BABYLON;
         /** @hidden */
         BoundingSphere.prototype._update = function (world) {
             BABYLON.Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            var tempVector = BABYLON.Tmp.Vector3[0];
+            var tempVector = BoundingSphere.TmpVector3[0];
             BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, tempVector);
             this.radiusWorld = Math.max(Math.abs(tempVector.x), Math.abs(tempVector.y), Math.abs(tempVector.z)) * this.radius;
         };
@@ -19220,11 +19229,8 @@ var BABYLON;
          * @returns true if the point is inside the bounding sphere
          */
         BoundingSphere.prototype.intersectsPoint = function (point) {
-            var x = this.centerWorld.x - point.x;
-            var y = this.centerWorld.y - point.y;
-            var z = this.centerWorld.z - point.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (this.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(this.centerWorld, point);
+            if (this.radiusWorld * this.radiusWorld < squareDistance) {
                 return false;
             }
             return true;
@@ -19237,15 +19243,14 @@ var BABYLON;
          * @returns true if the speres intersect
          */
         BoundingSphere.Intersects = function (sphere0, sphere1) {
-            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
-            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
-            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (sphere0.radiusWorld + sphere1.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(sphere0.centerWorld, sphere1.centerWorld);
+            var radiusSum = sphere0.radiusWorld + sphere1.radiusWorld;
+            if (radiusSum * radiusSum < squareDistance) {
                 return false;
             }
             return true;
         };
+        BoundingSphere.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingSphere;
     }());
     BABYLON.BoundingSphere = BoundingSphere;
@@ -19333,8 +19338,8 @@ var BABYLON;
             vectors[6].copyFromFloats(minX, maxY, maxZ);
             vectors[7].copyFromFloats(maxX, minY, maxZ);
             // OBB
-            this.maximum.addToRef(min, this.center).scaleInPlace(0.5);
-            this.maximum.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
+            max.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
             this._update(worldMatrix || this._worldMatrix || BABYLON.Matrix.Identity());
         };
         /**
@@ -19343,7 +19348,7 @@ var BABYLON;
          * @returns the current bounding box
          */
         BoundingBox.prototype.scale = function (factor) {
-            var tmpVectors = BABYLON.Tmp.Vector3;
+            var tmpVectors = BoundingBox.TmpVector3;
             var diff = this.maximum.subtractToRef(this.minimum, tmpVectors[0]);
             var len = diff.length();
             diff.normalizeFromLength(len);
@@ -19524,6 +19529,7 @@ var BABYLON;
             }
             return true;
         };
+        BoundingBox.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingBox;
     }());
     BABYLON.BoundingBox = BoundingBox;
@@ -19833,6 +19839,8 @@ var BABYLON;
             _this._pivotMatrix = BABYLON.Matrix.Identity();
             _this._postMultiplyPivotMatrix = false;
             _this._isWorldMatrixFrozen = false;
+            /** @hidden */
+            _this._indexInSceneTransformNodesArray = -1;
             /**
             * An event triggered after the world matrix is updated
             */
@@ -19904,8 +19912,8 @@ var BABYLON;
             set: function (quaternion) {
                 this._rotationQuaternion = quaternion;
                 //reset the rotation vector.
-                if (quaternion && this.rotation.length()) {
-                    this.rotation.copyFromFloats(0.0, 0.0, 0.0);
+                if (quaternion) {
+                    this.rotation.setAll(0.0);
                 }
             },
             enumerable: true,
@@ -20037,7 +20045,7 @@ var BABYLON;
         */
         TransformNode.prototype.setPivotMatrix = function (matrix, postMultiplyPivotMatrix) {
             if (postMultiplyPivotMatrix === void 0) { postMultiplyPivotMatrix = true; }
-            this._pivotMatrix = matrix.clone();
+            this._pivotMatrix.copyFrom(matrix);
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
             if (this._postMultiplyPivotMatrix) {
@@ -20121,10 +20129,9 @@ var BABYLON;
                 absolutePositionZ = absolutePosition.z;
             }
             if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+                var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
+                BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(absolutePositionX, absolutePositionY, absolutePositionZ, invertParentWorldMatrix, this.position);
             }
             else {
                 this.position.x = absolutePositionX;
@@ -20149,8 +20156,8 @@ var BABYLON;
          */
         TransformNode.prototype.getPositionExpressedInLocalSpace = function () {
             this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
+            var invLocalWorldMatrix = BABYLON.Tmp.Matrix[0];
+            this._localWorld.invertToRef(invLocalWorldMatrix);
             return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         };
         /**
@@ -20287,52 +20294,33 @@ var BABYLON;
             if (!node && !this.parent) {
                 return this;
             }
+            var quatRotation = BABYLON.Tmp.Quaternion[0];
+            var position = BABYLON.Tmp.Vector3[0];
+            var scale = BABYLON.Tmp.Vector3[1];
             if (!node) {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 if (this.parent && this.parent.computeWorldMatrix) {
                     this.parent.computeWorldMatrix(true);
                 }
                 this.computeWorldMatrix(true);
-                this.getWorldMatrix().decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                this.getWorldMatrix().decompose(scale, quatRotation, position);
             }
             else {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 var diffMatrix = BABYLON.Tmp.Matrix[0];
                 var invParentMatrix = BABYLON.Tmp.Matrix[1];
                 this.computeWorldMatrix(true);
                 node.computeWorldMatrix(true);
                 node.getWorldMatrix().invertToRef(invParentMatrix);
                 this.getWorldMatrix().multiplyToRef(invParentMatrix, diffMatrix);
-                diffMatrix.decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
+                diffMatrix.decompose(scale, quatRotation, position);
+            }
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(quatRotation);
+            }
+            else {
+                quatRotation.toEulerAnglesToRef(this.rotation);
             }
+            this.scaling.copyFrom(scale);
+            this.position.copyFrom(position);
             this.parent = node;
             return this;
         };
@@ -20396,8 +20384,8 @@ var BABYLON;
         TransformNode.prototype.rotate = function (axis, amount, space) {
             axis.normalize();
             if (!this.rotationQuaternion) {
-                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = BABYLON.Vector3.Zero();
+                this.rotationQuaternion = this.rotation.toQuaternion();
+                this.rotation.setAll(0);
             }
             var rotationQuaternion;
             if (!space || space === BABYLON.Space.LOCAL) {
@@ -20406,8 +20394,8 @@ var BABYLON;
             }
             else {
                 if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
+                    var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                    this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
                     axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
                 }
                 rotationQuaternion = BABYLON.Quaternion.RotationAxisToRef(axis, amount, TransformNode._rotationAxisCache);
@@ -20429,17 +20417,25 @@ var BABYLON;
             axis.normalize();
             if (!this.rotationQuaternion) {
                 this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation.copyFromFloats(0, 0, 0);
-            }
-            point.subtractToRef(this.position, BABYLON.Tmp.Vector3[0]);
-            BABYLON.Matrix.TranslationToRef(BABYLON.Tmp.Vector3[0].x, BABYLON.Tmp.Vector3[0].y, BABYLON.Tmp.Vector3[0].z, BABYLON.Tmp.Matrix[0]);
-            BABYLON.Tmp.Matrix[0].invertToRef(BABYLON.Tmp.Matrix[2]);
-            BABYLON.Matrix.RotationAxisToRef(axis, amount, BABYLON.Tmp.Matrix[1]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[1], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[0], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].decompose(BABYLON.Tmp.Vector3[0], BABYLON.Tmp.Quaternion[0], BABYLON.Tmp.Vector3[1]);
-            this.position.addInPlace(BABYLON.Tmp.Vector3[1]);
-            BABYLON.Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+                this.rotation.setAll(0);
+            }
+            var tmpVector = BABYLON.Tmp.Vector3[0];
+            var finalScale = BABYLON.Tmp.Vector3[1];
+            var finalTranslation = BABYLON.Tmp.Vector3[2];
+            var finalRotation = BABYLON.Tmp.Quaternion[0];
+            var translationMatrix = BABYLON.Tmp.Matrix[0]; // T
+            var translationMatrixInv = BABYLON.Tmp.Matrix[1]; // T'
+            var rotationMatrix = BABYLON.Tmp.Matrix[2]; // R
+            var finalMatrix = BABYLON.Tmp.Matrix[3]; // T' x R x T
+            point.subtractToRef(this.position, tmpVector);
+            BABYLON.Matrix.TranslationToRef(tmpVector.x, tmpVector.y, tmpVector.z, translationMatrix); // T
+            BABYLON.Matrix.TranslationToRef(-tmpVector.x, -tmpVector.y, -tmpVector.z, translationMatrixInv); // T'
+            BABYLON.Matrix.RotationAxisToRef(axis, amount, rotationMatrix); // R
+            translationMatrixInv.multiplyToRef(rotationMatrix, finalMatrix); // T' x R
+            finalMatrix.multiplyToRef(translationMatrix, finalMatrix); // T' x R x T
+            finalMatrix.decompose(finalScale, finalRotation, finalTranslation);
+            this.position.addInPlace(finalTranslation);
+            finalRotation.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
             return this;
         };
         /**
@@ -25171,6 +25167,9 @@ var BABYLON;
             this.geometries = new Array();
             /**
             * All of the tranform nodes added to this scene
+            * In the context a the Scene, it is not supposed to be modified manually.
+            * Any addition or removal should be done using the addTransformNode and removeTransformNode Scene methods.
+            * Note also that the order of the TransformNode wihin the array is not significant and might change.
             * @see http://doc.babylonjs.com/how_to/transformnode
             */
             this.transformNodes = new Array();
@@ -25371,6 +25370,11 @@ var BABYLON;
              * in order to block unwanted artifacts like system double clicks
              */
             _this.preventDefaultOnPointerDown = true;
+            /**
+             * This is used to call preventDefault() on pointer up
+             * in order to block unwanted artifacts like system double clicks
+             */
+            _this.preventDefaultOnPointerUp = true;
             // Metadata
             /**
              * Gets or sets user defined metadata
@@ -26970,8 +26974,10 @@ var BABYLON;
                         }
                     }
                 }
-                clickInfo.ignore = true;
-                cb(clickInfo, _this._currentPickResult);
+                else {
+                    clickInfo.ignore = true;
+                    cb(clickInfo, _this._currentPickResult);
+                }
             };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
@@ -27027,6 +27033,10 @@ var BABYLON;
                 _this._pickedUpMesh = null;
                 _this._meshPickProceed = false;
                 _this._updatePointerPosition(evt);
+                if (_this.preventDefaultOnPointerUp && canvas) {
+                    evt.preventDefault();
+                    canvas.focus();
+                }
                 _this._initClickEvent(_this.onPrePointerObservable, _this.onPointerObservable, evt, function (clickInfo, pickResult) {
                     // PreObservable support
                     if (_this.onPrePointerObservable.hasObservers()) {
@@ -27875,6 +27885,7 @@ var BABYLON;
          * @param newTransformNode defines the transform node to add
          */
         Scene.prototype.addTransformNode = function (newTransformNode) {
+            newTransformNode._indexInSceneTransformNodesArray = this.transformNodes.length;
             this.transformNodes.push(newTransformNode);
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
         };
@@ -27884,10 +27895,15 @@ var BABYLON;
          * @returns the index where the transform node was in the transform node list
          */
         Scene.prototype.removeTransformNode = function (toRemove) {
-            var index = this.transformNodes.indexOf(toRemove);
+            var index = toRemove._indexInSceneTransformNodesArray;
             if (index !== -1) {
-                // Remove from the scene if found
-                this.transformNodes.splice(index, 1);
+                if (index !== this.transformNodes.length - 1) {
+                    var lastNode = this.transformNodes[this.transformNodes.length - 1];
+                    this.transformNodes[index] = lastNode;
+                    lastNode._indexInSceneTransformNodesArray = index;
+                }
+                toRemove._indexInSceneTransformNodesArray = -1;
+                this.transformNodes.pop();
             }
             this.onTransformNodeRemovedObservable.notifyObservers(toRemove);
             return index;
@@ -28866,7 +28882,7 @@ var BABYLON;
                     continue;
                 }
                 mesh._preActivate();
-                if (mesh.isVisible && mesh.visibility > 0 && (mesh.alwaysSelectAsActiveMesh || ((mesh.layerMask & this.activeCamera.layerMask) !== 0 && mesh.isInFrustum(this._frustumPlanes)))) {
+                if (mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && (mesh.alwaysSelectAsActiveMesh || mesh.isInFrustum(this._frustumPlanes))) {
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
@@ -32978,12 +32994,12 @@ var BABYLON;
             this.computeWorldMatrix();
             var mat = this.material || scene.defaultMaterial;
             if (mat) {
-                if (mat.storeEffectOnSubMeshes) {
+                if (mat._storeEffectOnSubMeshes) {
                     for (var _i = 0, _a = this.subMeshes; _i < _a.length; _i++) {
                         var subMesh = _a[_i];
                         var effectiveMaterial = subMesh.getMaterial();
                         if (effectiveMaterial) {
-                            if (effectiveMaterial.storeEffectOnSubMeshes) {
+                            if (effectiveMaterial._storeEffectOnSubMeshes) {
                                 if (!effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                                     return false;
                                 }
@@ -33660,7 +33676,7 @@ var BABYLON;
                 return this;
             }
             this._effectiveMaterial = material;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                     return this;
                 }
@@ -33677,7 +33693,7 @@ var BABYLON;
                 step.action(this, subMesh, batch);
             }
             var effect;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 effect = subMesh.effect;
             }
             else {
@@ -33703,7 +33719,7 @@ var BABYLON;
                 this._bind(subMesh, effect, fillMode);
             }
             var world = this.getWorldMatrix();
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             }
             else {
@@ -36345,9 +36361,9 @@ var BABYLON;
              */
             this.doNotSerialize = false;
             /**
-             * Specifies if the effect should be stored on sub meshes
+             * @hidden
              */
-            this.storeEffectOnSubMeshes = false;
+            this._storeEffectOnSubMeshes = false;
             /**
             * An event triggered when the material is disposed
             */
@@ -37033,7 +37049,7 @@ var BABYLON;
                 if (localOptions.clipPlane) {
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                 }
-                if (_this.storeEffectOnSubMeshes) {
+                if (_this._storeEffectOnSubMeshes) {
                     if (_this.isReadyForSubMesh(mesh, subMesh)) {
                         if (onCompiled) {
                             onCompiled(_this);
@@ -37193,7 +37209,7 @@ var BABYLON;
                     mesh.material = null;
                     if (mesh.geometry) {
                         var geometry = (mesh.geometry);
-                        if (this.storeEffectOnSubMeshes) {
+                        if (this._storeEffectOnSubMeshes) {
                             for (var _i = 0, _a = mesh.subMeshes; _i < _a.length; _i++) {
                                 var subMesh = _a[_i];
                                 geometry._releaseVertexArrayObject(subMesh._materialEffect);
@@ -37211,7 +37227,7 @@ var BABYLON;
             this._uniformBuffer.dispose();
             // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
             if (forceDisposeEffect && this._effect) {
-                if (!this.storeEffectOnSubMeshes) {
+                if (!this._storeEffectOnSubMeshes) {
                     this._scene.getEngine()._releaseEffect(this._effect);
                 }
                 this._effect = null;
@@ -43191,7 +43207,7 @@ var BABYLON;
              * This is mostly used when shader parallel compilation is supported (true by default)
              */
             _this.allowShaderHotSwapping = true;
-            _this.storeEffectOnSubMeshes = true;
+            _this._storeEffectOnSubMeshes = true;
             return _this;
         }
         PushMaterial.prototype.getEffect = function () {
@@ -68312,13 +68328,22 @@ var BABYLON;
             var index = 0;
             var idx = 0;
             var tmpNormal = BABYLON.Tmp.Vector3[0];
-            var rotMatrix = BABYLON.Tmp.Matrix[0];
-            var invertedRotMatrix = BABYLON.Tmp.Matrix[1];
+            var quaternion = BABYLON.Tmp.Quaternion[0];
+            var invertedRotMatrix = BABYLON.Tmp.Matrix[0];
             for (var p = 0; p < this.particles.length; p++) {
                 var particle = this.particles[p];
                 var shape = particle._model._shape;
-                particle.getRotationMatrix(rotMatrix);
-                rotMatrix.invertToRef(invertedRotMatrix);
+                // computing the inverse of the rotation matrix from the quaternion
+                // is equivalent to computing the matrix of the inverse quaternion, i.e of the conjugate quaternion
+                if (particle.rotationQuaternion) {
+                    particle.rotationQuaternion.conjugateToRef(quaternion);
+                }
+                else {
+                    var rotation = particle.rotation;
+                    BABYLON.Quaternion.RotationYawPitchRollToRef(rotation.y, rotation.x, rotation.z, quaternion);
+                    quaternion.conjugateInPlace();
+                }
+                quaternion.toRotationMatrix(invertedRotMatrix);
                 for (var pt = 0; pt < shape.length; pt++) {
                     idx = index + pt * 3;
                     BABYLON.Vector3.TransformNormalFromFloatsToRef(this._normals32[idx], this._normals32[idx + 1], this._normals32[idx + 2], invertedRotMatrix, tmpNormal);
@@ -80167,7 +80192,7 @@ var BABYLON;
             var _this = _super.call(this, name, scene, true) || this;
             scene.multiMaterials.push(_this);
             _this.subMaterials = new Array();
-            _this.storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
+            _this._storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
             return _this;
         }
         Object.defineProperty(MultiMaterial.prototype, "subMaterials", {
@@ -80249,7 +80274,7 @@ var BABYLON;
             for (var index = 0; index < this.subMaterials.length; index++) {
                 var subMaterial = this.subMaterials[index];
                 if (subMaterial) {
-                    if (subMaterial.storeEffectOnSubMeshes) {
+                    if (subMaterial._storeEffectOnSubMeshes) {
                         if (!subMaterial.isReadyForSubMesh(mesh, subMesh, useInstances)) {
                             return false;
                         }

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/babylon.worker.js


+ 125 - 100
dist/preview release/es6.js

@@ -12239,6 +12239,10 @@ var BABYLON;
              */
             this.onBeginFrameObservable = new BABYLON.Observable();
             /**
+             * If set, will be used to request the next animation frame for the render loop
+             */
+            this.customAnimationFrameRequester = null;
+            /**
              * Observable raised when the engine ends the current frame
              */
             this.onEndFrameObservable = new BABYLON.Observable();
@@ -13401,11 +13405,16 @@ var BABYLON;
             }
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
-                var requester = null;
-                if (this._vrDisplay && this._vrDisplay.isPresenting) {
-                    requester = this._vrDisplay;
+                if (this.customAnimationFrameRequester) {
+                    this.customAnimationFrameRequester.requestID = BABYLON.Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
+                    this._frameHandler = this.customAnimationFrameRequester.requestID;
+                }
+                else if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+                }
+                else {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction);
                 }
-                this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, requester);
             }
             else {
                 this._renderingQueueLaunched = false;
@@ -19175,7 +19184,7 @@ var BABYLON;
             this.minimum.copyFrom(min);
             this.maximum.copyFrom(max);
             var distance = BABYLON.Vector3.Distance(min, max);
-            BABYLON.Vector3.LerpToRef(min, max, 0.5, this.center);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
             this.radius = distance * 0.5;
             this._update(worldMatrix || _identityMatrix);
         };
@@ -19186,8 +19195,8 @@ var BABYLON;
          */
         BoundingSphere.prototype.scale = function (factor) {
             var newRadius = this.radius * factor;
-            var tmpVectors = BABYLON.Tmp.Vector3;
-            var tempRadiusVector = tmpVectors[0].copyFromFloats(newRadius, newRadius, newRadius);
+            var tmpVectors = BoundingSphere.TmpVector3;
+            var tempRadiusVector = tmpVectors[0].setAll(newRadius);
             var min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
             var max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
             this.reConstruct(min, max);
@@ -19197,7 +19206,7 @@ var BABYLON;
         /** @hidden */
         BoundingSphere.prototype._update = function (world) {
             BABYLON.Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            var tempVector = BABYLON.Tmp.Vector3[0];
+            var tempVector = BoundingSphere.TmpVector3[0];
             BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, tempVector);
             this.radiusWorld = Math.max(Math.abs(tempVector.x), Math.abs(tempVector.y), Math.abs(tempVector.z)) * this.radius;
         };
@@ -19220,11 +19229,8 @@ var BABYLON;
          * @returns true if the point is inside the bounding sphere
          */
         BoundingSphere.prototype.intersectsPoint = function (point) {
-            var x = this.centerWorld.x - point.x;
-            var y = this.centerWorld.y - point.y;
-            var z = this.centerWorld.z - point.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (this.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(this.centerWorld, point);
+            if (this.radiusWorld * this.radiusWorld < squareDistance) {
                 return false;
             }
             return true;
@@ -19237,15 +19243,14 @@ var BABYLON;
          * @returns true if the speres intersect
          */
         BoundingSphere.Intersects = function (sphere0, sphere1) {
-            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
-            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
-            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (sphere0.radiusWorld + sphere1.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(sphere0.centerWorld, sphere1.centerWorld);
+            var radiusSum = sphere0.radiusWorld + sphere1.radiusWorld;
+            if (radiusSum * radiusSum < squareDistance) {
                 return false;
             }
             return true;
         };
+        BoundingSphere.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingSphere;
     }());
     BABYLON.BoundingSphere = BoundingSphere;
@@ -19333,8 +19338,8 @@ var BABYLON;
             vectors[6].copyFromFloats(minX, maxY, maxZ);
             vectors[7].copyFromFloats(maxX, minY, maxZ);
             // OBB
-            this.maximum.addToRef(min, this.center).scaleInPlace(0.5);
-            this.maximum.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
+            max.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
             this._update(worldMatrix || this._worldMatrix || BABYLON.Matrix.Identity());
         };
         /**
@@ -19343,7 +19348,7 @@ var BABYLON;
          * @returns the current bounding box
          */
         BoundingBox.prototype.scale = function (factor) {
-            var tmpVectors = BABYLON.Tmp.Vector3;
+            var tmpVectors = BoundingBox.TmpVector3;
             var diff = this.maximum.subtractToRef(this.minimum, tmpVectors[0]);
             var len = diff.length();
             diff.normalizeFromLength(len);
@@ -19524,6 +19529,7 @@ var BABYLON;
             }
             return true;
         };
+        BoundingBox.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingBox;
     }());
     BABYLON.BoundingBox = BoundingBox;
@@ -19833,6 +19839,8 @@ var BABYLON;
             _this._pivotMatrix = BABYLON.Matrix.Identity();
             _this._postMultiplyPivotMatrix = false;
             _this._isWorldMatrixFrozen = false;
+            /** @hidden */
+            _this._indexInSceneTransformNodesArray = -1;
             /**
             * An event triggered after the world matrix is updated
             */
@@ -19904,8 +19912,8 @@ var BABYLON;
             set: function (quaternion) {
                 this._rotationQuaternion = quaternion;
                 //reset the rotation vector.
-                if (quaternion && this.rotation.length()) {
-                    this.rotation.copyFromFloats(0.0, 0.0, 0.0);
+                if (quaternion) {
+                    this.rotation.setAll(0.0);
                 }
             },
             enumerable: true,
@@ -20037,7 +20045,7 @@ var BABYLON;
         */
         TransformNode.prototype.setPivotMatrix = function (matrix, postMultiplyPivotMatrix) {
             if (postMultiplyPivotMatrix === void 0) { postMultiplyPivotMatrix = true; }
-            this._pivotMatrix = matrix.clone();
+            this._pivotMatrix.copyFrom(matrix);
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
             if (this._postMultiplyPivotMatrix) {
@@ -20121,10 +20129,9 @@ var BABYLON;
                 absolutePositionZ = absolutePosition.z;
             }
             if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+                var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
+                BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(absolutePositionX, absolutePositionY, absolutePositionZ, invertParentWorldMatrix, this.position);
             }
             else {
                 this.position.x = absolutePositionX;
@@ -20149,8 +20156,8 @@ var BABYLON;
          */
         TransformNode.prototype.getPositionExpressedInLocalSpace = function () {
             this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
+            var invLocalWorldMatrix = BABYLON.Tmp.Matrix[0];
+            this._localWorld.invertToRef(invLocalWorldMatrix);
             return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         };
         /**
@@ -20287,52 +20294,33 @@ var BABYLON;
             if (!node && !this.parent) {
                 return this;
             }
+            var quatRotation = BABYLON.Tmp.Quaternion[0];
+            var position = BABYLON.Tmp.Vector3[0];
+            var scale = BABYLON.Tmp.Vector3[1];
             if (!node) {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 if (this.parent && this.parent.computeWorldMatrix) {
                     this.parent.computeWorldMatrix(true);
                 }
                 this.computeWorldMatrix(true);
-                this.getWorldMatrix().decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                this.getWorldMatrix().decompose(scale, quatRotation, position);
             }
             else {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 var diffMatrix = BABYLON.Tmp.Matrix[0];
                 var invParentMatrix = BABYLON.Tmp.Matrix[1];
                 this.computeWorldMatrix(true);
                 node.computeWorldMatrix(true);
                 node.getWorldMatrix().invertToRef(invParentMatrix);
                 this.getWorldMatrix().multiplyToRef(invParentMatrix, diffMatrix);
-                diffMatrix.decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
+                diffMatrix.decompose(scale, quatRotation, position);
+            }
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(quatRotation);
+            }
+            else {
+                quatRotation.toEulerAnglesToRef(this.rotation);
             }
+            this.scaling.copyFrom(scale);
+            this.position.copyFrom(position);
             this.parent = node;
             return this;
         };
@@ -20396,8 +20384,8 @@ var BABYLON;
         TransformNode.prototype.rotate = function (axis, amount, space) {
             axis.normalize();
             if (!this.rotationQuaternion) {
-                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = BABYLON.Vector3.Zero();
+                this.rotationQuaternion = this.rotation.toQuaternion();
+                this.rotation.setAll(0);
             }
             var rotationQuaternion;
             if (!space || space === BABYLON.Space.LOCAL) {
@@ -20406,8 +20394,8 @@ var BABYLON;
             }
             else {
                 if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
+                    var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                    this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
                     axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
                 }
                 rotationQuaternion = BABYLON.Quaternion.RotationAxisToRef(axis, amount, TransformNode._rotationAxisCache);
@@ -20429,17 +20417,25 @@ var BABYLON;
             axis.normalize();
             if (!this.rotationQuaternion) {
                 this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation.copyFromFloats(0, 0, 0);
-            }
-            point.subtractToRef(this.position, BABYLON.Tmp.Vector3[0]);
-            BABYLON.Matrix.TranslationToRef(BABYLON.Tmp.Vector3[0].x, BABYLON.Tmp.Vector3[0].y, BABYLON.Tmp.Vector3[0].z, BABYLON.Tmp.Matrix[0]);
-            BABYLON.Tmp.Matrix[0].invertToRef(BABYLON.Tmp.Matrix[2]);
-            BABYLON.Matrix.RotationAxisToRef(axis, amount, BABYLON.Tmp.Matrix[1]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[1], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[0], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].decompose(BABYLON.Tmp.Vector3[0], BABYLON.Tmp.Quaternion[0], BABYLON.Tmp.Vector3[1]);
-            this.position.addInPlace(BABYLON.Tmp.Vector3[1]);
-            BABYLON.Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+                this.rotation.setAll(0);
+            }
+            var tmpVector = BABYLON.Tmp.Vector3[0];
+            var finalScale = BABYLON.Tmp.Vector3[1];
+            var finalTranslation = BABYLON.Tmp.Vector3[2];
+            var finalRotation = BABYLON.Tmp.Quaternion[0];
+            var translationMatrix = BABYLON.Tmp.Matrix[0]; // T
+            var translationMatrixInv = BABYLON.Tmp.Matrix[1]; // T'
+            var rotationMatrix = BABYLON.Tmp.Matrix[2]; // R
+            var finalMatrix = BABYLON.Tmp.Matrix[3]; // T' x R x T
+            point.subtractToRef(this.position, tmpVector);
+            BABYLON.Matrix.TranslationToRef(tmpVector.x, tmpVector.y, tmpVector.z, translationMatrix); // T
+            BABYLON.Matrix.TranslationToRef(-tmpVector.x, -tmpVector.y, -tmpVector.z, translationMatrixInv); // T'
+            BABYLON.Matrix.RotationAxisToRef(axis, amount, rotationMatrix); // R
+            translationMatrixInv.multiplyToRef(rotationMatrix, finalMatrix); // T' x R
+            finalMatrix.multiplyToRef(translationMatrix, finalMatrix); // T' x R x T
+            finalMatrix.decompose(finalScale, finalRotation, finalTranslation);
+            this.position.addInPlace(finalTranslation);
+            finalRotation.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
             return this;
         };
         /**
@@ -25171,6 +25167,9 @@ var BABYLON;
             this.geometries = new Array();
             /**
             * All of the tranform nodes added to this scene
+            * In the context a the Scene, it is not supposed to be modified manually.
+            * Any addition or removal should be done using the addTransformNode and removeTransformNode Scene methods.
+            * Note also that the order of the TransformNode wihin the array is not significant and might change.
             * @see http://doc.babylonjs.com/how_to/transformnode
             */
             this.transformNodes = new Array();
@@ -25371,6 +25370,11 @@ var BABYLON;
              * in order to block unwanted artifacts like system double clicks
              */
             _this.preventDefaultOnPointerDown = true;
+            /**
+             * This is used to call preventDefault() on pointer up
+             * in order to block unwanted artifacts like system double clicks
+             */
+            _this.preventDefaultOnPointerUp = true;
             // Metadata
             /**
              * Gets or sets user defined metadata
@@ -26970,8 +26974,10 @@ var BABYLON;
                         }
                     }
                 }
-                clickInfo.ignore = true;
-                cb(clickInfo, _this._currentPickResult);
+                else {
+                    clickInfo.ignore = true;
+                    cb(clickInfo, _this._currentPickResult);
+                }
             };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
@@ -27027,6 +27033,10 @@ var BABYLON;
                 _this._pickedUpMesh = null;
                 _this._meshPickProceed = false;
                 _this._updatePointerPosition(evt);
+                if (_this.preventDefaultOnPointerUp && canvas) {
+                    evt.preventDefault();
+                    canvas.focus();
+                }
                 _this._initClickEvent(_this.onPrePointerObservable, _this.onPointerObservable, evt, function (clickInfo, pickResult) {
                     // PreObservable support
                     if (_this.onPrePointerObservable.hasObservers()) {
@@ -27875,6 +27885,7 @@ var BABYLON;
          * @param newTransformNode defines the transform node to add
          */
         Scene.prototype.addTransformNode = function (newTransformNode) {
+            newTransformNode._indexInSceneTransformNodesArray = this.transformNodes.length;
             this.transformNodes.push(newTransformNode);
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
         };
@@ -27884,10 +27895,15 @@ var BABYLON;
          * @returns the index where the transform node was in the transform node list
          */
         Scene.prototype.removeTransformNode = function (toRemove) {
-            var index = this.transformNodes.indexOf(toRemove);
+            var index = toRemove._indexInSceneTransformNodesArray;
             if (index !== -1) {
-                // Remove from the scene if found
-                this.transformNodes.splice(index, 1);
+                if (index !== this.transformNodes.length - 1) {
+                    var lastNode = this.transformNodes[this.transformNodes.length - 1];
+                    this.transformNodes[index] = lastNode;
+                    lastNode._indexInSceneTransformNodesArray = index;
+                }
+                toRemove._indexInSceneTransformNodesArray = -1;
+                this.transformNodes.pop();
             }
             this.onTransformNodeRemovedObservable.notifyObservers(toRemove);
             return index;
@@ -28866,7 +28882,7 @@ var BABYLON;
                     continue;
                 }
                 mesh._preActivate();
-                if (mesh.isVisible && mesh.visibility > 0 && (mesh.alwaysSelectAsActiveMesh || ((mesh.layerMask & this.activeCamera.layerMask) !== 0 && mesh.isInFrustum(this._frustumPlanes)))) {
+                if (mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && (mesh.alwaysSelectAsActiveMesh || mesh.isInFrustum(this._frustumPlanes))) {
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
@@ -32978,12 +32994,12 @@ var BABYLON;
             this.computeWorldMatrix();
             var mat = this.material || scene.defaultMaterial;
             if (mat) {
-                if (mat.storeEffectOnSubMeshes) {
+                if (mat._storeEffectOnSubMeshes) {
                     for (var _i = 0, _a = this.subMeshes; _i < _a.length; _i++) {
                         var subMesh = _a[_i];
                         var effectiveMaterial = subMesh.getMaterial();
                         if (effectiveMaterial) {
-                            if (effectiveMaterial.storeEffectOnSubMeshes) {
+                            if (effectiveMaterial._storeEffectOnSubMeshes) {
                                 if (!effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                                     return false;
                                 }
@@ -33660,7 +33676,7 @@ var BABYLON;
                 return this;
             }
             this._effectiveMaterial = material;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                     return this;
                 }
@@ -33677,7 +33693,7 @@ var BABYLON;
                 step.action(this, subMesh, batch);
             }
             var effect;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 effect = subMesh.effect;
             }
             else {
@@ -33703,7 +33719,7 @@ var BABYLON;
                 this._bind(subMesh, effect, fillMode);
             }
             var world = this.getWorldMatrix();
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             }
             else {
@@ -36345,9 +36361,9 @@ var BABYLON;
              */
             this.doNotSerialize = false;
             /**
-             * Specifies if the effect should be stored on sub meshes
+             * @hidden
              */
-            this.storeEffectOnSubMeshes = false;
+            this._storeEffectOnSubMeshes = false;
             /**
             * An event triggered when the material is disposed
             */
@@ -37033,7 +37049,7 @@ var BABYLON;
                 if (localOptions.clipPlane) {
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                 }
-                if (_this.storeEffectOnSubMeshes) {
+                if (_this._storeEffectOnSubMeshes) {
                     if (_this.isReadyForSubMesh(mesh, subMesh)) {
                         if (onCompiled) {
                             onCompiled(_this);
@@ -37193,7 +37209,7 @@ var BABYLON;
                     mesh.material = null;
                     if (mesh.geometry) {
                         var geometry = (mesh.geometry);
-                        if (this.storeEffectOnSubMeshes) {
+                        if (this._storeEffectOnSubMeshes) {
                             for (var _i = 0, _a = mesh.subMeshes; _i < _a.length; _i++) {
                                 var subMesh = _a[_i];
                                 geometry._releaseVertexArrayObject(subMesh._materialEffect);
@@ -37211,7 +37227,7 @@ var BABYLON;
             this._uniformBuffer.dispose();
             // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
             if (forceDisposeEffect && this._effect) {
-                if (!this.storeEffectOnSubMeshes) {
+                if (!this._storeEffectOnSubMeshes) {
                     this._scene.getEngine()._releaseEffect(this._effect);
                 }
                 this._effect = null;
@@ -43191,7 +43207,7 @@ var BABYLON;
              * This is mostly used when shader parallel compilation is supported (true by default)
              */
             _this.allowShaderHotSwapping = true;
-            _this.storeEffectOnSubMeshes = true;
+            _this._storeEffectOnSubMeshes = true;
             return _this;
         }
         PushMaterial.prototype.getEffect = function () {
@@ -68312,13 +68328,22 @@ var BABYLON;
             var index = 0;
             var idx = 0;
             var tmpNormal = BABYLON.Tmp.Vector3[0];
-            var rotMatrix = BABYLON.Tmp.Matrix[0];
-            var invertedRotMatrix = BABYLON.Tmp.Matrix[1];
+            var quaternion = BABYLON.Tmp.Quaternion[0];
+            var invertedRotMatrix = BABYLON.Tmp.Matrix[0];
             for (var p = 0; p < this.particles.length; p++) {
                 var particle = this.particles[p];
                 var shape = particle._model._shape;
-                particle.getRotationMatrix(rotMatrix);
-                rotMatrix.invertToRef(invertedRotMatrix);
+                // computing the inverse of the rotation matrix from the quaternion
+                // is equivalent to computing the matrix of the inverse quaternion, i.e of the conjugate quaternion
+                if (particle.rotationQuaternion) {
+                    particle.rotationQuaternion.conjugateToRef(quaternion);
+                }
+                else {
+                    var rotation = particle.rotation;
+                    BABYLON.Quaternion.RotationYawPitchRollToRef(rotation.y, rotation.x, rotation.z, quaternion);
+                    quaternion.conjugateInPlace();
+                }
+                quaternion.toRotationMatrix(invertedRotMatrix);
                 for (var pt = 0; pt < shape.length; pt++) {
                     idx = index + pt * 3;
                     BABYLON.Vector3.TransformNormalFromFloatsToRef(this._normals32[idx], this._normals32[idx + 1], this._normals32[idx + 2], invertedRotMatrix, tmpNormal);
@@ -80167,7 +80192,7 @@ var BABYLON;
             var _this = _super.call(this, name, scene, true) || this;
             scene.multiMaterials.push(_this);
             _this.subMaterials = new Array();
-            _this.storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
+            _this._storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
             return _this;
         }
         Object.defineProperty(MultiMaterial.prototype, "subMaterials", {
@@ -80249,7 +80274,7 @@ var BABYLON;
             for (var index = 0; index < this.subMaterials.length; index++) {
                 var subMaterial = this.subMaterials[index];
                 if (subMaterial) {
-                    if (subMaterial.storeEffectOnSubMeshes) {
+                    if (subMaterial._storeEffectOnSubMeshes) {
                         if (!subMaterial.isReadyForSubMesh(mesh, subMesh, useInstances)) {
                             return false;
                         }

+ 2 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -849,6 +849,8 @@ declare module BABYLON.GUI {
             isPointerBlocker: boolean;
             /** Gets or sets a boolean indicating if the control can be focusable */
             isFocusInvisible: boolean;
+            /** Gets or sets a boolean indicating if the children are clipped to the current control bounds */
+            clipChildren: boolean;
             /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
             shadowOffsetX: number;
             /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/gui/babylon.gui.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 4 - 0
dist/preview release/gui/babylon.gui.module.d.ts

@@ -952,6 +952,8 @@ declare module 'babylonjs-gui/2D/controls/control' {
             isPointerBlocker: boolean;
             /** Gets or sets a boolean indicating if the control can be focusable */
             isFocusInvisible: boolean;
+            /** Gets or sets a boolean indicating if the children are clipped to the current control bounds */
+            clipChildren: boolean;
             /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
             shadowOffsetX: number;
             /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */
@@ -3676,6 +3678,8 @@ declare module BABYLON.GUI {
             isPointerBlocker: boolean;
             /** Gets or sets a boolean indicating if the control can be focusable */
             isFocusInvisible: boolean;
+            /** Gets or sets a boolean indicating if the children are clipped to the current control bounds */
+            clipChildren: boolean;
             /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
             shadowOffsetX: number;
             /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


+ 459 - 202
dist/preview release/viewer/babylon.viewer.d.ts

@@ -674,208 +674,6 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
-    /**
-        * BABYLON.Animation play mode enum - is the animation looping or playing once
-        */
-    export const enum AnimationPlayMode {
-            ONCE = 0,
-            LOOP = 1
-    }
-    /**
-        * An enum representing the current state of an animation object
-        */
-    export const enum AnimationState {
-            INIT = 0,
-            PLAYING = 1,
-            PAUSED = 2,
-            STOPPED = 3,
-            ENDED = 4
-    }
-    /**
-        * The different type of easing functions available
-        */
-    export const enum EasingFunction {
-            Linear = 0,
-            CircleEase = 1,
-            BackEase = 2,
-            BounceEase = 3,
-            CubicEase = 4,
-            ElasticEase = 5,
-            ExponentialEase = 6,
-            PowerEase = 7,
-            QuadraticEase = 8,
-            QuarticEase = 9,
-            QuinticEase = 10,
-            SineEase = 11
-    }
-    /**
-        * Defines a simple animation to be applied to a model (scale).
-        */
-    export interface ModelAnimationConfiguration {
-            /**
-                * Time of animation, in seconds
-                */
-            time: number;
-            /**
-                * Scale to apply
-                */
-            scaling?: BABYLON.Vector3;
-            /**
-                * Easing function to apply
-                * See SPECTRE.EasingFunction
-                */
-            easingFunction?: number;
-            /**
-                * An Easing mode to apply to the easing function
-                * See BABYLON.EasingFunction
-                */
-            easingMode?: number;
-    }
-    /**
-        * This interface can be implemented to define new types of ModelAnimation objects.
-        */
-    export interface IModelAnimation {
-            /**
-                * Current animation state (playing, stopped etc')
-                */
-            readonly state: AnimationState;
-            /**
-                * the name of the animation
-                */
-            readonly name: string;
-            /**
-                * Get the max numbers of frame available in the animation group
-                *
-                * In correlation to an arry, this would be ".length"
-                */
-            readonly frames: number;
-            /**
-                * Get the current frame playing right now.
-                * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
-                *
-                * In correlation to an array, this would be the current index
-                */
-            readonly currentFrame: number;
-            /**
-                * BABYLON.Animation's FPS value
-                */
-            readonly fps: number;
-            /**
-                * Get or set the animation's speed ration (Frame-to-fps)
-                */
-            speedRatio: number;
-            /**
-                * Gets or sets the aimation's play mode.
-                */
-            playMode: AnimationPlayMode;
-            /**
-                * Start the animation
-                */
-            start(): any;
-            /**
-                * Stop the animation.
-                * This will fail silently if the animation group is already stopped.
-                */
-            stop(): any;
-            /**
-                * Pause the animation
-                * This will fail silently if the animation is not currently playing
-                */
-            pause(): any;
-            /**
-                * Reset this animation
-                */
-            reset(): any;
-            /**
-                * Restart the animation
-                */
-            restart(): any;
-            /**
-                * Go to a specific
-                * @param frameNumber the frame number to go to
-                */
-            goToFrame(frameNumber: number): any;
-            /**
-                * Dispose this animation
-                */
-            dispose(): any;
-    }
-    /**
-        * The GroupModelAnimation is an implementation of the IModelAnimation interface using BABYLON's
-        * native GroupAnimation class.
-        */
-    export class GroupModelAnimation implements IModelAnimation {
-            /**
-                * Create a new GroupModelAnimation object using an BABYLON.AnimationGroup object
-                * @param _animationGroup The aniamtion group to base the class on
-                */
-            constructor(_animationGroup: BABYLON.AnimationGroup);
-            /**
-                * Get the animation's name
-                */
-            readonly name: string;
-            /**
-                * Get the current animation's state
-                */
-            readonly state: AnimationState;
-            /**
-             * Sets the speed ratio to use for all animations
-             */
-            speedRatio: number;
-            /**
-                * Get the max numbers of frame available in the animation group
-                *
-                * In correlation to an arry, this would be ".length"
-                */
-            readonly frames: number;
-            /**
-                * Get the current frame playing right now.
-                * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
-                *
-                * In correlation to an array, this would be the current index
-                */
-            readonly currentFrame: number;
-            /**
-                * Get the FPS value of this animation
-                */
-            readonly fps: number;
-            /**
-             * Set the play mode.
-             * If the animation is played, it will continue playing at least once more, depending on the new play mode set.
-             * If the animation is not set, the will be initialized and will wait for the user to start playing it.
-             */
-            playMode: AnimationPlayMode;
-            /**
-                * Reset the animation group
-                */
-            reset(): void;
-            /**
-                * Restart the animation group
-                */
-            restart(): void;
-            /**
-                *
-                * @param frameNumber Go to a specific frame in the animation
-                */
-            goToFrame(frameNumber: number): void;
-            /**
-                * Start playing the animation.
-                */
-            start(): void;
-            /**
-                * Pause the animation
-                */
-            pause(): void;
-            /**
-                * Stop the animation.
-                * This will fail silently if the animation group is already stopped.
-                */
-            stop(): void;
-            /**
-                * Dispose this animation object.
-                */
-            dispose(): void;
-    }
 }
 declare module BabylonViewer {
     /**
@@ -1728,6 +1526,465 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
+    export interface ICameraConfiguration {
+        position?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        rotation?: {
+            x: number;
+            y: number;
+            z: number;
+            w: number;
+        };
+        fov?: number;
+        fovMode?: number;
+        minZ?: number;
+        maxZ?: number;
+        inertia?: number;
+        exposure?: number;
+        pinchPrecision?: number;
+        behaviors?: {
+            [name: string]: boolean | number | ICameraBehaviorConfiguration;
+        };
+        disableCameraControl?: boolean;
+        disableCtrlForPanning?: boolean;
+        disableAutoFocus?: boolean;
+        [propName: string]: any;
+    }
+    export interface ICameraBehaviorConfiguration {
+        type: number;
+        [propName: string]: any;
+    }
+}
+declare module BabylonViewer {
+    /**
+        * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
+        */
+    export interface IColorGradingConfiguration {
+            /**
+                * Transform data string, encoded as determined by transformDataFormat.
+                */
+            transformData: string;
+            /**
+                * The encoding format of TransformData (currently only raw-base16 is supported).
+                */
+            transformDataFormat: string;
+            /**
+                * The weight of the transform
+                */
+            transformWeight: number;
+            /**
+                * Color curve colorFilterHueGlobal value
+                */
+            colorFilterHueGlobal: number;
+            /**
+                * Color curve colorFilterHueShadows value
+                */
+            colorFilterHueShadows: number;
+            /**
+                * Color curve colorFilterHueMidtones value
+                */
+            colorFilterHueMidtones: number;
+            /**
+                * Color curve colorFilterHueHighlights value
+                */
+            colorFilterHueHighlights: number;
+            /**
+                * Color curve colorFilterDensityGlobal value
+                */
+            colorFilterDensityGlobal: number;
+            /**
+                * Color curve colorFilterDensityShadows value
+                */
+            colorFilterDensityShadows: number;
+            /**
+                * Color curve colorFilterDensityMidtones value
+                */
+            colorFilterDensityMidtones: number;
+            /**
+                * Color curve colorFilterDensityHighlights value
+                */
+            colorFilterDensityHighlights: number;
+            /**
+                * Color curve saturationGlobal value
+                */
+            saturationGlobal: number;
+            /**
+                * Color curve saturationShadows value
+                */
+            saturationShadows: number;
+            /**
+                * Color curve saturationMidtones value
+                */
+            saturationMidtones: number;
+            /**
+                * Color curve saturationHighlights value
+                */
+            saturationHighlights: number;
+            /**
+                * Color curve exposureGlobal value
+                */
+            exposureGlobal: number;
+            /**
+                * Color curve exposureShadows value
+                */
+            exposureShadows: number;
+            /**
+                * Color curve exposureMidtones value
+                */
+            exposureMidtones: number;
+            /**
+                * Color curve exposureHighlights value
+                */
+            exposureHighlights: number;
+    }
+}
+declare module BabylonViewer {
+    export interface IDefaultRenderingPipelineConfiguration {
+        sharpenEnabled?: boolean;
+        bloomEnabled?: boolean;
+        bloomThreshold?: number;
+        depthOfFieldEnabled?: boolean;
+        depthOfFieldBlurLevel?: BABYLON.DepthOfFieldEffectBlurLevel;
+        fxaaEnabled?: boolean;
+        imageProcessingEnabled?: boolean;
+        defaultPipelineTextureType?: number;
+        bloomScale?: number;
+        chromaticAberrationEnabled?: boolean;
+        grainEnabled?: boolean;
+        bloomKernel?: number;
+        hardwareScaleLevel?: number;
+        bloomWeight?: number;
+        hdr?: boolean;
+        samples?: number;
+        glowLayerEnabled?: boolean;
+    }
+}
+declare module BabylonViewer {
+    export interface IGroundConfiguration {
+        size?: number;
+        receiveShadows?: boolean;
+        shadowLevel?: number;
+        shadowOnly?: boolean;
+        mirror?: boolean | {
+            sizeRatio?: number;
+            blurKernel?: number;
+            amount?: number;
+            fresnelWeight?: number;
+            fallOffDistance?: number;
+            textureType?: number;
+        };
+        texture?: string;
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        opacity?: number;
+        material?: {
+            [propName: string]: any;
+        };
+    }
+}
+declare module BabylonViewer {
+    export interface IImageProcessingConfiguration {
+        colorGradingEnabled?: boolean;
+        colorCurvesEnabled?: boolean;
+        colorCurves?: {
+            globalHue?: number;
+            globalDensity?: number;
+            globalSaturation?: number;
+            globalExposure?: number;
+            highlightsHue?: number;
+            highlightsDensity?: number;
+            highlightsSaturation?: number;
+            highlightsExposure?: number;
+            midtonesHue?: number;
+            midtonesDensity?: number;
+            midtonesSaturation?: number;
+            midtonesExposure?: number;
+            shadowsHue?: number;
+            shadowsDensity?: number;
+            shadowsSaturation?: number;
+            shadowsExposure?: number;
+        };
+        colorGradingWithGreenDepth?: boolean;
+        colorGradingBGR?: boolean;
+        exposure?: number;
+        toneMappingEnabled?: boolean;
+        contrast?: number;
+        vignetteEnabled?: boolean;
+        vignetteStretch?: number;
+        vignetteCentreX?: number;
+        vignetteCentreY?: number;
+        vignetteWeight?: number;
+        vignetteColor?: {
+            r: number;
+            g: number;
+            b: number;
+            a?: number;
+        };
+        vignetteCameraFov?: number;
+        vignetteBlendMode?: number;
+        vignetteM?: boolean;
+        applyByPostProcess?: boolean;
+        isEnabled?: boolean;
+    }
+}
+declare module BabylonViewer {
+    export interface ILightConfiguration {
+        type: number;
+        name?: string;
+        disabled?: boolean;
+        position?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        target?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        direction?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        diffuse?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        specular?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        intensity?: number;
+        intensityMode?: number;
+        radius?: number;
+        shadownEnabled?: boolean;
+        shadowConfig?: {
+            useBlurExponentialShadowMap?: boolean;
+            useBlurCloseExponentialShadowMap?: boolean;
+            useKernelBlur?: boolean;
+            blurKernel?: number;
+            blurScale?: number;
+            minZ?: number;
+            maxZ?: number;
+            frustumSize?: number;
+            angleScale?: number;
+            frustumEdgeFalloff?: number;
+            [propName: string]: any;
+        };
+        spotAngle?: number;
+        shadowFieldOfView?: number;
+        shadowBufferSize?: number;
+        shadowFrustumSize?: number;
+        shadowMinZ?: number;
+        shadowMaxZ?: number;
+        [propName: string]: any;
+        behaviors?: {
+            [name: string]: number | {
+                type: number;
+                [propName: string]: any;
+            };
+        };
+    }
+}
+declare module BabylonViewer {
+    export interface IObserversConfiguration {
+        onEngineInit?: string;
+        onSceneInit?: string;
+        onModelLoaded?: string;
+    }
+}
+declare module BabylonViewer {
+    export interface ISceneConfiguration {
+            debug?: boolean;
+            clearColor?: {
+                    r: number;
+                    g: number;
+                    b: number;
+                    a: number;
+            };
+            /** Deprecated, use environmentMap.mainColor instead. */
+            mainColor?: {
+                    r?: number;
+                    g?: number;
+                    b?: number;
+            };
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            environmentTexture?: string;
+            colorGrading?: IColorGradingConfiguration;
+            environmentRotationY?: number;
+            /**
+                * Deprecated, please use default rendering pipeline
+                */
+            glow?: boolean | BABYLON.IGlowLayerOptions;
+            disableHdr?: boolean;
+            renderInBackground?: boolean;
+            disableCameraControl?: boolean;
+            animationPropertiesOverride?: {
+                    [propName: string]: any;
+            };
+            defaultMaterial?: {
+                    materialType: "standard" | "pbr";
+                    [propName: string]: any;
+            };
+            flags?: {
+                    shadowsEnabled?: boolean;
+                    particlesEnabled?: boolean;
+                    collisionsEnabled?: boolean;
+                    lightsEnabled?: boolean;
+                    texturesEnabled?: boolean;
+                    lensFlaresEnabled?: boolean;
+                    proceduralTexturesEnabled?: boolean;
+                    renderTargetsEnabled?: boolean;
+                    spritesEnabled?: boolean;
+                    skeletonsEnabled?: boolean;
+                    audioEnabled?: boolean;
+            };
+            assetsRootURL?: string;
+    }
+}
+declare module BabylonViewer {
+    export interface ISceneOptimizerConfiguration {
+        targetFrameRate?: number;
+        trackerDuration?: number;
+        autoGeneratePriorities?: boolean;
+        improvementMode?: boolean;
+        degradation?: string;
+        types?: {
+            texture?: ISceneOptimizerParameters;
+            hardwareScaling?: ISceneOptimizerParameters;
+            shadow?: ISceneOptimizerParameters;
+            postProcess?: ISceneOptimizerParameters;
+            lensFlare?: ISceneOptimizerParameters;
+            particles?: ISceneOptimizerParameters;
+            renderTarget?: ISceneOptimizerParameters;
+            mergeMeshes?: ISceneOptimizerParameters;
+        };
+        custom?: string;
+    }
+    export interface ISceneOptimizerParameters {
+        priority?: number;
+        maximumSize?: number;
+        step?: number;
+    }
+}
+declare module BabylonViewer {
+    export interface ISkyboxConfiguration {
+        cubeTexture?: {
+            noMipMap?: boolean;
+            gammaSpace?: boolean;
+            url?: string | Array<string>;
+        };
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        pbr?: boolean;
+        scale?: number;
+        blur?: number;
+        material?: {
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            [propName: string]: any;
+        };
+        infiniteDistance?: boolean;
+    }
+}
+declare module BabylonViewer {
+    /**
+        * A single template configuration object
+        */
+    export interface ITemplateConfiguration {
+            /**
+                * can be either the id of the template's html element or a URL.
+                * See - http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
+                */
+            location?: string;
+            /**
+                * If no location is provided you can provide here the raw html of this template.
+                * See http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
+                */
+            html?: string;
+            id?: string;
+            /**
+                * Parameters that will be delivered to the template and will render it accordingly.
+                */
+            params?: {
+                    [key: string]: string | number | boolean | object;
+            };
+            /**
+                * Events to attach to this template.
+                * event name is the key. the value can either be a boolean (attach to the parent element)
+                * or a map of html id elements.
+                *
+                * See - http://doc.babylonjs.com/extensions/the_templating_system#event-binding
+                */
+            events?: {
+                    pointerdown?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerup?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointermove?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerover?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerout?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerenter?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerleave?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointercancel?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    click?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    dragstart?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    drop?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    [key: string]: boolean | {
+                            [id: string]: boolean;
+                    } | undefined;
+            };
+    }
+}
+declare module BabylonViewer {
+    export interface IVRConfiguration {
+        disabled?: boolean;
+        objectScaleFactor?: number;
+        disableInteractions?: boolean;
+        disableTeleportation?: boolean;
+        overrideFloorMeshName?: string;
+        vrOptions?: BABYLON.VRExperienceHelperOptions;
+        modelHeightCorrection?: number | boolean;
+        rotateUsingControllers?: boolean;
+        cameraPosition?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+    }
+}
+declare module BabylonViewer {
     /**
         * Spherical polynomial coefficients (counter part to spherical harmonic coefficients used in shader irradiance calculation)
         * @ignoreChildren

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 493 - 204
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -732,209 +732,7 @@ declare module 'babylonjs-viewer/model/viewerModel' {
 }
 
 declare module 'babylonjs-viewer/model/modelAnimation' {
-    import { AnimationGroup, Vector3 } from 'babylonjs';
-    /**
-        * Animation play mode enum - is the animation looping or playing once
-        */
-    export const enum AnimationPlayMode {
-            ONCE = 0,
-            LOOP = 1
-    }
-    /**
-        * An enum representing the current state of an animation object
-        */
-    export const enum AnimationState {
-            INIT = 0,
-            PLAYING = 1,
-            PAUSED = 2,
-            STOPPED = 3,
-            ENDED = 4
-    }
-    /**
-        * The different type of easing functions available
-        */
-    export const enum EasingFunction {
-            Linear = 0,
-            CircleEase = 1,
-            BackEase = 2,
-            BounceEase = 3,
-            CubicEase = 4,
-            ElasticEase = 5,
-            ExponentialEase = 6,
-            PowerEase = 7,
-            QuadraticEase = 8,
-            QuarticEase = 9,
-            QuinticEase = 10,
-            SineEase = 11
-    }
-    /**
-        * Defines a simple animation to be applied to a model (scale).
-        */
-    export interface ModelAnimationConfiguration {
-            /**
-                * Time of animation, in seconds
-                */
-            time: number;
-            /**
-                * Scale to apply
-                */
-            scaling?: Vector3;
-            /**
-                * Easing function to apply
-                * See SPECTRE.EasingFunction
-                */
-            easingFunction?: number;
-            /**
-                * An Easing mode to apply to the easing function
-                * See BABYLON.EasingFunction
-                */
-            easingMode?: number;
-    }
-    /**
-        * This interface can be implemented to define new types of ModelAnimation objects.
-        */
-    export interface IModelAnimation {
-            /**
-                * Current animation state (playing, stopped etc')
-                */
-            readonly state: AnimationState;
-            /**
-                * the name of the animation
-                */
-            readonly name: string;
-            /**
-                * Get the max numbers of frame available in the animation group
-                *
-                * In correlation to an arry, this would be ".length"
-                */
-            readonly frames: number;
-            /**
-                * Get the current frame playing right now.
-                * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
-                *
-                * In correlation to an array, this would be the current index
-                */
-            readonly currentFrame: number;
-            /**
-                * Animation's FPS value
-                */
-            readonly fps: number;
-            /**
-                * Get or set the animation's speed ration (Frame-to-fps)
-                */
-            speedRatio: number;
-            /**
-                * Gets or sets the aimation's play mode.
-                */
-            playMode: AnimationPlayMode;
-            /**
-                * Start the animation
-                */
-            start(): any;
-            /**
-                * Stop the animation.
-                * This will fail silently if the animation group is already stopped.
-                */
-            stop(): any;
-            /**
-                * Pause the animation
-                * This will fail silently if the animation is not currently playing
-                */
-            pause(): any;
-            /**
-                * Reset this animation
-                */
-            reset(): any;
-            /**
-                * Restart the animation
-                */
-            restart(): any;
-            /**
-                * Go to a specific
-                * @param frameNumber the frame number to go to
-                */
-            goToFrame(frameNumber: number): any;
-            /**
-                * Dispose this animation
-                */
-            dispose(): any;
-    }
-    /**
-        * The GroupModelAnimation is an implementation of the IModelAnimation interface using BABYLON's
-        * native GroupAnimation class.
-        */
-    export class GroupModelAnimation implements IModelAnimation {
-            /**
-                * Create a new GroupModelAnimation object using an AnimationGroup object
-                * @param _animationGroup The aniamtion group to base the class on
-                */
-            constructor(_animationGroup: AnimationGroup);
-            /**
-                * Get the animation's name
-                */
-            readonly name: string;
-            /**
-                * Get the current animation's state
-                */
-            readonly state: AnimationState;
-            /**
-             * Sets the speed ratio to use for all animations
-             */
-            speedRatio: number;
-            /**
-                * Get the max numbers of frame available in the animation group
-                *
-                * In correlation to an arry, this would be ".length"
-                */
-            readonly frames: number;
-            /**
-                * Get the current frame playing right now.
-                * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
-                *
-                * In correlation to an array, this would be the current index
-                */
-            readonly currentFrame: number;
-            /**
-                * Get the FPS value of this animation
-                */
-            readonly fps: number;
-            /**
-             * Set the play mode.
-             * If the animation is played, it will continue playing at least once more, depending on the new play mode set.
-             * If the animation is not set, the will be initialized and will wait for the user to start playing it.
-             */
-            playMode: AnimationPlayMode;
-            /**
-                * Reset the animation group
-                */
-            reset(): void;
-            /**
-                * Restart the animation group
-                */
-            restart(): void;
-            /**
-                *
-                * @param frameNumber Go to a specific frame in the animation
-                */
-            goToFrame(frameNumber: number): void;
-            /**
-                * Start playing the animation.
-                */
-            start(): void;
-            /**
-                * Pause the animation
-                */
-            pause(): void;
-            /**
-                * Stop the animation.
-                * This will fail silently if the animation group is already stopped.
-                */
-            stop(): void;
-            /**
-                * Dispose this animation object.
-                */
-            dispose(): void;
-    }
+    
 }
 
 declare module 'babylonjs-viewer/loader/plugins/loaderPlugin' {
@@ -1663,7 +1461,21 @@ declare module 'babylonjs-viewer/loader/plugins' {
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces' {
-    
+    export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/defaultRenderingPipelineConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/groundConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/lightConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/modelAnimationConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/modelConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/observersConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/sceneConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/sceneOptimizerConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/templateConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/vrConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration';
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration' {
@@ -1857,6 +1669,483 @@ declare module 'babylonjs-viewer/loader/plugins/extendedMaterialLoaderPlugin' {
     }
 }
 
+declare module 'babylonjs-viewer/configuration/interfaces/cameraConfiguration' {
+    export interface ICameraConfiguration {
+        position?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        rotation?: {
+            x: number;
+            y: number;
+            z: number;
+            w: number;
+        };
+        fov?: number;
+        fovMode?: number;
+        minZ?: number;
+        maxZ?: number;
+        inertia?: number;
+        exposure?: number;
+        pinchPrecision?: number;
+        behaviors?: {
+            [name: string]: boolean | number | ICameraBehaviorConfiguration;
+        };
+        disableCameraControl?: boolean;
+        disableCtrlForPanning?: boolean;
+        disableAutoFocus?: boolean;
+        [propName: string]: any;
+    }
+    export interface ICameraBehaviorConfiguration {
+        type: number;
+        [propName: string]: any;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration' {
+    /**
+        * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
+        */
+    export interface IColorGradingConfiguration {
+            /**
+                * Transform data string, encoded as determined by transformDataFormat.
+                */
+            transformData: string;
+            /**
+                * The encoding format of TransformData (currently only raw-base16 is supported).
+                */
+            transformDataFormat: string;
+            /**
+                * The weight of the transform
+                */
+            transformWeight: number;
+            /**
+                * Color curve colorFilterHueGlobal value
+                */
+            colorFilterHueGlobal: number;
+            /**
+                * Color curve colorFilterHueShadows value
+                */
+            colorFilterHueShadows: number;
+            /**
+                * Color curve colorFilterHueMidtones value
+                */
+            colorFilterHueMidtones: number;
+            /**
+                * Color curve colorFilterHueHighlights value
+                */
+            colorFilterHueHighlights: number;
+            /**
+                * Color curve colorFilterDensityGlobal value
+                */
+            colorFilterDensityGlobal: number;
+            /**
+                * Color curve colorFilterDensityShadows value
+                */
+            colorFilterDensityShadows: number;
+            /**
+                * Color curve colorFilterDensityMidtones value
+                */
+            colorFilterDensityMidtones: number;
+            /**
+                * Color curve colorFilterDensityHighlights value
+                */
+            colorFilterDensityHighlights: number;
+            /**
+                * Color curve saturationGlobal value
+                */
+            saturationGlobal: number;
+            /**
+                * Color curve saturationShadows value
+                */
+            saturationShadows: number;
+            /**
+                * Color curve saturationMidtones value
+                */
+            saturationMidtones: number;
+            /**
+                * Color curve saturationHighlights value
+                */
+            saturationHighlights: number;
+            /**
+                * Color curve exposureGlobal value
+                */
+            exposureGlobal: number;
+            /**
+                * Color curve exposureShadows value
+                */
+            exposureShadows: number;
+            /**
+                * Color curve exposureMidtones value
+                */
+            exposureMidtones: number;
+            /**
+                * Color curve exposureHighlights value
+                */
+            exposureHighlights: number;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/defaultRenderingPipelineConfiguration' {
+    import { DepthOfFieldEffectBlurLevel } from 'babylonjs';
+    export interface IDefaultRenderingPipelineConfiguration {
+        sharpenEnabled?: boolean;
+        bloomEnabled?: boolean;
+        bloomThreshold?: number;
+        depthOfFieldEnabled?: boolean;
+        depthOfFieldBlurLevel?: DepthOfFieldEffectBlurLevel;
+        fxaaEnabled?: boolean;
+        imageProcessingEnabled?: boolean;
+        defaultPipelineTextureType?: number;
+        bloomScale?: number;
+        chromaticAberrationEnabled?: boolean;
+        grainEnabled?: boolean;
+        bloomKernel?: number;
+        hardwareScaleLevel?: number;
+        bloomWeight?: number;
+        hdr?: boolean;
+        samples?: number;
+        glowLayerEnabled?: boolean;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/groundConfiguration' {
+    export interface IGroundConfiguration {
+        size?: number;
+        receiveShadows?: boolean;
+        shadowLevel?: number;
+        shadowOnly?: boolean;
+        mirror?: boolean | {
+            sizeRatio?: number;
+            blurKernel?: number;
+            amount?: number;
+            fresnelWeight?: number;
+            fallOffDistance?: number;
+            textureType?: number;
+        };
+        texture?: string;
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        opacity?: number;
+        material?: {
+            [propName: string]: any;
+        };
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration' {
+    export interface IImageProcessingConfiguration {
+        colorGradingEnabled?: boolean;
+        colorCurvesEnabled?: boolean;
+        colorCurves?: {
+            globalHue?: number;
+            globalDensity?: number;
+            globalSaturation?: number;
+            globalExposure?: number;
+            highlightsHue?: number;
+            highlightsDensity?: number;
+            highlightsSaturation?: number;
+            highlightsExposure?: number;
+            midtonesHue?: number;
+            midtonesDensity?: number;
+            midtonesSaturation?: number;
+            midtonesExposure?: number;
+            shadowsHue?: number;
+            shadowsDensity?: number;
+            shadowsSaturation?: number;
+            shadowsExposure?: number;
+        };
+        colorGradingWithGreenDepth?: boolean;
+        colorGradingBGR?: boolean;
+        exposure?: number;
+        toneMappingEnabled?: boolean;
+        contrast?: number;
+        vignetteEnabled?: boolean;
+        vignetteStretch?: number;
+        vignetteCentreX?: number;
+        vignetteCentreY?: number;
+        vignetteWeight?: number;
+        vignetteColor?: {
+            r: number;
+            g: number;
+            b: number;
+            a?: number;
+        };
+        vignetteCameraFov?: number;
+        vignetteBlendMode?: number;
+        vignetteM?: boolean;
+        applyByPostProcess?: boolean;
+        isEnabled?: boolean;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/lightConfiguration' {
+    export interface ILightConfiguration {
+        type: number;
+        name?: string;
+        disabled?: boolean;
+        position?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        target?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        direction?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        diffuse?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        specular?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        intensity?: number;
+        intensityMode?: number;
+        radius?: number;
+        shadownEnabled?: boolean;
+        shadowConfig?: {
+            useBlurExponentialShadowMap?: boolean;
+            useBlurCloseExponentialShadowMap?: boolean;
+            useKernelBlur?: boolean;
+            blurKernel?: number;
+            blurScale?: number;
+            minZ?: number;
+            maxZ?: number;
+            frustumSize?: number;
+            angleScale?: number;
+            frustumEdgeFalloff?: number;
+            [propName: string]: any;
+        };
+        spotAngle?: number;
+        shadowFieldOfView?: number;
+        shadowBufferSize?: number;
+        shadowFrustumSize?: number;
+        shadowMinZ?: number;
+        shadowMaxZ?: number;
+        [propName: string]: any;
+        behaviors?: {
+            [name: string]: number | {
+                type: number;
+                [propName: string]: any;
+            };
+        };
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/observersConfiguration' {
+    export interface IObserversConfiguration {
+        onEngineInit?: string;
+        onSceneInit?: string;
+        onModelLoaded?: string;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/sceneConfiguration' {
+    import { IImageProcessingConfiguration } from "babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration";
+    import { IColorGradingConfiguration } from "babylonjs-viewer/configuration/interfaces/colorGradingConfiguration";
+    import { IGlowLayerOptions } from "babylonjs";
+    export interface ISceneConfiguration {
+            debug?: boolean;
+            clearColor?: {
+                    r: number;
+                    g: number;
+                    b: number;
+                    a: number;
+            };
+            /** Deprecated, use environmentMap.mainColor instead. */
+            mainColor?: {
+                    r?: number;
+                    g?: number;
+                    b?: number;
+            };
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            environmentTexture?: string;
+            colorGrading?: IColorGradingConfiguration;
+            environmentRotationY?: number;
+            /**
+                * Deprecated, please use default rendering pipeline
+                */
+            glow?: boolean | IGlowLayerOptions;
+            disableHdr?: boolean;
+            renderInBackground?: boolean;
+            disableCameraControl?: boolean;
+            animationPropertiesOverride?: {
+                    [propName: string]: any;
+            };
+            defaultMaterial?: {
+                    materialType: "standard" | "pbr";
+                    [propName: string]: any;
+            };
+            flags?: {
+                    shadowsEnabled?: boolean;
+                    particlesEnabled?: boolean;
+                    collisionsEnabled?: boolean;
+                    lightsEnabled?: boolean;
+                    texturesEnabled?: boolean;
+                    lensFlaresEnabled?: boolean;
+                    proceduralTexturesEnabled?: boolean;
+                    renderTargetsEnabled?: boolean;
+                    spritesEnabled?: boolean;
+                    skeletonsEnabled?: boolean;
+                    audioEnabled?: boolean;
+            };
+            assetsRootURL?: string;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/sceneOptimizerConfiguration' {
+    export interface ISceneOptimizerConfiguration {
+        targetFrameRate?: number;
+        trackerDuration?: number;
+        autoGeneratePriorities?: boolean;
+        improvementMode?: boolean;
+        degradation?: string;
+        types?: {
+            texture?: ISceneOptimizerParameters;
+            hardwareScaling?: ISceneOptimizerParameters;
+            shadow?: ISceneOptimizerParameters;
+            postProcess?: ISceneOptimizerParameters;
+            lensFlare?: ISceneOptimizerParameters;
+            particles?: ISceneOptimizerParameters;
+            renderTarget?: ISceneOptimizerParameters;
+            mergeMeshes?: ISceneOptimizerParameters;
+        };
+        custom?: string;
+    }
+    export interface ISceneOptimizerParameters {
+        priority?: number;
+        maximumSize?: number;
+        step?: number;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration' {
+    import { IImageProcessingConfiguration } from "babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration";
+    export interface ISkyboxConfiguration {
+        cubeTexture?: {
+            noMipMap?: boolean;
+            gammaSpace?: boolean;
+            url?: string | Array<string>;
+        };
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        pbr?: boolean;
+        scale?: number;
+        blur?: number;
+        material?: {
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            [propName: string]: any;
+        };
+        infiniteDistance?: boolean;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/templateConfiguration' {
+    /**
+        * A single template configuration object
+        */
+    export interface ITemplateConfiguration {
+            /**
+                * can be either the id of the template's html element or a URL.
+                * See - http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
+                */
+            location?: string;
+            /**
+                * If no location is provided you can provide here the raw html of this template.
+                * See http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
+                */
+            html?: string;
+            id?: string;
+            /**
+                * Parameters that will be delivered to the template and will render it accordingly.
+                */
+            params?: {
+                    [key: string]: string | number | boolean | object;
+            };
+            /**
+                * Events to attach to this template.
+                * event name is the key. the value can either be a boolean (attach to the parent element)
+                * or a map of html id elements.
+                *
+                * See - http://doc.babylonjs.com/extensions/the_templating_system#event-binding
+                */
+            events?: {
+                    pointerdown?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerup?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointermove?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerover?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerout?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerenter?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerleave?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointercancel?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    click?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    dragstart?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    drop?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    [key: string]: boolean | {
+                            [id: string]: boolean;
+                    } | undefined;
+            };
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/vrConfiguration' {
+    import { VRExperienceHelperOptions } from "babylonjs";
+    export interface IVRConfiguration {
+        disabled?: boolean;
+        objectScaleFactor?: number;
+        disableInteractions?: boolean;
+        disableTeleportation?: boolean;
+        overrideFloorMeshName?: string;
+        vrOptions?: VRExperienceHelperOptions;
+        modelHeightCorrection?: number | boolean;
+        rotateUsingControllers?: boolean;
+        cameraPosition?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+    }
+}
+
 declare module 'babylonjs-viewer/labs/environmentSerializer' {
     import { Vector3 } from "babylonjs";
     import { TextureCube } from 'babylonjs-viewer/labs/texture';

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

@@ -5,6 +5,8 @@
 - Added support for [parallel shader compilation](https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/) ([Deltakosh](https://github.com/deltakosh))
 - Added FlyCamera for free navigation in 3D space, with a limited set of settings ([Phuein](https://github.com/phuein))
 - Added Object Based Motion Blur post-process ([julien-moreau](https://github.com/julien-moreau))
+- WebXR ([TrevorDev](https://github.com/TrevorDev))
+  - Add customAnimationFrameRequester to allow sessions to hook into engine's render loop ([TrevorDev](https://github.com/TrevorDev))
 
 ## Updates
 
@@ -20,7 +22,7 @@
   - prevent avoidable matrix inversion or square root computation.
   - enable a removal in O(1) from the `transformNodes` array and `materials` array of the `Scene`. As a consequence, the order of the element within these arrays might change during a removal.
   - enable a removal in O(1) from the `instances` array of a `Mesh`. As a consequence, the order of the element within this array might change during a removal.
-  - Stop calling splice on the `scene.meshes` array and on the `engine._uniformBuffer` when removing an element. As a consequence, the order of the element within these array might change during a removal.
+  - Stop calling `Array.splice` on the `scene.meshes` array and on the `engine._uniformBuffer` when removing an element. As a consequence, the order of the element within these arrays might change during a removal.
   - Added an option `useMaterialMeshMap` in the `Scene` constructor options. When set to true, each `Material` isntance will have and will keep up-to-date a map of its bound meshes. This is to avoid browsing all the meshes of the scene to retrieve the ones bound to the current material when disposing the Material. Disabled by default.
   - Added an option `useClonedMeshhMap` in the `Scene` constructor options. When set to true, each `Mesh` will have and will keep up-to-date a map of cloned meshes. This is to avoid browsing all the meshes of the scene to retrieve the ones that have the current mesh as source mesh. Disabled by default.
   - Added `blockfreeActiveMeshesAndRenderingGroups` property in the `Scene`, following the same model as `blockMaterialDirtyMechanism`. This is to avoid calling `Scene.freeActiveMeshes` and `Scene.freeRenderingGroups` for each disposed mesh when we dispose several meshes in a row. One have to set `blockfreeActiveMeshesAndRenderingGroups` to `true` just before disposing the meshes, and set it back to `false` just after.
@@ -37,7 +39,9 @@
 ## Bug fixes
 
 ### Core Engine
-
+- Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))
+- Fixed a bug with pointer up being fire twice ([Deltakosh](https://github.com/deltakosh))
+- Fixed a bug with particle systems being update once per camera instead of once per frame ([Deltakosh](https://github.com/deltakosh))
 
 
 ### Viewer

+ 12 - 4
src/Engine/babylon.engine.ts

@@ -625,6 +625,11 @@ module BABYLON {
         public onBeginFrameObservable = new Observable<Engine>();
 
         /**
+         * If set, will be used to request the next animation frame for the render loop
+         */
+        public customAnimationFrameRequester: Nullable<ICustomAnimationFrameRequester> = null;
+
+        /**
          * Observable raised when the engine ends the current frame
          */
         public onEndFrameObservable = new Observable<Engine>();
@@ -1894,11 +1899,14 @@ module BABYLON {
 
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
-                var requester = null;
-                if (this._vrDisplay && this._vrDisplay.isPresenting) {
-                    requester = this._vrDisplay;
+                if (this.customAnimationFrameRequester) {
+                    this.customAnimationFrameRequester.requestID = Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
+                    this._frameHandler = this.customAnimationFrameRequester.requestID;
+                } else if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                    this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+                } else {
+                    this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
                 }
-                this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, requester);
             } else {
                 this._renderingQueueLaunched = false;
             }

+ 7 - 6
src/Materials/babylon.material.ts

@@ -467,7 +467,7 @@ module BABYLON {
          * Gets a boolean indicating that current material needs to register RTT
          */
         public get hasRenderTargetTextures(): boolean {
-          return false;
+            return false;
         }
 
         /**
@@ -476,9 +476,9 @@ module BABYLON {
         public doNotSerialize = false;
 
         /**
-         * Specifies if the effect should be stored on sub meshes
+         * @hidden
          */
-        public storeEffectOnSubMeshes = false;
+        public _storeEffectOnSubMeshes = false;
 
         /**
          * Stores the animations for the material
@@ -1112,7 +1112,7 @@ module BABYLON {
                     scene.clipPlane = new Plane(0, 0, 0, 1);
                 }
 
-                if (this.storeEffectOnSubMeshes) {
+                if (this._storeEffectOnSubMeshes) {
                     if (this.isReadyForSubMesh(mesh, subMesh)) {
                         if (onCompiled) {
                             onCompiled(this);
@@ -1271,6 +1271,7 @@ module BABYLON {
          * Disposes the material
          * @param forceDisposeEffect specifies if effects should be forcefully disposed
          * @param forceDisposeTextures specifies if textures should be forcefully disposed
+         * @param isLineMeshColorShader specifies if the material that is being disposed is the ShaderMaterial of a LinesMesh
          */
         public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, isLineMeshColorShader?: boolean): void {
             const scene = this.getScene();
@@ -1307,7 +1308,7 @@ module BABYLON {
 
             // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
             if (forceDisposeEffect && this._effect) {
-                if (!this.storeEffectOnSubMeshes) {
+                if (!this._storeEffectOnSubMeshes) {
                     scene.getEngine()._releaseEffect(this._effect);
                 }
 
@@ -1332,7 +1333,7 @@ module BABYLON {
             if ((<Mesh>mesh).geometry) {
                 var geometry = <Geometry>((<Mesh>mesh).geometry);
                 const scene = this.getScene();
-                if (this.storeEffectOnSubMeshes) {
+                if (this._storeEffectOnSubMeshes) {
                     for (var subMesh of mesh.subMeshes) {
                         geometry._releaseVertexArrayObject(subMesh._materialEffect);
                         if (forceDisposeEffect && subMesh._materialEffect) {

+ 2 - 2
src/Materials/babylon.multiMaterial.ts

@@ -35,7 +35,7 @@ module BABYLON {
 
             this.subMaterials = new Array<Material>();
 
-            this.storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
+            this._storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
         }
 
         private _hookArray(array: Nullable<Material>[]): void {
@@ -105,7 +105,7 @@ module BABYLON {
             for (var index = 0; index < this.subMaterials.length; index++) {
                 var subMaterial = this.subMaterials[index];
                 if (subMaterial) {
-                    if (subMaterial.storeEffectOnSubMeshes) {
+                    if (subMaterial._storeEffectOnSubMeshes) {
                         if (!subMaterial.isReadyForSubMesh(mesh, subMesh, useInstances)) {
                             return false;
                         }

+ 1 - 1
src/Materials/babylon.pushMaterial.ts

@@ -18,7 +18,7 @@ module BABYLON {
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
-            this.storeEffectOnSubMeshes = true;
+            this._storeEffectOnSubMeshes = true;
         }
 
         public getEffect(): Effect {

+ 1 - 0
src/Materials/babylon.shaderMaterial.ts

@@ -656,6 +656,7 @@ module BABYLON {
          * Disposes the material
          * @param forceDisposeEffect specifies if effects should be forcefully disposed
          * @param forceDisposeTextures specifies if textures should be forcefully disposed
+         * @param isLineMeshColorShader specifies if the material that is being disposed is the ShaderMaterial of a LinesMesh
          */
         public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, isLineMeshColorShader?: boolean): void {
 

+ 5 - 5
src/Mesh/babylon.mesh.ts

@@ -769,11 +769,11 @@ module BABYLON {
 
             let mat = this.material || scene.defaultMaterial;
             if (mat) {
-                if (mat.storeEffectOnSubMeshes) {
+                if (mat._storeEffectOnSubMeshes) {
                     for (var subMesh of this.subMeshes) {
                         let effectiveMaterial = subMesh.getMaterial();
                         if (effectiveMaterial) {
-                            if (effectiveMaterial.storeEffectOnSubMeshes) {
+                            if (effectiveMaterial._storeEffectOnSubMeshes) {
                                 if (!effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                                     return false;
                                 }
@@ -1543,7 +1543,7 @@ module BABYLON {
 
             this._effectiveMaterial = material;
 
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                     return this;
                 }
@@ -1561,7 +1561,7 @@ module BABYLON {
             }
 
             var effect: Nullable<Effect>;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 effect = subMesh.effect;
             } else {
                 effect = this._effectiveMaterial.getEffect();
@@ -1594,7 +1594,7 @@ module BABYLON {
 
             var world = this.getWorldMatrix();
 
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             } else {
                 this._effectiveMaterial.bind(world, this);

+ 19 - 20
src/Particles/babylon.gpuParticleSystem.ts

@@ -591,9 +591,9 @@ module BABYLON {
          * @param isAnimationSheetEnabled Must be true if using a spritesheet to animate the particles texture
          */
         constructor(name: string, options: Partial<{
-                        capacity: number,
-                        randomTextureSize: number
-                    }>, scene: Scene, isAnimationSheetEnabled: boolean = false) {
+            capacity: number,
+            randomTextureSize: number
+        }>, scene: Scene, isAnimationSheetEnabled: boolean = false) {
             super(name);
             this._scene = scene || Engine.LastCreatedScene;
             // Setup the default processing configuration to the scene.
@@ -626,8 +626,8 @@ module BABYLON {
             this._updateEffectOptions = {
                 attributes: ["position", "age", "life", "seed", "size", "color", "direction", "initialDirection", "angle", "cellIndex", "cellStartOffset", "noiseCoordinates1", "noiseCoordinates2"],
                 uniformsNames: ["currentCount", "timeDelta", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "scaleRange", "gravity", "emitPower",
-                                "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "coneAngle", "stopFactor",
-                                "angleRange", "radiusRange", "cellInfos", "noiseStrength", "limitVelocityDamping"],
+                    "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "coneAngle", "stopFactor",
+                    "angleRange", "radiusRange", "cellInfos", "noiseStrength", "limitVelocityDamping"],
                 uniformBuffersNames: [],
                 samplers: ["randomSampler", "randomSampler2", "sizeGradientSampler", "angularSpeedGradientSampler", "velocityGradientSampler", "limitVelocityGradientSampler", "noiseSampler", "dragGradientSampler"],
                 defines: "",
@@ -673,7 +673,7 @@ module BABYLON {
         }
 
         private _createUpdateVAO(source: Buffer): WebGLVertexArrayObject {
-            let updateVertexBuffers: {[key: string]: VertexBuffer} = {};
+            let updateVertexBuffers: { [key: string]: VertexBuffer } = {};
             updateVertexBuffers["position"] = source.createVertexBuffer("position", 0, 3);
             updateVertexBuffers["age"] = source.createVertexBuffer("age", 3, 1);
             updateVertexBuffers["life"] = source.createVertexBuffer("life", 4, 1);
@@ -725,7 +725,7 @@ module BABYLON {
         }
 
         private _createRenderVAO(source: Buffer, spriteSource: Buffer): WebGLVertexArrayObject {
-            let renderVertexBuffers: {[key: string]: VertexBuffer} = {};
+            let renderVertexBuffers: { [key: string]: VertexBuffer } = {};
             renderVertexBuffers["position"] = source.createVertexBuffer("position", 0, 3, this._attributesStrideSize, true);
             renderVertexBuffers["age"] = source.createVertexBuffer("age", 3, 1, this._attributesStrideSize, true);
             renderVertexBuffers["life"] = source.createVertexBuffer("life", 4, 1, this._attributesStrideSize, true);
@@ -877,10 +877,10 @@ module BABYLON {
             }
 
             // Sprite data
-            var spriteData = new Float32Array([0.5, 0.5,  1, 1,
-                                              -0.5, 0.5,  0, 1,
-                                             -0.5, -0.5,  0, 0,
-                                             0.5, -0.5,  1, 0]);
+            var spriteData = new Float32Array([0.5, 0.5, 1, 1,
+                -0.5, 0.5, 0, 1,
+                -0.5, -0.5, 0, 0,
+                0.5, -0.5, 1, 0]);
 
             // Buffers
             this._buffer0 = new Buffer(engine, data, false, this._attributesStrideSize);
@@ -1042,9 +1042,9 @@ module BABYLON {
             }
 
             this._renderEffect = new Effect("gpuRenderParticles",
-                                            ["position", "age", "life", "size", "color", "offset", "uv", "direction", "initialDirection", "angle", "cellIndex"],
-                                            uniforms,
-                                            samplers, this._scene.getEngine(), defines);
+                ["position", "age", "life", "size", "color", "offset", "uv", "direction", "initialDirection", "angle", "cellIndex"],
+                uniforms,
+                samplers, this._scene.getEngine(), defines);
         }
 
         /**
@@ -1161,11 +1161,11 @@ module BABYLON {
                     this._preWarmDone = true;
                 }
 
-                if (this._currentRenderId === this._scene.getRenderId()) {
+                if (this._currentRenderId === this._scene.getFrameId()) {
                     return 0;
                 }
 
-                this._currentRenderId = this._scene.getRenderId();
+                this._currentRenderId = this._scene.getFrameId();
             }
 
             // Get everything ready to render
@@ -1294,8 +1294,7 @@ module BABYLON {
                 }
 
                 // Draw order
-                switch (this.blendMode)
-                {
+                switch (this.blendMode) {
                     case ParticleSystem.BLENDMODE_ADD:
                         this._engine.setAlphaMode(Engine.ALPHA_ADD);
                         break;
@@ -1447,7 +1446,7 @@ module BABYLON {
          * @returns the cloned particle system
          */
         public clone(name: string, newEmitter: any): GPUParticleSystem {
-            var result = new GPUParticleSystem(name, {capacity: this._capacity, randomTextureSize: this._randomTextureSize}, this._scene);
+            var result = new GPUParticleSystem(name, { capacity: this._capacity, randomTextureSize: this._randomTextureSize }, this._scene);
 
             Tools.DeepCopy(this, result);
 
@@ -1486,7 +1485,7 @@ module BABYLON {
          */
         public static Parse(parsedParticleSystem: any, scene: Scene, rootUrl: string, doNotStart = false): GPUParticleSystem {
             var name = parsedParticleSystem.name;
-            var particleSystem = new GPUParticleSystem(name, {capacity: parsedParticleSystem.capacity, randomTextureSize: parsedParticleSystem.randomTextureSize}, scene);
+            var particleSystem = new GPUParticleSystem(name, { capacity: parsedParticleSystem.capacity, randomTextureSize: parsedParticleSystem.randomTextureSize }, scene);
 
             if (parsedParticleSystem.activeParticleCount) {
                 particleSystem.activeParticleCount = parsedParticleSystem.activeParticleCount;

+ 149 - 149
src/Particles/babylon.particleSystem.ts

@@ -206,181 +206,181 @@ module BABYLON {
                 for (var index = 0; index < particles.length; index++) {
                     var particle = particles[index];
 
-                        let scaledUpdateSpeed = this._scaledUpdateSpeed;
-                        let previousAge = particle.age;
-                        particle.age += scaledUpdateSpeed;
+                    let scaledUpdateSpeed = this._scaledUpdateSpeed;
+                    let previousAge = particle.age;
+                    particle.age += scaledUpdateSpeed;
 
-                        // Evaluate step to death
-                        if (particle.age > particle.lifeTime) {
-                            let diff = particle.age - previousAge;
-                            let oldDiff = particle.lifeTime - previousAge;
+                    // Evaluate step to death
+                    if (particle.age > particle.lifeTime) {
+                        let diff = particle.age - previousAge;
+                        let oldDiff = particle.lifeTime - previousAge;
 
-                            scaledUpdateSpeed = (oldDiff * scaledUpdateSpeed) / diff;
+                        scaledUpdateSpeed = (oldDiff * scaledUpdateSpeed) / diff;
 
-                            particle.age = particle.lifeTime;
-                        }
+                        particle.age = particle.lifeTime;
+                    }
 
-                        let ratio = particle.age / particle.lifeTime;
-
-                        // Color
-                        if (this._colorGradients && this._colorGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentColorGradient) {
-                                    particle._currentColor1.copyFrom(particle._currentColor2);
-                                    (<ColorGradient>nextGradient).getColorToRef(particle._currentColor2);
-                                    particle._currentColorGradient = (<ColorGradient>currentGradient);
-                                }
-                                Color4.LerpToRef(particle._currentColor1, particle._currentColor2, scale, particle.color);
-                            });
-                        }
-                        else {
-                            particle.colorStep.scaleToRef(scaledUpdateSpeed, this._scaledColorStep);
-                            particle.color.addInPlace(this._scaledColorStep);
+                    let ratio = particle.age / particle.lifeTime;
 
-                            if (particle.color.a < 0) {
-                                particle.color.a = 0;
+                    // Color
+                    if (this._colorGradients && this._colorGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentColorGradient) {
+                                particle._currentColor1.copyFrom(particle._currentColor2);
+                                (<ColorGradient>nextGradient).getColorToRef(particle._currentColor2);
+                                particle._currentColorGradient = (<ColorGradient>currentGradient);
                             }
-                        }
+                            Color4.LerpToRef(particle._currentColor1, particle._currentColor2, scale, particle.color);
+                        });
+                    }
+                    else {
+                        particle.colorStep.scaleToRef(scaledUpdateSpeed, this._scaledColorStep);
+                        particle.color.addInPlace(this._scaledColorStep);
 
-                        // Angular speed
-                        if (this._angularSpeedGradients && this._angularSpeedGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._angularSpeedGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentAngularSpeedGradient) {
-                                    particle._currentAngularSpeed1 = particle._currentAngularSpeed2;
-                                    particle._currentAngularSpeed2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentAngularSpeedGradient = (<FactorGradient>currentGradient);
-                                }
-                                particle.angularSpeed = Scalar.Lerp(particle._currentAngularSpeed1, particle._currentAngularSpeed2, scale);
-                            });
-                        }
-                        particle.angle += particle.angularSpeed * scaledUpdateSpeed;
-
-                        // Direction
-                        let directionScale = scaledUpdateSpeed;
-
-                        /// Velocity
-                        if (this._velocityGradients && this._velocityGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._velocityGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentVelocityGradient) {
-                                    particle._currentVelocity1 = particle._currentVelocity2;
-                                    particle._currentVelocity2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentVelocityGradient = (<FactorGradient>currentGradient);
-                                }
-                                directionScale *= Scalar.Lerp(particle._currentVelocity1, particle._currentVelocity2, scale);
-                            });
+                        if (particle.color.a < 0) {
+                            particle.color.a = 0;
                         }
+                    }
 
-                        particle.direction.scaleToRef(directionScale, this._scaledDirection);
-
-                        /// Limit velocity
-                        if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._limitVelocityGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentLimitVelocityGradient) {
-                                    particle._currentLimitVelocity1 = particle._currentLimitVelocity2;
-                                    particle._currentLimitVelocity2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentLimitVelocityGradient = (<FactorGradient>currentGradient);
-                                }
+                    // Angular speed
+                    if (this._angularSpeedGradients && this._angularSpeedGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._angularSpeedGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentAngularSpeedGradient) {
+                                particle._currentAngularSpeed1 = particle._currentAngularSpeed2;
+                                particle._currentAngularSpeed2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentAngularSpeedGradient = (<FactorGradient>currentGradient);
+                            }
+                            particle.angularSpeed = Scalar.Lerp(particle._currentAngularSpeed1, particle._currentAngularSpeed2, scale);
+                        });
+                    }
+                    particle.angle += particle.angularSpeed * scaledUpdateSpeed;
+
+                    // Direction
+                    let directionScale = scaledUpdateSpeed;
+
+                    /// Velocity
+                    if (this._velocityGradients && this._velocityGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._velocityGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentVelocityGradient) {
+                                particle._currentVelocity1 = particle._currentVelocity2;
+                                particle._currentVelocity2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentVelocityGradient = (<FactorGradient>currentGradient);
+                            }
+                            directionScale *= Scalar.Lerp(particle._currentVelocity1, particle._currentVelocity2, scale);
+                        });
+                    }
 
-                                let limitVelocity = Scalar.Lerp(particle._currentLimitVelocity1, particle._currentLimitVelocity2, scale);
-                                let currentVelocity = particle.direction.length();
+                    particle.direction.scaleToRef(directionScale, this._scaledDirection);
 
-                                if (currentVelocity > limitVelocity) {
-                                    particle.direction.scaleInPlace(this.limitVelocityDamping);
-                                }
-                            });
-                        }
+                    /// Limit velocity
+                    if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._limitVelocityGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentLimitVelocityGradient) {
+                                particle._currentLimitVelocity1 = particle._currentLimitVelocity2;
+                                particle._currentLimitVelocity2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentLimitVelocityGradient = (<FactorGradient>currentGradient);
+                            }
 
-                        /// Drag
-                        if (this._dragGradients && this._dragGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentDragGradient) {
-                                    particle._currentDrag1 = particle._currentDrag2;
-                                    particle._currentDrag2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentDragGradient = (<FactorGradient>currentGradient);
-                                }
+                            let limitVelocity = Scalar.Lerp(particle._currentLimitVelocity1, particle._currentLimitVelocity2, scale);
+                            let currentVelocity = particle.direction.length();
 
-                                let drag = Scalar.Lerp(particle._currentDrag1, particle._currentDrag2, scale);
+                            if (currentVelocity > limitVelocity) {
+                                particle.direction.scaleInPlace(this.limitVelocityDamping);
+                            }
+                        });
+                    }
 
-                                this._scaledDirection.scaleInPlace(1.0 - drag);
-                            });
-                        }
+                    /// Drag
+                    if (this._dragGradients && this._dragGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentDragGradient) {
+                                particle._currentDrag1 = particle._currentDrag2;
+                                particle._currentDrag2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentDragGradient = (<FactorGradient>currentGradient);
+                            }
 
-                        particle.position.addInPlace(this._scaledDirection);
+                            let drag = Scalar.Lerp(particle._currentDrag1, particle._currentDrag2, scale);
 
-                        // Noise
-                        if (noiseTextureData && noiseTextureSize) {
-                            let fetchedColorR = this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
-                            let fetchedColorG = this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
-                            let fetchedColorB = this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
+                            this._scaledDirection.scaleInPlace(1.0 - drag);
+                        });
+                    }
 
-                            let force = Tmp.Vector3[0];
-                            let scaledForce = Tmp.Vector3[1];
+                    particle.position.addInPlace(this._scaledDirection);
 
-                            force.copyFromFloats((2 * fetchedColorR - 1) * this.noiseStrength.x, (2 * fetchedColorG - 1) * this.noiseStrength.y, (2 * fetchedColorB - 1) * this.noiseStrength.z);
+                    // Noise
+                    if (noiseTextureData && noiseTextureSize) {
+                        let fetchedColorR = this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
+                        let fetchedColorG = this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
+                        let fetchedColorB = this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
 
-                            force.scaleToRef(scaledUpdateSpeed, scaledForce);
-                            particle.direction.addInPlace(scaledForce);
-                        }
+                        let force = Tmp.Vector3[0];
+                        let scaledForce = Tmp.Vector3[1];
 
-                        // Gravity
-                        this.gravity.scaleToRef(scaledUpdateSpeed, this._scaledGravity);
-                        particle.direction.addInPlace(this._scaledGravity);
-
-                        // Size
-                        if (this._sizeGradients && this._sizeGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentSizeGradient) {
-                                    particle._currentSize1 = particle._currentSize2;
-                                    particle._currentSize2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentSizeGradient = (<FactorGradient>currentGradient);
-                                }
-                                particle.size = Scalar.Lerp(particle._currentSize1, particle._currentSize2, scale);
-                            });
-                        }
+                        force.copyFromFloats((2 * fetchedColorR - 1) * this.noiseStrength.x, (2 * fetchedColorG - 1) * this.noiseStrength.y, (2 * fetchedColorB - 1) * this.noiseStrength.z);
 
-                        // Remap data
-                        if (this._useRampGradients) {
-                            if (this._colorRemapGradients && this._colorRemapGradients.length > 0) {
-                                Tools.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, scale) => {
-                                    let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
-                                    let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
+                        force.scaleToRef(scaledUpdateSpeed, scaledForce);
+                        particle.direction.addInPlace(scaledForce);
+                    }
 
-                                    particle.remapData.x = min;
-                                    particle.remapData.y = max - min;
-                                });
+                    // Gravity
+                    this.gravity.scaleToRef(scaledUpdateSpeed, this._scaledGravity);
+                    particle.direction.addInPlace(this._scaledGravity);
+
+                    // Size
+                    if (this._sizeGradients && this._sizeGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentSizeGradient) {
+                                particle._currentSize1 = particle._currentSize2;
+                                particle._currentSize2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentSizeGradient = (<FactorGradient>currentGradient);
                             }
+                            particle.size = Scalar.Lerp(particle._currentSize1, particle._currentSize2, scale);
+                        });
+                    }
 
-                            if (this._alphaRemapGradients && this._alphaRemapGradients.length > 0) {
-                                Tools.GetCurrentGradient(ratio, this._alphaRemapGradients, (currentGradient, nextGradient, scale) => {
-                                    let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
-                                    let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
+                    // Remap data
+                    if (this._useRampGradients) {
+                        if (this._colorRemapGradients && this._colorRemapGradients.length > 0) {
+                            Tools.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, scale) => {
+                                let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
+                                let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
 
-                                    particle.remapData.z = min;
-                                    particle.remapData.w = max - min;
-                                });
-                            }
+                                particle.remapData.x = min;
+                                particle.remapData.y = max - min;
+                            });
                         }
 
-                        if (this._isAnimationSheetEnabled) {
-                            particle.updateCellIndex();
+                        if (this._alphaRemapGradients && this._alphaRemapGradients.length > 0) {
+                            Tools.GetCurrentGradient(ratio, this._alphaRemapGradients, (currentGradient, nextGradient, scale) => {
+                                let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
+                                let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
+
+                                particle.remapData.z = min;
+                                particle.remapData.w = max - min;
+                            });
                         }
+                    }
 
-                        // Update the position of the attached sub-emitters to match their attached particle
-                        particle._inheritParticleInfoToSubEmitters();
-
-                        if (particle.age >= particle.lifeTime) { // Recycle by swapping with last particle
-                            this._emitFromParticle(particle);
-                            if (particle._attachedSubEmitters) {
-                                particle._attachedSubEmitters.forEach((subEmitter) => {
-                                    subEmitter.particleSystem.disposeOnStop = true;
-                                    subEmitter.particleSystem.stop();
-                                });
-                                particle._attachedSubEmitters = null;
-                            }
-                            this.recycleParticle(particle);
-                            index--;
-                            continue;
+                    if (this._isAnimationSheetEnabled) {
+                        particle.updateCellIndex();
+                    }
+
+                    // Update the position of the attached sub-emitters to match their attached particle
+                    particle._inheritParticleInfoToSubEmitters();
+
+                    if (particle.age >= particle.lifeTime) { // Recycle by swapping with last particle
+                        this._emitFromParticle(particle);
+                        if (particle._attachedSubEmitters) {
+                            particle._attachedSubEmitters.forEach((subEmitter) => {
+                                subEmitter.particleSystem.disposeOnStop = true;
+                                subEmitter.particleSystem.stop();
+                            });
+                            particle._attachedSubEmitters = null;
                         }
+                        this.recycleParticle(particle);
+                        index--;
+                        continue;
+                    }
                 }
             };
         }
@@ -1138,14 +1138,14 @@ module BABYLON {
                     }
                     else if (offsetX === 1) {
                         offsetX = 1 - this._epsilon;
-                         }
+                    }
 
                     if (offsetY === 0) {
                         offsetY = this._epsilon;
                     }
                     else if (offsetY === 1) {
                         offsetY = 1 - this._epsilon;
-                         }
+                    }
                 }
 
                 this._vertexData[offset++] = offsetX;
@@ -1565,10 +1565,10 @@ module BABYLON {
                     return;
                 }
 
-                if (this._currentRenderId === this._scene.getRenderId()) {
+                if (this._currentRenderId === this._scene.getFrameId()) {
                     return;
                 }
-                this._currentRenderId = this._scene.getRenderId();
+                this._currentRenderId = this._scene.getFrameId();
             }
 
             this._scaledUpdateSpeed = this.updateSpeed * (preWarmOnly ? this.preWarmStepOffset : this._scene.getAnimationRatio());

+ 20 - 0
src/Tools/babylon.tools.ts

@@ -1,5 +1,25 @@
 module BABYLON {
     /**
+     * Interface for any object that can request an animation frame
+     */
+    export interface ICustomAnimationFrameRequester {
+        /**
+         * This function will be called when the render loop is ready. If this is not populated, the engine's renderloop function will be called
+         */
+        renderFunction?: Function;
+        /**
+         * Called to request the next frame to render to
+         * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
+         */
+        requestAnimationFrame: Function;
+        /**
+         * You can pass this value to cancelAnimationFrame() to cancel the refresh callback request
+         * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame#Return_value
+         */
+        requestID?: number;
+    }
+
+    /**
      * Interface containing an array of animations
      */
     export interface IAnimatable {

+ 16 - 3
src/babylon.scene.ts

@@ -265,6 +265,12 @@ module BABYLON {
          */
         public preventDefaultOnPointerDown = true;
 
+        /**
+         * This is used to call preventDefault() on pointer up
+         * in order to block unwanted artifacts like system double clicks
+         */
+        public preventDefaultOnPointerUp = true;
+
         // Metadata
         /**
          * Gets or sets user defined metadata
@@ -1980,9 +1986,10 @@ module BABYLON {
                             }
                         }
                     }
+                } else {
+                    clickInfo.ignore = true;
+                    cb(clickInfo, this._currentPickResult);
                 }
-                clickInfo.ignore = true;
-                cb(clickInfo, this._currentPickResult);
             };
 
             this._onPointerMove = (evt: PointerEvent) => {
@@ -2057,6 +2064,12 @@ module BABYLON {
                 this._meshPickProceed = false;
 
                 this._updatePointerPosition(evt);
+
+                if (this.preventDefaultOnPointerUp && canvas) {
+                    evt.preventDefault();
+                    canvas.focus();
+                }
+
                 this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable, evt, (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => {
                     // PreObservable support
                     if (this.onPrePointerObservable.hasObservers()) {
@@ -4228,7 +4241,7 @@ module BABYLON {
 
                 mesh._preActivate();
 
-                if (mesh.isVisible && mesh.visibility > 0 && (mesh.alwaysSelectAsActiveMesh || ((mesh.layerMask & this.activeCamera.layerMask) !== 0 && mesh.isInFrustum(this._frustumPlanes)))) {
+                if (mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && (mesh.alwaysSelectAsActiveMesh || mesh.isInFrustum(this._frustumPlanes))) {
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
 

+ 1 - 1
src/babylon.sceneComponent.ts

@@ -138,7 +138,7 @@ module BABYLON {
     /**
      * Strong typing of a Active Mesh related stage step action
      */
-    export type ActiveMeshStageAction =  (sourceMesh: AbstractMesh, mesh: AbstractMesh) => void;
+    export type ActiveMeshStageAction = (sourceMesh: AbstractMesh, mesh: AbstractMesh) => void;
 
     /**
      * Strong typing of a Camera related stage step action

+ 2 - 2
tests/validation/validation.js

@@ -7,7 +7,7 @@ var config;
 var justOnce;
 
 var threshold = 25;
-var errorCountThreshold = 400;
+var errorRatio = 2.5;
 
 // Overload the random to make it deterministic
 var seed = 100000,
@@ -52,7 +52,7 @@ function compare(renderData, referenceCanvas) {
         console.log("Pixel difference: " + differencesCount + " pixels.");
     }
 
-    return differencesCount > errorCountThreshold;
+    return (differencesCount * 100) / (width * height) > errorRatio;
 }
 
 function getRenderData(canvas, engine) {