瀏覽代碼

Merge branch 'master' into object-space-normal-maps

Max Limper 7 年之前
父節點
當前提交
328508bf4d
共有 35 個文件被更改,包括 24558 次插入24103 次删除
  1. 3572 3556
      Playground/babylon.d.txt
  2. 8738 8721
      dist/preview release/babylon.d.ts
  3. 50 50
      dist/preview release/babylon.js
  4. 120 36
      dist/preview release/babylon.max.js
  5. 51 51
      dist/preview release/babylon.worker.js
  6. 11390 11373
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  7. 52 52
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  8. 120 36
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  9. 120 36
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  10. 120 36
      dist/preview release/es6.js
  11. 3 3
      dist/preview release/gui/babylon.gui.min.js
  12. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  13. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  14. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  15. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  16. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  17. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  18. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  19. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  20. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  21. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  22. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  23. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  24. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  25. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  26. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  27. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  28. 60 60
      dist/preview release/viewer/babylon.viewer.js
  29. 2 0
      dist/preview release/what's new.md
  30. 0 28
      sandbox/index.js
  31. 5 0
      src/Layer/babylon.highlightLayer.ts
  32. 23 6
      src/Materials/babylon.effect.ts
  33. 8 0
      src/Particles/babylon.particleSystem.ts
  34. 9 0
      src/Particles/babylon.solidParticle.ts
  35. 86 30
      src/Particles/babylon.solidParticleSystem.ts

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


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


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


+ 120 - 36
dist/preview release/babylon.max.js

@@ -75,21 +75,37 @@ var __extends = (this && this.__extends) || (function () {
         });
         /**
          * Removes the defines that shoould be removed when falling back.
-         * @param currentDefines The current define statements for the shader.
+         * @param currentDefines defines the current define statements for the shader.
+         * @param effect defines the current effect we try to compile
          * @returns The resulting defines with defines of the current rank removed.
          */
-        EffectFallbacks.prototype.reduce = function (currentDefines) {
+        EffectFallbacks.prototype.reduce = function (currentDefines, effect) {
             // First we try to switch to CPU skinning
-            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0) {
+            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0 && this._mesh.material) {
                 this._mesh.computeBonesUsingShaders = false;
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
-                BABYLON.Tools.Log("Falling back to CPU skinning for " + this._mesh.name);
                 var scene = this._mesh.getScene();
                 for (var index = 0; index < scene.meshes.length; index++) {
                     var otherMesh = scene.meshes[index];
-                    if (otherMesh.material === this._mesh.material && otherMesh.computeBonesUsingShaders && otherMesh.numBoneInfluencers > 0) {
+                    if (!otherMesh.material) {
+                        continue;
+                    }
+                    if (!otherMesh.computeBonesUsingShaders || otherMesh.numBoneInfluencers === 0) {
+                        continue;
+                    }
+                    if (otherMesh.material.getEffect() === effect) {
                         otherMesh.computeBonesUsingShaders = false;
                     }
+                    else {
+                        for (var _i = 0, _a = otherMesh.subMeshes; _i < _a.length; _i++) {
+                            var subMesh = _a[_i];
+                            var subMeshEffect = subMesh.effect;
+                            if (subMeshEffect === effect) {
+                                otherMesh.computeBonesUsingShaders = false;
+                                break;
+                            }
+                        }
+                    }
                 }
             }
             else {
@@ -665,7 +681,7 @@ var __extends = (this && this.__extends) || (function () {
                 }
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                     BABYLON.Tools.Error("Trying next fallback.");
-                    this.defines = fallbacks.reduce(this.defines);
+                    this.defines = fallbacks.reduce(this.defines, this);
                     this._prepareEffect();
                 }
                 else {
@@ -50533,6 +50549,13 @@ var BABYLON;
             this._stopped = true;
         };
         /**
+         * Remove all active particles
+         */
+        ParticleSystem.prototype.reset = function () {
+            this._stockParticles = [];
+            this._particles = [];
+        };
+        /**
          * @ignore (for internal use only)
          */
         ParticleSystem.prototype._appendParticleVertex = function (index, particle, offsetX, offsetY) {
@@ -51409,7 +51432,7 @@ var BABYLON;
 
 
 
-//# sourceMappingURL=babylon.IParticleEmitterType.js.map
+//# sourceMappingURL=babylon.iParticleEmitterType.js.map
 
 var BABYLON;
 (function (BABYLON) {
@@ -51707,6 +51730,15 @@ var BABYLON;
              * Last computed particle rotation matrix
              */
             this._rotationMatrix = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
+            /**
+             * Parent particle Id, if any.
+             * Default null.
+             */
+            this.parentId = null;
+            /**
+             * Internal global position in the SPS.
+             */
+            this._globalPosition = BABYLON.Vector3.Zero();
             this.idx = particleIndex;
             this._pos = positionIndex;
             this._ind = indiceIndex;
@@ -51935,6 +51967,8 @@ var BABYLON;
             };
             this._needs32Bits = false;
             this._pivotBackTranslation = BABYLON.Vector3.Zero();
+            this._scaledPivot = BABYLON.Vector3.Zero();
+            this._particleHasParent = false;
             this.name = name;
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
             this._camera = scene.activeCamera;
@@ -52169,11 +52203,14 @@ var BABYLON;
                 this._quaternionRotationYPR();
             }
             this._quaternionToRotationMatrix();
+            this._scaledPivot.x = this._copy.pivot.x * this._copy.scaling.x;
+            this._scaledPivot.y = this._copy.pivot.y * this._copy.scaling.y;
+            this._scaledPivot.z = this._copy.pivot.z * this._copy.scaling.z;
             if (this._copy.translateFromPivot) {
                 this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
             }
             else {
-                this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                this._pivotBackTranslation.copyFrom(this._scaledPivot);
             }
             for (i = 0; i < shape.length; i++) {
                 this._vertex.x = shape[i].x;
@@ -52185,9 +52222,9 @@ var BABYLON;
                 this._vertex.x *= this._copy.scaling.x;
                 this._vertex.y *= this._copy.scaling.y;
                 this._vertex.z *= this._copy.scaling.z;
-                this._vertex.x -= this._copy.pivot.x;
-                this._vertex.y -= this._copy.pivot.y;
-                this._vertex.z -= this._copy.pivot.z;
+                this._vertex.x -= this._scaledPivot.x;
+                this._vertex.y -= this._scaledPivot.y;
+                this._vertex.z -= this._scaledPivot.z;
                 BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                 this._rotated.addInPlace(this._pivotBackTranslation);
                 positions.push(this._copy.position.x + this._rotated.x, this._copy.position.y + this._rotated.y, this._copy.position.z + this._rotated.z);
@@ -52331,11 +52368,14 @@ var BABYLON;
                 this._quaternionRotationYPR();
             }
             this._quaternionToRotationMatrix();
+            this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+            this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+            this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
             if (this._copy.translateFromPivot) {
                 this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
             }
             else {
-                this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                this._pivotBackTranslation.copyFrom(this._scaledPivot);
             }
             this._shape = particle._model._shape;
             for (var pt = 0; pt < this._shape.length; pt++) {
@@ -52348,9 +52388,9 @@ var BABYLON;
                 this._vertex.x *= this._copy.scaling.x;
                 this._vertex.y *= this._copy.scaling.y;
                 this._vertex.z *= this._copy.scaling.z;
-                this._vertex.x -= this._copy.pivot.x;
-                this._vertex.y -= this._copy.pivot.y;
-                this._vertex.z -= this._copy.pivot.z;
+                this._vertex.x -= this._scaledPivot.x;
+                this._vertex.y -= this._scaledPivot.y;
+                this._vertex.z -= this._scaledPivot.z;
                 BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                 this._rotated.addInPlace(this._pivotBackTranslation);
                 this._positions32[particle._pos + pt * 3] = this._copy.position.x + this._rotated.x;
@@ -52367,6 +52407,15 @@ var BABYLON;
             particle.scaling.x = 1.0;
             particle.scaling.y = 1.0;
             particle.scaling.z = 1.0;
+            particle.uvs.x = 0.0;
+            particle.uvs.y = 0.0;
+            particle.uvs.z = 1.0;
+            particle.uvs.w = 1.0;
+            particle.pivot.x = 0.0;
+            particle.pivot.y = 0.0;
+            particle.pivot.z = 0.0;
+            particle.translateFromPivot = false;
+            particle.parentId = null;
         };
         /**
          * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.
@@ -52481,6 +52530,10 @@ var BABYLON;
                 }
                 if (this._particle.isVisible) {
                     this._particle._stillInvisible = false; // un-mark permanent invisibility
+                    this._particleHasParent = (this._particle.parentId !== null);
+                    this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+                    this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+                    this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
                     // particle rotation matrix
                     if (this.billboard) {
                         this._particle.rotation.x = 0.0;
@@ -52497,15 +52550,42 @@ var BABYLON;
                             this._quaternionRotationYPR();
                         }
                         this._quaternionToRotationMatrix();
-                        this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
-                        this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
-                        this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
-                        this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
-                        this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
-                        this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
-                        this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
-                        this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
-                        this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                    }
+                    if (this._particleHasParent) {
+                        this._parent = this.particles[this._particle.parentId];
+                        this._rotated.x = this._particle.position.x * this._parent._rotationMatrix[0] + this._particle.position.y * this._parent._rotationMatrix[3] + this._particle.position.z * this._parent._rotationMatrix[6];
+                        this._rotated.y = this._particle.position.x * this._parent._rotationMatrix[1] + this._particle.position.y * this._parent._rotationMatrix[4] + this._particle.position.z * this._parent._rotationMatrix[7];
+                        this._rotated.z = this._particle.position.x * this._parent._rotationMatrix[2] + this._particle.position.y * this._parent._rotationMatrix[5] + this._particle.position.z * this._parent._rotationMatrix[8];
+                        this._particle._globalPosition.x = this._parent._globalPosition.x + this._rotated.x;
+                        this._particle._globalPosition.y = this._parent._globalPosition.y + this._rotated.y;
+                        this._particle._globalPosition.z = this._parent._globalPosition.z + this._rotated.z;
+                        if (this._computeParticleRotation || this.billboard) {
+                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0] * this._parent._rotationMatrix[0] + this._rotMatrix.m[1] * this._parent._rotationMatrix[3] + this._rotMatrix.m[2] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[1] = this._rotMatrix.m[0] * this._parent._rotationMatrix[1] + this._rotMatrix.m[1] * this._parent._rotationMatrix[4] + this._rotMatrix.m[2] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[2] = this._rotMatrix.m[0] * this._parent._rotationMatrix[2] + this._rotMatrix.m[1] * this._parent._rotationMatrix[5] + this._rotMatrix.m[2] * this._parent._rotationMatrix[8];
+                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4] * this._parent._rotationMatrix[0] + this._rotMatrix.m[5] * this._parent._rotationMatrix[3] + this._rotMatrix.m[6] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[4] = this._rotMatrix.m[4] * this._parent._rotationMatrix[1] + this._rotMatrix.m[5] * this._parent._rotationMatrix[4] + this._rotMatrix.m[6] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[5] = this._rotMatrix.m[4] * this._parent._rotationMatrix[2] + this._rotMatrix.m[5] * this._parent._rotationMatrix[5] + this._rotMatrix.m[6] * this._parent._rotationMatrix[8];
+                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8] * this._parent._rotationMatrix[0] + this._rotMatrix.m[9] * this._parent._rotationMatrix[3] + this._rotMatrix.m[10] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[7] = this._rotMatrix.m[8] * this._parent._rotationMatrix[1] + this._rotMatrix.m[9] * this._parent._rotationMatrix[4] + this._rotMatrix.m[10] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[8] = this._rotMatrix.m[8] * this._parent._rotationMatrix[2] + this._rotMatrix.m[9] * this._parent._rotationMatrix[5] + this._rotMatrix.m[10] * this._parent._rotationMatrix[8];
+                        }
+                    }
+                    else {
+                        this._particle._globalPosition.x = this._particle.position.x;
+                        this._particle._globalPosition.y = this._particle.position.y;
+                        this._particle._globalPosition.z = this._particle.position.z;
+                        if (this._computeParticleRotation || this.billboard) {
+                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
+                            this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
+                            this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
+                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
+                            this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
+                            this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
+                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
+                            this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
+                            this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                        }
                     }
                     if (this._particle.translateFromPivot) {
                         this._pivotBackTranslation.x = 0.0;
@@ -52513,9 +52593,9 @@ var BABYLON;
                         this._pivotBackTranslation.z = 0.0;
                     }
                     else {
-                        this._pivotBackTranslation.x = this._particle.pivot.x;
-                        this._pivotBackTranslation.y = this._particle.pivot.y;
-                        this._pivotBackTranslation.z = this._particle.pivot.z;
+                        this._pivotBackTranslation.x = this._scaledPivot.x;
+                        this._pivotBackTranslation.y = this._scaledPivot.y;
+                        this._pivotBackTranslation.z = this._scaledPivot.z;
                     }
                     // particle vertex loop
                     for (pt = 0; pt < this._shape.length; pt++) {
@@ -52532,18 +52612,18 @@ var BABYLON;
                         this._vertex.x *= this._particle.scaling.x;
                         this._vertex.y *= this._particle.scaling.y;
                         this._vertex.z *= this._particle.scaling.z;
-                        this._vertex.x -= this._particle.pivot.x;
-                        this._vertex.y -= this._particle.pivot.y;
-                        this._vertex.z -= this._particle.pivot.z;
+                        this._vertex.x -= this._scaledPivot.x;
+                        this._vertex.y -= this._scaledPivot.y;
+                        this._vertex.z -= this._scaledPivot.z;
                         this._rotated.x = this._vertex.x * this._particle._rotationMatrix[0] + this._vertex.y * this._particle._rotationMatrix[3] + this._vertex.z * this._particle._rotationMatrix[6];
                         this._rotated.y = this._vertex.x * this._particle._rotationMatrix[1] + this._vertex.y * this._particle._rotationMatrix[4] + this._vertex.z * this._particle._rotationMatrix[7];
                         this._rotated.z = this._vertex.x * this._particle._rotationMatrix[2] + this._vertex.y * this._particle._rotationMatrix[5] + this._vertex.z * this._particle._rotationMatrix[8];
                         this._rotated.x += this._pivotBackTranslation.x;
                         this._rotated.y += this._pivotBackTranslation.y;
                         this._rotated.z += this._pivotBackTranslation.z;
-                        this._positions32[idx] = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
-                        this._positions32[idx + 1] = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
-                        this._positions32[idx + 2] = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                        this._positions32[idx] = this._particle._globalPosition.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
+                        this._positions32[idx + 1] = this._particle._globalPosition.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
+                        this._positions32[idx + 2] = this._particle._globalPosition.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
                         if (this._computeBoundingBox) {
                             if (this._positions32[idx] < this._minimum.x) {
                                 this._minimum.x = this._positions32[idx];
@@ -52639,9 +52719,9 @@ var BABYLON;
                     this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
                     this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
                     this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
-                    bSphere.center.x = this._particle.position.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
-                    bSphere.center.y = this._particle.position.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
-                    bSphere.center.z = this._particle.position.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
+                    bSphere.center.x = this._particle._globalPosition.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
+                    bSphere.center.y = this._particle._globalPosition.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
+                    bSphere.center.z = this._particle._globalPosition.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
                     bSphere.radius = this._bSphereRadiusFactor * 0.5 * Math.sqrt((this._maxBbox.x - this._minBbox.x) * (this._maxBbox.x - this._minBbox.x) + (this._maxBbox.y - this._minBbox.y) * (this._maxBbox.y - this._minBbox.y) + (this._maxBbox.z - this._minBbox.z) * (this._maxBbox.z - this._minBbox.z));
                     bSphere._update(this.mesh._worldMatrix);
                 }
@@ -83634,6 +83714,8 @@ var BABYLON;
                 mainTextureFixedSize: _this._options.mainTextureFixedSize,
                 mainTextureRatio: _this._options.mainTextureRatio
             });
+            // Do not render as long as no meshes have been added
+            _this._shouldRender = false;
             return _this;
         }
         Object.defineProperty(HighlightLayer.prototype, "blurHorizontalSize", {
@@ -83786,6 +83868,7 @@ var BABYLON;
             var previousStencilOperationPass = engine.getStencilOperationPass();
             var previousStencilOperationFail = engine.getStencilOperationFail();
             var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
+            var previousStencilReference = engine.getStencilFunctionReference();
             // Stencil operations
             engine.setStencilOperationPass(BABYLON.Engine.REPLACE);
             engine.setStencilOperationFail(BABYLON.Engine.KEEP);
@@ -83812,6 +83895,7 @@ var BABYLON;
             engine.setStencilOperationPass(previousStencilOperationPass);
             engine.setStencilOperationFail(previousStencilOperationFail);
             engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
+            engine.setStencilFunctionReference(previousStencilReference);
         };
         /**
          * Returns true if the layer contains information to display, otherwise false.

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


File diff suppressed because it is too large
+ 11390 - 11373
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


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


+ 120 - 36
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -75,21 +75,37 @@ var __extends = (this && this.__extends) || (function () {
         });
         /**
          * Removes the defines that shoould be removed when falling back.
-         * @param currentDefines The current define statements for the shader.
+         * @param currentDefines defines the current define statements for the shader.
+         * @param effect defines the current effect we try to compile
          * @returns The resulting defines with defines of the current rank removed.
          */
-        EffectFallbacks.prototype.reduce = function (currentDefines) {
+        EffectFallbacks.prototype.reduce = function (currentDefines, effect) {
             // First we try to switch to CPU skinning
-            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0) {
+            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0 && this._mesh.material) {
                 this._mesh.computeBonesUsingShaders = false;
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
-                BABYLON.Tools.Log("Falling back to CPU skinning for " + this._mesh.name);
                 var scene = this._mesh.getScene();
                 for (var index = 0; index < scene.meshes.length; index++) {
                     var otherMesh = scene.meshes[index];
-                    if (otherMesh.material === this._mesh.material && otherMesh.computeBonesUsingShaders && otherMesh.numBoneInfluencers > 0) {
+                    if (!otherMesh.material) {
+                        continue;
+                    }
+                    if (!otherMesh.computeBonesUsingShaders || otherMesh.numBoneInfluencers === 0) {
+                        continue;
+                    }
+                    if (otherMesh.material.getEffect() === effect) {
                         otherMesh.computeBonesUsingShaders = false;
                     }
+                    else {
+                        for (var _i = 0, _a = otherMesh.subMeshes; _i < _a.length; _i++) {
+                            var subMesh = _a[_i];
+                            var subMeshEffect = subMesh.effect;
+                            if (subMeshEffect === effect) {
+                                otherMesh.computeBonesUsingShaders = false;
+                                break;
+                            }
+                        }
+                    }
                 }
             }
             else {
@@ -665,7 +681,7 @@ var __extends = (this && this.__extends) || (function () {
                 }
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                     BABYLON.Tools.Error("Trying next fallback.");
-                    this.defines = fallbacks.reduce(this.defines);
+                    this.defines = fallbacks.reduce(this.defines, this);
                     this._prepareEffect();
                 }
                 else {
@@ -50533,6 +50549,13 @@ var BABYLON;
             this._stopped = true;
         };
         /**
+         * Remove all active particles
+         */
+        ParticleSystem.prototype.reset = function () {
+            this._stockParticles = [];
+            this._particles = [];
+        };
+        /**
          * @ignore (for internal use only)
          */
         ParticleSystem.prototype._appendParticleVertex = function (index, particle, offsetX, offsetY) {
@@ -51409,7 +51432,7 @@ var BABYLON;
 
 
 
-//# sourceMappingURL=babylon.IParticleEmitterType.js.map
+//# sourceMappingURL=babylon.iParticleEmitterType.js.map
 
 var BABYLON;
 (function (BABYLON) {
@@ -51501,6 +51524,15 @@ var BABYLON;
              * Last computed particle rotation matrix
              */
             this._rotationMatrix = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
+            /**
+             * Parent particle Id, if any.
+             * Default null.
+             */
+            this.parentId = null;
+            /**
+             * Internal global position in the SPS.
+             */
+            this._globalPosition = BABYLON.Vector3.Zero();
             this.idx = particleIndex;
             this._pos = positionIndex;
             this._ind = indiceIndex;
@@ -51729,6 +51761,8 @@ var BABYLON;
             };
             this._needs32Bits = false;
             this._pivotBackTranslation = BABYLON.Vector3.Zero();
+            this._scaledPivot = BABYLON.Vector3.Zero();
+            this._particleHasParent = false;
             this.name = name;
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
             this._camera = scene.activeCamera;
@@ -51963,11 +51997,14 @@ var BABYLON;
                 this._quaternionRotationYPR();
             }
             this._quaternionToRotationMatrix();
+            this._scaledPivot.x = this._copy.pivot.x * this._copy.scaling.x;
+            this._scaledPivot.y = this._copy.pivot.y * this._copy.scaling.y;
+            this._scaledPivot.z = this._copy.pivot.z * this._copy.scaling.z;
             if (this._copy.translateFromPivot) {
                 this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
             }
             else {
-                this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                this._pivotBackTranslation.copyFrom(this._scaledPivot);
             }
             for (i = 0; i < shape.length; i++) {
                 this._vertex.x = shape[i].x;
@@ -51979,9 +52016,9 @@ var BABYLON;
                 this._vertex.x *= this._copy.scaling.x;
                 this._vertex.y *= this._copy.scaling.y;
                 this._vertex.z *= this._copy.scaling.z;
-                this._vertex.x -= this._copy.pivot.x;
-                this._vertex.y -= this._copy.pivot.y;
-                this._vertex.z -= this._copy.pivot.z;
+                this._vertex.x -= this._scaledPivot.x;
+                this._vertex.y -= this._scaledPivot.y;
+                this._vertex.z -= this._scaledPivot.z;
                 BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                 this._rotated.addInPlace(this._pivotBackTranslation);
                 positions.push(this._copy.position.x + this._rotated.x, this._copy.position.y + this._rotated.y, this._copy.position.z + this._rotated.z);
@@ -52125,11 +52162,14 @@ var BABYLON;
                 this._quaternionRotationYPR();
             }
             this._quaternionToRotationMatrix();
+            this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+            this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+            this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
             if (this._copy.translateFromPivot) {
                 this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
             }
             else {
-                this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                this._pivotBackTranslation.copyFrom(this._scaledPivot);
             }
             this._shape = particle._model._shape;
             for (var pt = 0; pt < this._shape.length; pt++) {
@@ -52142,9 +52182,9 @@ var BABYLON;
                 this._vertex.x *= this._copy.scaling.x;
                 this._vertex.y *= this._copy.scaling.y;
                 this._vertex.z *= this._copy.scaling.z;
-                this._vertex.x -= this._copy.pivot.x;
-                this._vertex.y -= this._copy.pivot.y;
-                this._vertex.z -= this._copy.pivot.z;
+                this._vertex.x -= this._scaledPivot.x;
+                this._vertex.y -= this._scaledPivot.y;
+                this._vertex.z -= this._scaledPivot.z;
                 BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                 this._rotated.addInPlace(this._pivotBackTranslation);
                 this._positions32[particle._pos + pt * 3] = this._copy.position.x + this._rotated.x;
@@ -52161,6 +52201,15 @@ var BABYLON;
             particle.scaling.x = 1.0;
             particle.scaling.y = 1.0;
             particle.scaling.z = 1.0;
+            particle.uvs.x = 0.0;
+            particle.uvs.y = 0.0;
+            particle.uvs.z = 1.0;
+            particle.uvs.w = 1.0;
+            particle.pivot.x = 0.0;
+            particle.pivot.y = 0.0;
+            particle.pivot.z = 0.0;
+            particle.translateFromPivot = false;
+            particle.parentId = null;
         };
         /**
          * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.
@@ -52275,6 +52324,10 @@ var BABYLON;
                 }
                 if (this._particle.isVisible) {
                     this._particle._stillInvisible = false; // un-mark permanent invisibility
+                    this._particleHasParent = (this._particle.parentId !== null);
+                    this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+                    this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+                    this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
                     // particle rotation matrix
                     if (this.billboard) {
                         this._particle.rotation.x = 0.0;
@@ -52291,15 +52344,42 @@ var BABYLON;
                             this._quaternionRotationYPR();
                         }
                         this._quaternionToRotationMatrix();
-                        this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
-                        this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
-                        this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
-                        this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
-                        this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
-                        this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
-                        this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
-                        this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
-                        this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                    }
+                    if (this._particleHasParent) {
+                        this._parent = this.particles[this._particle.parentId];
+                        this._rotated.x = this._particle.position.x * this._parent._rotationMatrix[0] + this._particle.position.y * this._parent._rotationMatrix[3] + this._particle.position.z * this._parent._rotationMatrix[6];
+                        this._rotated.y = this._particle.position.x * this._parent._rotationMatrix[1] + this._particle.position.y * this._parent._rotationMatrix[4] + this._particle.position.z * this._parent._rotationMatrix[7];
+                        this._rotated.z = this._particle.position.x * this._parent._rotationMatrix[2] + this._particle.position.y * this._parent._rotationMatrix[5] + this._particle.position.z * this._parent._rotationMatrix[8];
+                        this._particle._globalPosition.x = this._parent._globalPosition.x + this._rotated.x;
+                        this._particle._globalPosition.y = this._parent._globalPosition.y + this._rotated.y;
+                        this._particle._globalPosition.z = this._parent._globalPosition.z + this._rotated.z;
+                        if (this._computeParticleRotation || this.billboard) {
+                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0] * this._parent._rotationMatrix[0] + this._rotMatrix.m[1] * this._parent._rotationMatrix[3] + this._rotMatrix.m[2] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[1] = this._rotMatrix.m[0] * this._parent._rotationMatrix[1] + this._rotMatrix.m[1] * this._parent._rotationMatrix[4] + this._rotMatrix.m[2] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[2] = this._rotMatrix.m[0] * this._parent._rotationMatrix[2] + this._rotMatrix.m[1] * this._parent._rotationMatrix[5] + this._rotMatrix.m[2] * this._parent._rotationMatrix[8];
+                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4] * this._parent._rotationMatrix[0] + this._rotMatrix.m[5] * this._parent._rotationMatrix[3] + this._rotMatrix.m[6] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[4] = this._rotMatrix.m[4] * this._parent._rotationMatrix[1] + this._rotMatrix.m[5] * this._parent._rotationMatrix[4] + this._rotMatrix.m[6] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[5] = this._rotMatrix.m[4] * this._parent._rotationMatrix[2] + this._rotMatrix.m[5] * this._parent._rotationMatrix[5] + this._rotMatrix.m[6] * this._parent._rotationMatrix[8];
+                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8] * this._parent._rotationMatrix[0] + this._rotMatrix.m[9] * this._parent._rotationMatrix[3] + this._rotMatrix.m[10] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[7] = this._rotMatrix.m[8] * this._parent._rotationMatrix[1] + this._rotMatrix.m[9] * this._parent._rotationMatrix[4] + this._rotMatrix.m[10] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[8] = this._rotMatrix.m[8] * this._parent._rotationMatrix[2] + this._rotMatrix.m[9] * this._parent._rotationMatrix[5] + this._rotMatrix.m[10] * this._parent._rotationMatrix[8];
+                        }
+                    }
+                    else {
+                        this._particle._globalPosition.x = this._particle.position.x;
+                        this._particle._globalPosition.y = this._particle.position.y;
+                        this._particle._globalPosition.z = this._particle.position.z;
+                        if (this._computeParticleRotation || this.billboard) {
+                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
+                            this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
+                            this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
+                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
+                            this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
+                            this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
+                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
+                            this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
+                            this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                        }
                     }
                     if (this._particle.translateFromPivot) {
                         this._pivotBackTranslation.x = 0.0;
@@ -52307,9 +52387,9 @@ var BABYLON;
                         this._pivotBackTranslation.z = 0.0;
                     }
                     else {
-                        this._pivotBackTranslation.x = this._particle.pivot.x;
-                        this._pivotBackTranslation.y = this._particle.pivot.y;
-                        this._pivotBackTranslation.z = this._particle.pivot.z;
+                        this._pivotBackTranslation.x = this._scaledPivot.x;
+                        this._pivotBackTranslation.y = this._scaledPivot.y;
+                        this._pivotBackTranslation.z = this._scaledPivot.z;
                     }
                     // particle vertex loop
                     for (pt = 0; pt < this._shape.length; pt++) {
@@ -52326,18 +52406,18 @@ var BABYLON;
                         this._vertex.x *= this._particle.scaling.x;
                         this._vertex.y *= this._particle.scaling.y;
                         this._vertex.z *= this._particle.scaling.z;
-                        this._vertex.x -= this._particle.pivot.x;
-                        this._vertex.y -= this._particle.pivot.y;
-                        this._vertex.z -= this._particle.pivot.z;
+                        this._vertex.x -= this._scaledPivot.x;
+                        this._vertex.y -= this._scaledPivot.y;
+                        this._vertex.z -= this._scaledPivot.z;
                         this._rotated.x = this._vertex.x * this._particle._rotationMatrix[0] + this._vertex.y * this._particle._rotationMatrix[3] + this._vertex.z * this._particle._rotationMatrix[6];
                         this._rotated.y = this._vertex.x * this._particle._rotationMatrix[1] + this._vertex.y * this._particle._rotationMatrix[4] + this._vertex.z * this._particle._rotationMatrix[7];
                         this._rotated.z = this._vertex.x * this._particle._rotationMatrix[2] + this._vertex.y * this._particle._rotationMatrix[5] + this._vertex.z * this._particle._rotationMatrix[8];
                         this._rotated.x += this._pivotBackTranslation.x;
                         this._rotated.y += this._pivotBackTranslation.y;
                         this._rotated.z += this._pivotBackTranslation.z;
-                        this._positions32[idx] = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
-                        this._positions32[idx + 1] = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
-                        this._positions32[idx + 2] = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                        this._positions32[idx] = this._particle._globalPosition.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
+                        this._positions32[idx + 1] = this._particle._globalPosition.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
+                        this._positions32[idx + 2] = this._particle._globalPosition.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
                         if (this._computeBoundingBox) {
                             if (this._positions32[idx] < this._minimum.x) {
                                 this._minimum.x = this._positions32[idx];
@@ -52433,9 +52513,9 @@ var BABYLON;
                     this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
                     this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
                     this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
-                    bSphere.center.x = this._particle.position.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
-                    bSphere.center.y = this._particle.position.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
-                    bSphere.center.z = this._particle.position.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
+                    bSphere.center.x = this._particle._globalPosition.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
+                    bSphere.center.y = this._particle._globalPosition.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
+                    bSphere.center.z = this._particle._globalPosition.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
                     bSphere.radius = this._bSphereRadiusFactor * 0.5 * Math.sqrt((this._maxBbox.x - this._minBbox.x) * (this._maxBbox.x - this._minBbox.x) + (this._maxBbox.y - this._minBbox.y) * (this._maxBbox.y - this._minBbox.y) + (this._maxBbox.z - this._minBbox.z) * (this._maxBbox.z - this._minBbox.z));
                     bSphere._update(this.mesh._worldMatrix);
                 }
@@ -83378,6 +83458,8 @@ var BABYLON;
                 mainTextureFixedSize: _this._options.mainTextureFixedSize,
                 mainTextureRatio: _this._options.mainTextureRatio
             });
+            // Do not render as long as no meshes have been added
+            _this._shouldRender = false;
             return _this;
         }
         Object.defineProperty(HighlightLayer.prototype, "blurHorizontalSize", {
@@ -83530,6 +83612,7 @@ var BABYLON;
             var previousStencilOperationPass = engine.getStencilOperationPass();
             var previousStencilOperationFail = engine.getStencilOperationFail();
             var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
+            var previousStencilReference = engine.getStencilFunctionReference();
             // Stencil operations
             engine.setStencilOperationPass(BABYLON.Engine.REPLACE);
             engine.setStencilOperationFail(BABYLON.Engine.KEEP);
@@ -83556,6 +83639,7 @@ var BABYLON;
             engine.setStencilOperationPass(previousStencilOperationPass);
             engine.setStencilOperationFail(previousStencilOperationFail);
             engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
+            engine.setStencilFunctionReference(previousStencilReference);
         };
         /**
          * Returns true if the layer contains information to display, otherwise false.

+ 120 - 36
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js

@@ -61,21 +61,37 @@ var BABYLON;
         });
         /**
          * Removes the defines that shoould be removed when falling back.
-         * @param currentDefines The current define statements for the shader.
+         * @param currentDefines defines the current define statements for the shader.
+         * @param effect defines the current effect we try to compile
          * @returns The resulting defines with defines of the current rank removed.
          */
-        EffectFallbacks.prototype.reduce = function (currentDefines) {
+        EffectFallbacks.prototype.reduce = function (currentDefines, effect) {
             // First we try to switch to CPU skinning
-            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0) {
+            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0 && this._mesh.material) {
                 this._mesh.computeBonesUsingShaders = false;
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
-                BABYLON.Tools.Log("Falling back to CPU skinning for " + this._mesh.name);
                 var scene = this._mesh.getScene();
                 for (var index = 0; index < scene.meshes.length; index++) {
                     var otherMesh = scene.meshes[index];
-                    if (otherMesh.material === this._mesh.material && otherMesh.computeBonesUsingShaders && otherMesh.numBoneInfluencers > 0) {
+                    if (!otherMesh.material) {
+                        continue;
+                    }
+                    if (!otherMesh.computeBonesUsingShaders || otherMesh.numBoneInfluencers === 0) {
+                        continue;
+                    }
+                    if (otherMesh.material.getEffect() === effect) {
                         otherMesh.computeBonesUsingShaders = false;
                     }
+                    else {
+                        for (var _i = 0, _a = otherMesh.subMeshes; _i < _a.length; _i++) {
+                            var subMesh = _a[_i];
+                            var subMeshEffect = subMesh.effect;
+                            if (subMeshEffect === effect) {
+                                otherMesh.computeBonesUsingShaders = false;
+                                break;
+                            }
+                        }
+                    }
                 }
             }
             else {
@@ -651,7 +667,7 @@ var BABYLON;
                 }
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                     BABYLON.Tools.Error("Trying next fallback.");
-                    this.defines = fallbacks.reduce(this.defines);
+                    this.defines = fallbacks.reduce(this.defines, this);
                     this._prepareEffect();
                 }
                 else {
@@ -50519,6 +50535,13 @@ var BABYLON;
             this._stopped = true;
         };
         /**
+         * Remove all active particles
+         */
+        ParticleSystem.prototype.reset = function () {
+            this._stockParticles = [];
+            this._particles = [];
+        };
+        /**
          * @ignore (for internal use only)
          */
         ParticleSystem.prototype._appendParticleVertex = function (index, particle, offsetX, offsetY) {
@@ -51395,7 +51418,7 @@ var BABYLON;
 
 
 
-//# sourceMappingURL=babylon.IParticleEmitterType.js.map
+//# sourceMappingURL=babylon.iParticleEmitterType.js.map
 
 var BABYLON;
 (function (BABYLON) {
@@ -51487,6 +51510,15 @@ var BABYLON;
              * Last computed particle rotation matrix
              */
             this._rotationMatrix = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
+            /**
+             * Parent particle Id, if any.
+             * Default null.
+             */
+            this.parentId = null;
+            /**
+             * Internal global position in the SPS.
+             */
+            this._globalPosition = BABYLON.Vector3.Zero();
             this.idx = particleIndex;
             this._pos = positionIndex;
             this._ind = indiceIndex;
@@ -51715,6 +51747,8 @@ var BABYLON;
             };
             this._needs32Bits = false;
             this._pivotBackTranslation = BABYLON.Vector3.Zero();
+            this._scaledPivot = BABYLON.Vector3.Zero();
+            this._particleHasParent = false;
             this.name = name;
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
             this._camera = scene.activeCamera;
@@ -51949,11 +51983,14 @@ var BABYLON;
                 this._quaternionRotationYPR();
             }
             this._quaternionToRotationMatrix();
+            this._scaledPivot.x = this._copy.pivot.x * this._copy.scaling.x;
+            this._scaledPivot.y = this._copy.pivot.y * this._copy.scaling.y;
+            this._scaledPivot.z = this._copy.pivot.z * this._copy.scaling.z;
             if (this._copy.translateFromPivot) {
                 this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
             }
             else {
-                this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                this._pivotBackTranslation.copyFrom(this._scaledPivot);
             }
             for (i = 0; i < shape.length; i++) {
                 this._vertex.x = shape[i].x;
@@ -51965,9 +52002,9 @@ var BABYLON;
                 this._vertex.x *= this._copy.scaling.x;
                 this._vertex.y *= this._copy.scaling.y;
                 this._vertex.z *= this._copy.scaling.z;
-                this._vertex.x -= this._copy.pivot.x;
-                this._vertex.y -= this._copy.pivot.y;
-                this._vertex.z -= this._copy.pivot.z;
+                this._vertex.x -= this._scaledPivot.x;
+                this._vertex.y -= this._scaledPivot.y;
+                this._vertex.z -= this._scaledPivot.z;
                 BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                 this._rotated.addInPlace(this._pivotBackTranslation);
                 positions.push(this._copy.position.x + this._rotated.x, this._copy.position.y + this._rotated.y, this._copy.position.z + this._rotated.z);
@@ -52111,11 +52148,14 @@ var BABYLON;
                 this._quaternionRotationYPR();
             }
             this._quaternionToRotationMatrix();
+            this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+            this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+            this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
             if (this._copy.translateFromPivot) {
                 this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
             }
             else {
-                this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                this._pivotBackTranslation.copyFrom(this._scaledPivot);
             }
             this._shape = particle._model._shape;
             for (var pt = 0; pt < this._shape.length; pt++) {
@@ -52128,9 +52168,9 @@ var BABYLON;
                 this._vertex.x *= this._copy.scaling.x;
                 this._vertex.y *= this._copy.scaling.y;
                 this._vertex.z *= this._copy.scaling.z;
-                this._vertex.x -= this._copy.pivot.x;
-                this._vertex.y -= this._copy.pivot.y;
-                this._vertex.z -= this._copy.pivot.z;
+                this._vertex.x -= this._scaledPivot.x;
+                this._vertex.y -= this._scaledPivot.y;
+                this._vertex.z -= this._scaledPivot.z;
                 BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                 this._rotated.addInPlace(this._pivotBackTranslation);
                 this._positions32[particle._pos + pt * 3] = this._copy.position.x + this._rotated.x;
@@ -52147,6 +52187,15 @@ var BABYLON;
             particle.scaling.x = 1.0;
             particle.scaling.y = 1.0;
             particle.scaling.z = 1.0;
+            particle.uvs.x = 0.0;
+            particle.uvs.y = 0.0;
+            particle.uvs.z = 1.0;
+            particle.uvs.w = 1.0;
+            particle.pivot.x = 0.0;
+            particle.pivot.y = 0.0;
+            particle.pivot.z = 0.0;
+            particle.translateFromPivot = false;
+            particle.parentId = null;
         };
         /**
          * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.
@@ -52261,6 +52310,10 @@ var BABYLON;
                 }
                 if (this._particle.isVisible) {
                     this._particle._stillInvisible = false; // un-mark permanent invisibility
+                    this._particleHasParent = (this._particle.parentId !== null);
+                    this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+                    this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+                    this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
                     // particle rotation matrix
                     if (this.billboard) {
                         this._particle.rotation.x = 0.0;
@@ -52277,15 +52330,42 @@ var BABYLON;
                             this._quaternionRotationYPR();
                         }
                         this._quaternionToRotationMatrix();
-                        this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
-                        this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
-                        this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
-                        this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
-                        this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
-                        this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
-                        this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
-                        this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
-                        this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                    }
+                    if (this._particleHasParent) {
+                        this._parent = this.particles[this._particle.parentId];
+                        this._rotated.x = this._particle.position.x * this._parent._rotationMatrix[0] + this._particle.position.y * this._parent._rotationMatrix[3] + this._particle.position.z * this._parent._rotationMatrix[6];
+                        this._rotated.y = this._particle.position.x * this._parent._rotationMatrix[1] + this._particle.position.y * this._parent._rotationMatrix[4] + this._particle.position.z * this._parent._rotationMatrix[7];
+                        this._rotated.z = this._particle.position.x * this._parent._rotationMatrix[2] + this._particle.position.y * this._parent._rotationMatrix[5] + this._particle.position.z * this._parent._rotationMatrix[8];
+                        this._particle._globalPosition.x = this._parent._globalPosition.x + this._rotated.x;
+                        this._particle._globalPosition.y = this._parent._globalPosition.y + this._rotated.y;
+                        this._particle._globalPosition.z = this._parent._globalPosition.z + this._rotated.z;
+                        if (this._computeParticleRotation || this.billboard) {
+                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0] * this._parent._rotationMatrix[0] + this._rotMatrix.m[1] * this._parent._rotationMatrix[3] + this._rotMatrix.m[2] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[1] = this._rotMatrix.m[0] * this._parent._rotationMatrix[1] + this._rotMatrix.m[1] * this._parent._rotationMatrix[4] + this._rotMatrix.m[2] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[2] = this._rotMatrix.m[0] * this._parent._rotationMatrix[2] + this._rotMatrix.m[1] * this._parent._rotationMatrix[5] + this._rotMatrix.m[2] * this._parent._rotationMatrix[8];
+                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4] * this._parent._rotationMatrix[0] + this._rotMatrix.m[5] * this._parent._rotationMatrix[3] + this._rotMatrix.m[6] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[4] = this._rotMatrix.m[4] * this._parent._rotationMatrix[1] + this._rotMatrix.m[5] * this._parent._rotationMatrix[4] + this._rotMatrix.m[6] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[5] = this._rotMatrix.m[4] * this._parent._rotationMatrix[2] + this._rotMatrix.m[5] * this._parent._rotationMatrix[5] + this._rotMatrix.m[6] * this._parent._rotationMatrix[8];
+                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8] * this._parent._rotationMatrix[0] + this._rotMatrix.m[9] * this._parent._rotationMatrix[3] + this._rotMatrix.m[10] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[7] = this._rotMatrix.m[8] * this._parent._rotationMatrix[1] + this._rotMatrix.m[9] * this._parent._rotationMatrix[4] + this._rotMatrix.m[10] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[8] = this._rotMatrix.m[8] * this._parent._rotationMatrix[2] + this._rotMatrix.m[9] * this._parent._rotationMatrix[5] + this._rotMatrix.m[10] * this._parent._rotationMatrix[8];
+                        }
+                    }
+                    else {
+                        this._particle._globalPosition.x = this._particle.position.x;
+                        this._particle._globalPosition.y = this._particle.position.y;
+                        this._particle._globalPosition.z = this._particle.position.z;
+                        if (this._computeParticleRotation || this.billboard) {
+                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
+                            this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
+                            this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
+                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
+                            this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
+                            this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
+                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
+                            this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
+                            this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                        }
                     }
                     if (this._particle.translateFromPivot) {
                         this._pivotBackTranslation.x = 0.0;
@@ -52293,9 +52373,9 @@ var BABYLON;
                         this._pivotBackTranslation.z = 0.0;
                     }
                     else {
-                        this._pivotBackTranslation.x = this._particle.pivot.x;
-                        this._pivotBackTranslation.y = this._particle.pivot.y;
-                        this._pivotBackTranslation.z = this._particle.pivot.z;
+                        this._pivotBackTranslation.x = this._scaledPivot.x;
+                        this._pivotBackTranslation.y = this._scaledPivot.y;
+                        this._pivotBackTranslation.z = this._scaledPivot.z;
                     }
                     // particle vertex loop
                     for (pt = 0; pt < this._shape.length; pt++) {
@@ -52312,18 +52392,18 @@ var BABYLON;
                         this._vertex.x *= this._particle.scaling.x;
                         this._vertex.y *= this._particle.scaling.y;
                         this._vertex.z *= this._particle.scaling.z;
-                        this._vertex.x -= this._particle.pivot.x;
-                        this._vertex.y -= this._particle.pivot.y;
-                        this._vertex.z -= this._particle.pivot.z;
+                        this._vertex.x -= this._scaledPivot.x;
+                        this._vertex.y -= this._scaledPivot.y;
+                        this._vertex.z -= this._scaledPivot.z;
                         this._rotated.x = this._vertex.x * this._particle._rotationMatrix[0] + this._vertex.y * this._particle._rotationMatrix[3] + this._vertex.z * this._particle._rotationMatrix[6];
                         this._rotated.y = this._vertex.x * this._particle._rotationMatrix[1] + this._vertex.y * this._particle._rotationMatrix[4] + this._vertex.z * this._particle._rotationMatrix[7];
                         this._rotated.z = this._vertex.x * this._particle._rotationMatrix[2] + this._vertex.y * this._particle._rotationMatrix[5] + this._vertex.z * this._particle._rotationMatrix[8];
                         this._rotated.x += this._pivotBackTranslation.x;
                         this._rotated.y += this._pivotBackTranslation.y;
                         this._rotated.z += this._pivotBackTranslation.z;
-                        this._positions32[idx] = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
-                        this._positions32[idx + 1] = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
-                        this._positions32[idx + 2] = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                        this._positions32[idx] = this._particle._globalPosition.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
+                        this._positions32[idx + 1] = this._particle._globalPosition.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
+                        this._positions32[idx + 2] = this._particle._globalPosition.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
                         if (this._computeBoundingBox) {
                             if (this._positions32[idx] < this._minimum.x) {
                                 this._minimum.x = this._positions32[idx];
@@ -52419,9 +52499,9 @@ var BABYLON;
                     this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
                     this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
                     this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
-                    bSphere.center.x = this._particle.position.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
-                    bSphere.center.y = this._particle.position.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
-                    bSphere.center.z = this._particle.position.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
+                    bSphere.center.x = this._particle._globalPosition.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
+                    bSphere.center.y = this._particle._globalPosition.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
+                    bSphere.center.z = this._particle._globalPosition.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
                     bSphere.radius = this._bSphereRadiusFactor * 0.5 * Math.sqrt((this._maxBbox.x - this._minBbox.x) * (this._maxBbox.x - this._minBbox.x) + (this._maxBbox.y - this._minBbox.y) * (this._maxBbox.y - this._minBbox.y) + (this._maxBbox.z - this._minBbox.z) * (this._maxBbox.z - this._minBbox.z));
                     bSphere._update(this.mesh._worldMatrix);
                 }
@@ -83364,6 +83444,8 @@ var BABYLON;
                 mainTextureFixedSize: _this._options.mainTextureFixedSize,
                 mainTextureRatio: _this._options.mainTextureRatio
             });
+            // Do not render as long as no meshes have been added
+            _this._shouldRender = false;
             return _this;
         }
         Object.defineProperty(HighlightLayer.prototype, "blurHorizontalSize", {
@@ -83516,6 +83598,7 @@ var BABYLON;
             var previousStencilOperationPass = engine.getStencilOperationPass();
             var previousStencilOperationFail = engine.getStencilOperationFail();
             var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
+            var previousStencilReference = engine.getStencilFunctionReference();
             // Stencil operations
             engine.setStencilOperationPass(BABYLON.Engine.REPLACE);
             engine.setStencilOperationFail(BABYLON.Engine.KEEP);
@@ -83542,6 +83625,7 @@ var BABYLON;
             engine.setStencilOperationPass(previousStencilOperationPass);
             engine.setStencilOperationFail(previousStencilOperationFail);
             engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
+            engine.setStencilFunctionReference(previousStencilReference);
         };
         /**
          * Returns true if the layer contains information to display, otherwise false.

+ 120 - 36
dist/preview release/es6.js

@@ -61,21 +61,37 @@ var BABYLON;
         });
         /**
          * Removes the defines that shoould be removed when falling back.
-         * @param currentDefines The current define statements for the shader.
+         * @param currentDefines defines the current define statements for the shader.
+         * @param effect defines the current effect we try to compile
          * @returns The resulting defines with defines of the current rank removed.
          */
-        EffectFallbacks.prototype.reduce = function (currentDefines) {
+        EffectFallbacks.prototype.reduce = function (currentDefines, effect) {
             // First we try to switch to CPU skinning
-            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0) {
+            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0 && this._mesh.material) {
                 this._mesh.computeBonesUsingShaders = false;
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
-                BABYLON.Tools.Log("Falling back to CPU skinning for " + this._mesh.name);
                 var scene = this._mesh.getScene();
                 for (var index = 0; index < scene.meshes.length; index++) {
                     var otherMesh = scene.meshes[index];
-                    if (otherMesh.material === this._mesh.material && otherMesh.computeBonesUsingShaders && otherMesh.numBoneInfluencers > 0) {
+                    if (!otherMesh.material) {
+                        continue;
+                    }
+                    if (!otherMesh.computeBonesUsingShaders || otherMesh.numBoneInfluencers === 0) {
+                        continue;
+                    }
+                    if (otherMesh.material.getEffect() === effect) {
                         otherMesh.computeBonesUsingShaders = false;
                     }
+                    else {
+                        for (var _i = 0, _a = otherMesh.subMeshes; _i < _a.length; _i++) {
+                            var subMesh = _a[_i];
+                            var subMeshEffect = subMesh.effect;
+                            if (subMeshEffect === effect) {
+                                otherMesh.computeBonesUsingShaders = false;
+                                break;
+                            }
+                        }
+                    }
                 }
             }
             else {
@@ -651,7 +667,7 @@ var BABYLON;
                 }
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                     BABYLON.Tools.Error("Trying next fallback.");
-                    this.defines = fallbacks.reduce(this.defines);
+                    this.defines = fallbacks.reduce(this.defines, this);
                     this._prepareEffect();
                 }
                 else {
@@ -50519,6 +50535,13 @@ var BABYLON;
             this._stopped = true;
         };
         /**
+         * Remove all active particles
+         */
+        ParticleSystem.prototype.reset = function () {
+            this._stockParticles = [];
+            this._particles = [];
+        };
+        /**
          * @ignore (for internal use only)
          */
         ParticleSystem.prototype._appendParticleVertex = function (index, particle, offsetX, offsetY) {
@@ -51395,7 +51418,7 @@ var BABYLON;
 
 
 
-//# sourceMappingURL=babylon.IParticleEmitterType.js.map
+//# sourceMappingURL=babylon.iParticleEmitterType.js.map
 
 var BABYLON;
 (function (BABYLON) {
@@ -51693,6 +51716,15 @@ var BABYLON;
              * Last computed particle rotation matrix
              */
             this._rotationMatrix = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
+            /**
+             * Parent particle Id, if any.
+             * Default null.
+             */
+            this.parentId = null;
+            /**
+             * Internal global position in the SPS.
+             */
+            this._globalPosition = BABYLON.Vector3.Zero();
             this.idx = particleIndex;
             this._pos = positionIndex;
             this._ind = indiceIndex;
@@ -51921,6 +51953,8 @@ var BABYLON;
             };
             this._needs32Bits = false;
             this._pivotBackTranslation = BABYLON.Vector3.Zero();
+            this._scaledPivot = BABYLON.Vector3.Zero();
+            this._particleHasParent = false;
             this.name = name;
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
             this._camera = scene.activeCamera;
@@ -52155,11 +52189,14 @@ var BABYLON;
                 this._quaternionRotationYPR();
             }
             this._quaternionToRotationMatrix();
+            this._scaledPivot.x = this._copy.pivot.x * this._copy.scaling.x;
+            this._scaledPivot.y = this._copy.pivot.y * this._copy.scaling.y;
+            this._scaledPivot.z = this._copy.pivot.z * this._copy.scaling.z;
             if (this._copy.translateFromPivot) {
                 this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
             }
             else {
-                this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                this._pivotBackTranslation.copyFrom(this._scaledPivot);
             }
             for (i = 0; i < shape.length; i++) {
                 this._vertex.x = shape[i].x;
@@ -52171,9 +52208,9 @@ var BABYLON;
                 this._vertex.x *= this._copy.scaling.x;
                 this._vertex.y *= this._copy.scaling.y;
                 this._vertex.z *= this._copy.scaling.z;
-                this._vertex.x -= this._copy.pivot.x;
-                this._vertex.y -= this._copy.pivot.y;
-                this._vertex.z -= this._copy.pivot.z;
+                this._vertex.x -= this._scaledPivot.x;
+                this._vertex.y -= this._scaledPivot.y;
+                this._vertex.z -= this._scaledPivot.z;
                 BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                 this._rotated.addInPlace(this._pivotBackTranslation);
                 positions.push(this._copy.position.x + this._rotated.x, this._copy.position.y + this._rotated.y, this._copy.position.z + this._rotated.z);
@@ -52317,11 +52354,14 @@ var BABYLON;
                 this._quaternionRotationYPR();
             }
             this._quaternionToRotationMatrix();
+            this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+            this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+            this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
             if (this._copy.translateFromPivot) {
                 this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
             }
             else {
-                this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                this._pivotBackTranslation.copyFrom(this._scaledPivot);
             }
             this._shape = particle._model._shape;
             for (var pt = 0; pt < this._shape.length; pt++) {
@@ -52334,9 +52374,9 @@ var BABYLON;
                 this._vertex.x *= this._copy.scaling.x;
                 this._vertex.y *= this._copy.scaling.y;
                 this._vertex.z *= this._copy.scaling.z;
-                this._vertex.x -= this._copy.pivot.x;
-                this._vertex.y -= this._copy.pivot.y;
-                this._vertex.z -= this._copy.pivot.z;
+                this._vertex.x -= this._scaledPivot.x;
+                this._vertex.y -= this._scaledPivot.y;
+                this._vertex.z -= this._scaledPivot.z;
                 BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                 this._rotated.addInPlace(this._pivotBackTranslation);
                 this._positions32[particle._pos + pt * 3] = this._copy.position.x + this._rotated.x;
@@ -52353,6 +52393,15 @@ var BABYLON;
             particle.scaling.x = 1.0;
             particle.scaling.y = 1.0;
             particle.scaling.z = 1.0;
+            particle.uvs.x = 0.0;
+            particle.uvs.y = 0.0;
+            particle.uvs.z = 1.0;
+            particle.uvs.w = 1.0;
+            particle.pivot.x = 0.0;
+            particle.pivot.y = 0.0;
+            particle.pivot.z = 0.0;
+            particle.translateFromPivot = false;
+            particle.parentId = null;
         };
         /**
          * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.
@@ -52467,6 +52516,10 @@ var BABYLON;
                 }
                 if (this._particle.isVisible) {
                     this._particle._stillInvisible = false; // un-mark permanent invisibility
+                    this._particleHasParent = (this._particle.parentId !== null);
+                    this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+                    this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+                    this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
                     // particle rotation matrix
                     if (this.billboard) {
                         this._particle.rotation.x = 0.0;
@@ -52483,15 +52536,42 @@ var BABYLON;
                             this._quaternionRotationYPR();
                         }
                         this._quaternionToRotationMatrix();
-                        this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
-                        this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
-                        this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
-                        this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
-                        this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
-                        this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
-                        this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
-                        this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
-                        this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                    }
+                    if (this._particleHasParent) {
+                        this._parent = this.particles[this._particle.parentId];
+                        this._rotated.x = this._particle.position.x * this._parent._rotationMatrix[0] + this._particle.position.y * this._parent._rotationMatrix[3] + this._particle.position.z * this._parent._rotationMatrix[6];
+                        this._rotated.y = this._particle.position.x * this._parent._rotationMatrix[1] + this._particle.position.y * this._parent._rotationMatrix[4] + this._particle.position.z * this._parent._rotationMatrix[7];
+                        this._rotated.z = this._particle.position.x * this._parent._rotationMatrix[2] + this._particle.position.y * this._parent._rotationMatrix[5] + this._particle.position.z * this._parent._rotationMatrix[8];
+                        this._particle._globalPosition.x = this._parent._globalPosition.x + this._rotated.x;
+                        this._particle._globalPosition.y = this._parent._globalPosition.y + this._rotated.y;
+                        this._particle._globalPosition.z = this._parent._globalPosition.z + this._rotated.z;
+                        if (this._computeParticleRotation || this.billboard) {
+                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0] * this._parent._rotationMatrix[0] + this._rotMatrix.m[1] * this._parent._rotationMatrix[3] + this._rotMatrix.m[2] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[1] = this._rotMatrix.m[0] * this._parent._rotationMatrix[1] + this._rotMatrix.m[1] * this._parent._rotationMatrix[4] + this._rotMatrix.m[2] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[2] = this._rotMatrix.m[0] * this._parent._rotationMatrix[2] + this._rotMatrix.m[1] * this._parent._rotationMatrix[5] + this._rotMatrix.m[2] * this._parent._rotationMatrix[8];
+                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4] * this._parent._rotationMatrix[0] + this._rotMatrix.m[5] * this._parent._rotationMatrix[3] + this._rotMatrix.m[6] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[4] = this._rotMatrix.m[4] * this._parent._rotationMatrix[1] + this._rotMatrix.m[5] * this._parent._rotationMatrix[4] + this._rotMatrix.m[6] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[5] = this._rotMatrix.m[4] * this._parent._rotationMatrix[2] + this._rotMatrix.m[5] * this._parent._rotationMatrix[5] + this._rotMatrix.m[6] * this._parent._rotationMatrix[8];
+                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8] * this._parent._rotationMatrix[0] + this._rotMatrix.m[9] * this._parent._rotationMatrix[3] + this._rotMatrix.m[10] * this._parent._rotationMatrix[6];
+                            this._particle._rotationMatrix[7] = this._rotMatrix.m[8] * this._parent._rotationMatrix[1] + this._rotMatrix.m[9] * this._parent._rotationMatrix[4] + this._rotMatrix.m[10] * this._parent._rotationMatrix[7];
+                            this._particle._rotationMatrix[8] = this._rotMatrix.m[8] * this._parent._rotationMatrix[2] + this._rotMatrix.m[9] * this._parent._rotationMatrix[5] + this._rotMatrix.m[10] * this._parent._rotationMatrix[8];
+                        }
+                    }
+                    else {
+                        this._particle._globalPosition.x = this._particle.position.x;
+                        this._particle._globalPosition.y = this._particle.position.y;
+                        this._particle._globalPosition.z = this._particle.position.z;
+                        if (this._computeParticleRotation || this.billboard) {
+                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
+                            this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
+                            this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
+                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
+                            this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
+                            this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
+                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
+                            this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
+                            this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                        }
                     }
                     if (this._particle.translateFromPivot) {
                         this._pivotBackTranslation.x = 0.0;
@@ -52499,9 +52579,9 @@ var BABYLON;
                         this._pivotBackTranslation.z = 0.0;
                     }
                     else {
-                        this._pivotBackTranslation.x = this._particle.pivot.x;
-                        this._pivotBackTranslation.y = this._particle.pivot.y;
-                        this._pivotBackTranslation.z = this._particle.pivot.z;
+                        this._pivotBackTranslation.x = this._scaledPivot.x;
+                        this._pivotBackTranslation.y = this._scaledPivot.y;
+                        this._pivotBackTranslation.z = this._scaledPivot.z;
                     }
                     // particle vertex loop
                     for (pt = 0; pt < this._shape.length; pt++) {
@@ -52518,18 +52598,18 @@ var BABYLON;
                         this._vertex.x *= this._particle.scaling.x;
                         this._vertex.y *= this._particle.scaling.y;
                         this._vertex.z *= this._particle.scaling.z;
-                        this._vertex.x -= this._particle.pivot.x;
-                        this._vertex.y -= this._particle.pivot.y;
-                        this._vertex.z -= this._particle.pivot.z;
+                        this._vertex.x -= this._scaledPivot.x;
+                        this._vertex.y -= this._scaledPivot.y;
+                        this._vertex.z -= this._scaledPivot.z;
                         this._rotated.x = this._vertex.x * this._particle._rotationMatrix[0] + this._vertex.y * this._particle._rotationMatrix[3] + this._vertex.z * this._particle._rotationMatrix[6];
                         this._rotated.y = this._vertex.x * this._particle._rotationMatrix[1] + this._vertex.y * this._particle._rotationMatrix[4] + this._vertex.z * this._particle._rotationMatrix[7];
                         this._rotated.z = this._vertex.x * this._particle._rotationMatrix[2] + this._vertex.y * this._particle._rotationMatrix[5] + this._vertex.z * this._particle._rotationMatrix[8];
                         this._rotated.x += this._pivotBackTranslation.x;
                         this._rotated.y += this._pivotBackTranslation.y;
                         this._rotated.z += this._pivotBackTranslation.z;
-                        this._positions32[idx] = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
-                        this._positions32[idx + 1] = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
-                        this._positions32[idx + 2] = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                        this._positions32[idx] = this._particle._globalPosition.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
+                        this._positions32[idx + 1] = this._particle._globalPosition.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
+                        this._positions32[idx + 2] = this._particle._globalPosition.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
                         if (this._computeBoundingBox) {
                             if (this._positions32[idx] < this._minimum.x) {
                                 this._minimum.x = this._positions32[idx];
@@ -52625,9 +52705,9 @@ var BABYLON;
                     this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
                     this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
                     this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
-                    bSphere.center.x = this._particle.position.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
-                    bSphere.center.y = this._particle.position.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
-                    bSphere.center.z = this._particle.position.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
+                    bSphere.center.x = this._particle._globalPosition.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
+                    bSphere.center.y = this._particle._globalPosition.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
+                    bSphere.center.z = this._particle._globalPosition.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
                     bSphere.radius = this._bSphereRadiusFactor * 0.5 * Math.sqrt((this._maxBbox.x - this._minBbox.x) * (this._maxBbox.x - this._minBbox.x) + (this._maxBbox.y - this._minBbox.y) * (this._maxBbox.y - this._minBbox.y) + (this._maxBbox.z - this._minBbox.z) * (this._maxBbox.z - this._minBbox.z));
                     bSphere._update(this.mesh._worldMatrix);
                 }
@@ -83620,6 +83700,8 @@ var BABYLON;
                 mainTextureFixedSize: _this._options.mainTextureFixedSize,
                 mainTextureRatio: _this._options.mainTextureRatio
             });
+            // Do not render as long as no meshes have been added
+            _this._shouldRender = false;
             return _this;
         }
         Object.defineProperty(HighlightLayer.prototype, "blurHorizontalSize", {
@@ -83772,6 +83854,7 @@ var BABYLON;
             var previousStencilOperationPass = engine.getStencilOperationPass();
             var previousStencilOperationFail = engine.getStencilOperationFail();
             var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
+            var previousStencilReference = engine.getStencilFunctionReference();
             // Stencil operations
             engine.setStencilOperationPass(BABYLON.Engine.REPLACE);
             engine.setStencilOperationFail(BABYLON.Engine.KEEP);
@@ -83798,6 +83881,7 @@ var BABYLON;
             engine.setStencilOperationPass(previousStencilOperationPass);
             engine.setStencilOperationFail(previousStencilOperationFail);
             engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
+            engine.setStencilFunctionReference(previousStencilReference);
         };
         /**
          * Returns true if the layer contains information to display, otherwise false.

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


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


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


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


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


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

@@ -16,6 +16,7 @@
 ## Updates
 
 - Tons of functions and classes received the code comments they deserved (All the community)
+- Added `particleSystem.reset()` to clear a particle system ([deltakosh](https://github.com/deltakosh))
 - Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
 - Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adaptability ([deltakosh](https://github.com/deltakosh))
 - Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
@@ -48,6 +49,7 @@
 - (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
 - Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager, Effect classes ([trevordev](https://github.com/trevordev))
 - SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
+- SPS particle parenting feature ([jbousquie](https://github.com/jbousquie))
 - (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
 - AssetContainer Class and loading methods ([trevordev](https://github.com/trevordev))
 - KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))

+ 0 - 28
sandbox/index.js

@@ -20,7 +20,6 @@ if (BABYLON.Engine.isSupported()) {
     var currentSkybox;
     var enableDebugLayer = false;
     var currentPluginName;
-    var toExecuteAfterSceneCreation;
 
     canvas.addEventListener("contextmenu", function (evt) {
         evt.preventDefault();
@@ -129,10 +128,6 @@ if (BABYLON.Engine.isSupported()) {
             }
         }
 
-        if (toExecuteAfterSceneCreation) {
-            toExecuteAfterSceneCreation();
-        }
-
     };
 
     var sceneError = function (sceneFile, babylonScene, message) {
@@ -152,29 +147,6 @@ if (BABYLON.Engine.isSupported()) {
     };
 
     filesInput = new BABYLON.FilesInput(engine, null, sceneLoaded, null, null, null, function () { BABYLON.Tools.ClearLogCache() }, null, sceneError);
-    filesInput.onProcessFileCallback = (function (file, name, extension) {
-        if (extension === "dds") {
-            BABYLON.FilesInput.FilesToLoad[name] = file;
-            var loadTexture = () => {
-                if (currentPluginName === "gltf") { // currentPluginName is updated only once scene is loaded
-                    var newHdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("file:" + file.correctName, currentScene);
-                    if (currentSkybox) {
-                        currentSkybox.dispose();
-                    }
-                    currentSkybox = currentScene.createDefaultSkybox(newHdrTexture, true, (currentScene.activeCamera.maxZ - currentScene.activeCamera.minZ) / 2, 0.3);
-                }
-            }
-            if (currentScene) {
-                loadTexture();
-            }
-            else {
-                // Postpone texture loading until scene is loaded
-                toExecuteAfterSceneCreation = loadTexture;
-            }
-            return false;
-        }
-        return true;
-    }).bind(this);
     filesInput.monitorElementForDragNDrop(canvas);
 
     window.addEventListener("keydown", function (evt) {

+ 5 - 0
src/Layer/babylon.highlightLayer.ts

@@ -230,6 +230,9 @@
                 mainTextureFixedSize: this._options.mainTextureFixedSize,
                 mainTextureRatio: this._options.mainTextureRatio
             });
+
+            // Do not render as long as no meshes have been added
+            this._shouldRender = false;
         }
 
         /**
@@ -388,6 +391,7 @@
             var previousStencilOperationPass = engine.getStencilOperationPass();
             var previousStencilOperationFail = engine.getStencilOperationFail();
             var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
+            var previousStencilReference = engine.getStencilFunctionReference();
 
             // Stencil operations
             engine.setStencilOperationPass(Engine.REPLACE);
@@ -418,6 +422,7 @@
             engine.setStencilOperationPass(previousStencilOperationPass);
             engine.setStencilOperationFail(previousStencilOperationFail);
             engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
+            engine.setStencilFunctionReference(previousStencilReference);
         }
 
         /**

+ 23 - 6
src/Materials/babylon.effect.ts

@@ -64,22 +64,39 @@
 
         /**
          * Removes the defines that shoould be removed when falling back.
-         * @param currentDefines The current define statements for the shader.
+         * @param currentDefines defines the current define statements for the shader.
+         * @param effect defines the current effect we try to compile
          * @returns The resulting defines with defines of the current rank removed.
          */
-        public reduce(currentDefines: string): string {
+        public reduce(currentDefines: string, effect: Effect): string {
             // First we try to switch to CPU skinning
-            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0) {
+            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0 && this._mesh.material) {
                 this._mesh.computeBonesUsingShaders = false;
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
-                Tools.Log("Falling back to CPU skinning for " + this._mesh.name);
 
                 var scene = this._mesh.getScene();
                 for (var index = 0; index < scene.meshes.length; index++) {
                     var otherMesh = scene.meshes[index];
 
-                    if (otherMesh.material === this._mesh.material && otherMesh.computeBonesUsingShaders && otherMesh.numBoneInfluencers > 0) {
+                    if (!otherMesh.material) {
+                        continue;
+                    }
+
+                    if (!otherMesh.computeBonesUsingShaders || otherMesh.numBoneInfluencers === 0) {
+                        continue;
+                    }
+
+                    if (otherMesh.material.getEffect() === effect) {
                         otherMesh.computeBonesUsingShaders = false;
+                    } else {
+                        for (var subMesh of otherMesh.subMeshes) {
+                            let subMeshEffect = subMesh.effect;
+
+                            if (subMeshEffect === effect) {
+                                otherMesh.computeBonesUsingShaders = false;
+                                break;
+                            }
+                        }
                     }
                 }
             }
@@ -808,7 +825,7 @@
 
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                     Tools.Error("Trying next fallback.");
-                    this.defines = fallbacks.reduce(this.defines);
+                    this.defines = fallbacks.reduce(this.defines, this);
                     this._prepareEffect();
                 } else { // Sorry we did everything we can
 

+ 8 - 0
src/Particles/babylon.particleSystem.ts

@@ -494,6 +494,14 @@
         }
 
         /**
+         * Remove all active particles
+         */
+        public reset(): void {
+            this._stockParticles = [];
+            this._particles = [];
+        }
+
+        /**
          * @ignore (for internal use only)
          */
         public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {

+ 9 - 0
src/Particles/babylon.solidParticle.ts

@@ -94,6 +94,15 @@ module BABYLON {
          * Last computed particle rotation matrix
          */
         public _rotationMatrix: number[] = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
+        /**
+         * Parent particle Id, if any.
+         * Default null.
+         */
+        public parentId: Nullable<number> = null;
+        /**
+         * Internal global position in the SPS.
+         */
+        public _globalPosition: Vector3 = Vector3.Zero();
 
         /**
          * Creates a Solid Particle object.

+ 86 - 30
src/Particles/babylon.solidParticleSystem.ts

@@ -134,6 +134,9 @@
                 };
             private _needs32Bits: boolean = false;
             private _pivotBackTranslation: Vector3 = Vector3.Zero();
+            private _scaledPivot: Vector3 = Vector3.Zero();
+            private _particleHasParent: boolean = false;
+            private _parent: SolidParticle;
 
             /**
              * Creates a SPS (Solid Particle System) object.
@@ -399,12 +402,16 @@
                     this._quaternionRotationYPR();
                 }
                 this._quaternionToRotationMatrix();
+
+                this._scaledPivot.x = this._copy.pivot.x * this._copy.scaling.x;
+                this._scaledPivot.y = this._copy.pivot.y * this._copy.scaling.y;
+                this._scaledPivot.z = this._copy.pivot.z * this._copy.scaling.z;
                 
                 if (this._copy.translateFromPivot) {
                     this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
                 }
                 else {
-                    this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                    this._pivotBackTranslation.copyFrom(this._scaledPivot);
                 }
     
                 for (i = 0; i < shape.length; i++) {
@@ -420,9 +427,9 @@
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.z *= this._copy.scaling.z;
 
-                    this._vertex.x -= this._copy.pivot.x;
-                    this._vertex.y -= this._copy.pivot.y;
-                    this._vertex.z -= this._copy.pivot.z;
+                    this._vertex.x -= this._scaledPivot.x;
+                    this._vertex.y -= this._scaledPivot.y;
+                    this._vertex.z -= this._scaledPivot.z;
     
                     Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
 
@@ -582,11 +589,15 @@
                 }
                 this._quaternionToRotationMatrix();
 
+                this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+                this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+                this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
+
                 if (this._copy.translateFromPivot) {
                     this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
                 }
                 else {
-                    this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                    this._pivotBackTranslation.copyFrom(this._scaledPivot);
                 }
     
                 this._shape = particle._model._shape;
@@ -603,9 +614,9 @@
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.z *= this._copy.scaling.z;
 
-                    this._vertex.x -= this._copy.pivot.x;
-                    this._vertex.y -= this._copy.pivot.y;
-                    this._vertex.z -= this._copy.pivot.z;
+                    this._vertex.x -= this._scaledPivot.x;
+                    this._vertex.y -= this._scaledPivot.y;
+                    this._vertex.z -= this._scaledPivot.z;
     
                     Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                     this._rotated.addInPlace(this._pivotBackTranslation);
@@ -624,6 +635,15 @@
                 particle.scaling.x = 1.0;
                 particle.scaling.y = 1.0;
                 particle.scaling.z = 1.0;
+                particle.uvs.x = 0.0;
+                particle.uvs.y = 0.0;
+                particle.uvs.z = 1.0;
+                particle.uvs.w = 1.0;
+                particle.pivot.x = 0.0;
+                particle.pivot.y = 0.0;
+                particle.pivot.z = 0.0;
+                particle.translateFromPivot = false;
+                particle.parentId = null;
             }
 
             /**
@@ -751,7 +771,12 @@
     
                     if (this._particle.isVisible) {
                         this._particle._stillInvisible = false; // un-mark permanent invisibility
-    
+                        this._particleHasParent = (this._particle.parentId !== null);
+
+                        this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+                        this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+                        this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
+
                         // particle rotation matrix
                         if (this.billboard) {
                             this._particle.rotation.x = 0.0;
@@ -767,15 +792,46 @@
                                 this._quaternionRotationYPR();
                             }
                             this._quaternionToRotationMatrix();
-                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
-                            this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
-                            this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
-                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
-                            this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
-                            this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
-                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
-                            this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
-                            this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                        }
+
+                        if (this._particleHasParent) {
+                            this._parent = this.particles[this._particle.parentId!];
+                            this._rotated.x = this._particle.position.x * this._parent._rotationMatrix[0] + this._particle.position.y * this._parent._rotationMatrix[3] + this._particle.position.z * this._parent._rotationMatrix[6];
+                            this._rotated.y = this._particle.position.x * this._parent._rotationMatrix[1] + this._particle.position.y * this._parent._rotationMatrix[4] + this._particle.position.z * this._parent._rotationMatrix[7];
+                            this._rotated.z = this._particle.position.x * this._parent._rotationMatrix[2] + this._particle.position.y * this._parent._rotationMatrix[5] + this._particle.position.z * this._parent._rotationMatrix[8];
+
+                            this._particle._globalPosition.x = this._parent._globalPosition.x + this._rotated.x;
+                            this._particle._globalPosition.y = this._parent._globalPosition.y + this._rotated.y;
+                            this._particle._globalPosition.z = this._parent._globalPosition.z + this._rotated.z;
+
+                            if (this._computeParticleRotation || this.billboard) {
+                                this._particle._rotationMatrix[0] = this._rotMatrix.m[0] * this._parent._rotationMatrix[0] + this._rotMatrix.m[1] * this._parent._rotationMatrix[3] + this._rotMatrix.m[2] * this._parent._rotationMatrix[6];
+                                this._particle._rotationMatrix[1] = this._rotMatrix.m[0] * this._parent._rotationMatrix[1] + this._rotMatrix.m[1] * this._parent._rotationMatrix[4] + this._rotMatrix.m[2] * this._parent._rotationMatrix[7];
+                                this._particle._rotationMatrix[2] = this._rotMatrix.m[0] * this._parent._rotationMatrix[2] + this._rotMatrix.m[1] * this._parent._rotationMatrix[5] + this._rotMatrix.m[2] * this._parent._rotationMatrix[8];
+                                this._particle._rotationMatrix[3] = this._rotMatrix.m[4] * this._parent._rotationMatrix[0] + this._rotMatrix.m[5] * this._parent._rotationMatrix[3] + this._rotMatrix.m[6] * this._parent._rotationMatrix[6];
+                                this._particle._rotationMatrix[4] = this._rotMatrix.m[4] * this._parent._rotationMatrix[1] + this._rotMatrix.m[5] * this._parent._rotationMatrix[4] + this._rotMatrix.m[6] * this._parent._rotationMatrix[7];
+                                this._particle._rotationMatrix[5] = this._rotMatrix.m[4] * this._parent._rotationMatrix[2] + this._rotMatrix.m[5] * this._parent._rotationMatrix[5] + this._rotMatrix.m[6] * this._parent._rotationMatrix[8];
+                                this._particle._rotationMatrix[6] = this._rotMatrix.m[8] * this._parent._rotationMatrix[0] + this._rotMatrix.m[9] * this._parent._rotationMatrix[3] + this._rotMatrix.m[10] * this._parent._rotationMatrix[6];
+                                this._particle._rotationMatrix[7] = this._rotMatrix.m[8] * this._parent._rotationMatrix[1] + this._rotMatrix.m[9] * this._parent._rotationMatrix[4] + this._rotMatrix.m[10] * this._parent._rotationMatrix[7];
+                                this._particle._rotationMatrix[8] = this._rotMatrix.m[8] * this._parent._rotationMatrix[2] + this._rotMatrix.m[9] * this._parent._rotationMatrix[5] + this._rotMatrix.m[10] * this._parent._rotationMatrix[8];
+                            }
+                        }
+                        else {
+                            this._particle._globalPosition.x = this._particle.position.x;
+                            this._particle._globalPosition.y = this._particle.position.y;
+                            this._particle._globalPosition.z = this._particle.position.z;
+
+                            if (this._computeParticleRotation || this.billboard) {
+                                this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
+                                this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
+                                this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
+                                this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
+                                this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
+                                this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
+                                this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
+                                this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
+                                this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                            }
                         }
        
                         if (this._particle.translateFromPivot) {
@@ -784,9 +840,9 @@
                             this._pivotBackTranslation.z = 0.0;
                         }
                         else {
-                            this._pivotBackTranslation.x = this._particle.pivot.x;
-                            this._pivotBackTranslation.y = this._particle.pivot.y;
-                            this._pivotBackTranslation.z = this._particle.pivot.z;
+                            this._pivotBackTranslation.x = this._scaledPivot.x;
+                            this._pivotBackTranslation.y = this._scaledPivot.y;
+                            this._pivotBackTranslation.z = this._scaledPivot.z;
                         }
                         // particle vertex loop
                         for (pt = 0; pt < this._shape.length; pt++) {
@@ -807,9 +863,9 @@
                             this._vertex.y *= this._particle.scaling.y;
                             this._vertex.z *= this._particle.scaling.z;
 
-                            this._vertex.x -= this._particle.pivot.x;
-                            this._vertex.y -= this._particle.pivot.y;
-                            this._vertex.z -= this._particle.pivot.z;
+                            this._vertex.x -= this._scaledPivot.x;
+                            this._vertex.y -= this._scaledPivot.y;
+                            this._vertex.z -= this._scaledPivot.z;
     
                             this._rotated.x = this._vertex.x * this._particle._rotationMatrix[0] + this._vertex.y * this._particle._rotationMatrix[3] + this._vertex.z * this._particle._rotationMatrix[6];
                             this._rotated.y = this._vertex.x * this._particle._rotationMatrix[1] + this._vertex.y * this._particle._rotationMatrix[4] + this._vertex.z * this._particle._rotationMatrix[7];
@@ -819,9 +875,9 @@
                             this._rotated.y += this._pivotBackTranslation.y;
                             this._rotated.z += this._pivotBackTranslation.z;
 
-                            this._positions32[idx] = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
-                            this._positions32[idx + 1] = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
-                            this._positions32[idx + 2] = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                            this._positions32[idx] = this._particle._globalPosition.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
+                            this._positions32[idx + 1] = this._particle._globalPosition.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
+                            this._positions32[idx + 2] = this._particle._globalPosition.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
     
                             if (this._computeBoundingBox) {
                                 if (this._positions32[idx] < this._minimum.x) {
@@ -926,9 +982,9 @@
                         this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
                         this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
                         this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
-                        bSphere.center.x = this._particle.position.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
-                        bSphere.center.y = this._particle.position.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
-                        bSphere.center.z = this._particle.position.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
+                        bSphere.center.x = this._particle._globalPosition.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
+                        bSphere.center.y = this._particle._globalPosition.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
+                        bSphere.center.z = this._particle._globalPosition.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
                         bSphere.radius = this._bSphereRadiusFactor * 0.5 * Math.sqrt((this._maxBbox.x - this._minBbox.x) * (this._maxBbox.x - this._minBbox.x) + (this._maxBbox.y - this._minBbox.y) * (this._maxBbox.y - this._minBbox.y) + (this._maxBbox.z - this._minBbox.z) * (this._maxBbox.z - this._minBbox.z));
                         bSphere._update(this.mesh._worldMatrix);
                     }