Browse Source

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into customAnimationFrameReq

Trevor Baron 6 years ago
parent
commit
08c4ebd56d

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


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


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


+ 35 - 10
dist/preview release/babylon.max.js

@@ -5457,10 +5457,10 @@ var BABYLON;
          * @return the angle between vector0 and vector1
          */
         Vector3.GetAngleBetweenVectors = function (vector0, vector1, normal) {
-            var v0 = vector0.normalizeToRef(MathTmp.Vector3[0]);
-            var v1 = vector1.normalizeToRef(MathTmp.Vector3[1]);
+            var v0 = vector0.normalizeToRef(MathTmp.Vector3[1]);
+            var v1 = vector1.normalizeToRef(MathTmp.Vector3[2]);
             var dot = Vector3.Dot(v0, v1);
-            var n = MathTmp.Vector3[2];
+            var n = MathTmp.Vector3[3];
             Vector3.CrossToRef(v0, v1, n);
             if (Vector3.Dot(n, normal) > 0) {
                 return Math.acos(dot);
@@ -43218,6 +43218,12 @@ var BABYLON;
         function PushMaterial(name, scene) {
             var _this = _super.call(this, name, scene) || this;
             _this._normalMatrix = new BABYLON.Matrix();
+            /**
+             * Gets or sets a boolean indicating that the material is allowed to do shader hot swapping.
+             * This means that the material can keep using a previous shader while a new one is being compiled.
+             * This is mostly used when shader parallel compilation is supported (true by default)
+             */
+            _this.allowShaderHotSwapping = true;
             _this.storeEffectOnSubMeshes = true;
             return _this;
         }
@@ -43965,7 +43971,6 @@ var BABYLON;
             // Get correct effect
             if (defines.isDirty) {
                 defines.markAsProcessed();
-                scene.resetCachedMaterial();
                 // Fallbacks
                 var fallbacks = new BABYLON.EffectFallbacks();
                 if (defines.REFLECTION) {
@@ -44058,7 +44063,8 @@ var BABYLON;
                     shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines);
                 }
                 var join = defines.toString();
-                subMesh.setEffect(scene.getEngine().createEffect(shaderName, {
+                var previousEffect = subMesh.effect;
+                var effect = scene.getEngine().createEffect(shaderName, {
                     attributes: attribs,
                     uniformsNames: uniforms,
                     uniformBuffersNames: uniformBuffers,
@@ -44068,8 +44074,19 @@ var BABYLON;
                     onCompiled: this.onCompiled,
                     onError: this.onError,
                     indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
-                }, engine), defines);
-                this.buildUniformLayout();
+                }, engine);
+                if (effect) {
+                    // Use previous effect while new one is compiling
+                    if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                        effect = previousEffect;
+                        defines.markAsUnprocessed();
+                    }
+                    else {
+                        scene.resetCachedMaterial();
+                        subMesh.setEffect(effect, defines);
+                        this.buildUniformLayout();
+                    }
+                }
             }
             if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;
@@ -46013,11 +46030,19 @@ var BABYLON;
                 mesh.createNormals(true);
                 BABYLON.Tools.Warn("PBRMaterial: Normals have been created for the mesh: " + mesh.name);
             }
+            var previousEffect = subMesh.effect;
             var effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances);
             if (effect) {
-                scene.resetCachedMaterial();
-                subMesh.setEffect(effect, defines);
-                this.buildUniformLayout();
+                // Use previous effect while new one is compiling
+                if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                    effect = previousEffect;
+                    defines.markAsUnprocessed();
+                }
+                else {
+                    scene.resetCachedMaterial();
+                    subMesh.setEffect(effect, defines);
+                    this.buildUniformLayout();
+                }
             }
             if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;

+ 35 - 10
dist/preview release/babylon.no-module.max.js

@@ -5424,10 +5424,10 @@ var BABYLON;
          * @return the angle between vector0 and vector1
          */
         Vector3.GetAngleBetweenVectors = function (vector0, vector1, normal) {
-            var v0 = vector0.normalizeToRef(MathTmp.Vector3[0]);
-            var v1 = vector1.normalizeToRef(MathTmp.Vector3[1]);
+            var v0 = vector0.normalizeToRef(MathTmp.Vector3[1]);
+            var v1 = vector1.normalizeToRef(MathTmp.Vector3[2]);
             var dot = Vector3.Dot(v0, v1);
-            var n = MathTmp.Vector3[2];
+            var n = MathTmp.Vector3[3];
             Vector3.CrossToRef(v0, v1, n);
             if (Vector3.Dot(n, normal) > 0) {
                 return Math.acos(dot);
@@ -43185,6 +43185,12 @@ var BABYLON;
         function PushMaterial(name, scene) {
             var _this = _super.call(this, name, scene) || this;
             _this._normalMatrix = new BABYLON.Matrix();
+            /**
+             * Gets or sets a boolean indicating that the material is allowed to do shader hot swapping.
+             * This means that the material can keep using a previous shader while a new one is being compiled.
+             * This is mostly used when shader parallel compilation is supported (true by default)
+             */
+            _this.allowShaderHotSwapping = true;
             _this.storeEffectOnSubMeshes = true;
             return _this;
         }
@@ -43932,7 +43938,6 @@ var BABYLON;
             // Get correct effect
             if (defines.isDirty) {
                 defines.markAsProcessed();
-                scene.resetCachedMaterial();
                 // Fallbacks
                 var fallbacks = new BABYLON.EffectFallbacks();
                 if (defines.REFLECTION) {
@@ -44025,7 +44030,8 @@ var BABYLON;
                     shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines);
                 }
                 var join = defines.toString();
-                subMesh.setEffect(scene.getEngine().createEffect(shaderName, {
+                var previousEffect = subMesh.effect;
+                var effect = scene.getEngine().createEffect(shaderName, {
                     attributes: attribs,
                     uniformsNames: uniforms,
                     uniformBuffersNames: uniformBuffers,
@@ -44035,8 +44041,19 @@ var BABYLON;
                     onCompiled: this.onCompiled,
                     onError: this.onError,
                     indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
-                }, engine), defines);
-                this.buildUniformLayout();
+                }, engine);
+                if (effect) {
+                    // Use previous effect while new one is compiling
+                    if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                        effect = previousEffect;
+                        defines.markAsUnprocessed();
+                    }
+                    else {
+                        scene.resetCachedMaterial();
+                        subMesh.setEffect(effect, defines);
+                        this.buildUniformLayout();
+                    }
+                }
             }
             if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;
@@ -45980,11 +45997,19 @@ var BABYLON;
                 mesh.createNormals(true);
                 BABYLON.Tools.Warn("PBRMaterial: Normals have been created for the mesh: " + mesh.name);
             }
+            var previousEffect = subMesh.effect;
             var effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances);
             if (effect) {
-                scene.resetCachedMaterial();
-                subMesh.setEffect(effect, defines);
-                this.buildUniformLayout();
+                // Use previous effect while new one is compiling
+                if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                    effect = previousEffect;
+                    defines.markAsUnprocessed();
+                }
+                else {
+                    scene.resetCachedMaterial();
+                    subMesh.setEffect(effect, defines);
+                    this.buildUniformLayout();
+                }
             }
             if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;

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


+ 35 - 10
dist/preview release/es6.js

@@ -5424,10 +5424,10 @@ var BABYLON;
          * @return the angle between vector0 and vector1
          */
         Vector3.GetAngleBetweenVectors = function (vector0, vector1, normal) {
-            var v0 = vector0.normalizeToRef(MathTmp.Vector3[0]);
-            var v1 = vector1.normalizeToRef(MathTmp.Vector3[1]);
+            var v0 = vector0.normalizeToRef(MathTmp.Vector3[1]);
+            var v1 = vector1.normalizeToRef(MathTmp.Vector3[2]);
             var dot = Vector3.Dot(v0, v1);
-            var n = MathTmp.Vector3[2];
+            var n = MathTmp.Vector3[3];
             Vector3.CrossToRef(v0, v1, n);
             if (Vector3.Dot(n, normal) > 0) {
                 return Math.acos(dot);
@@ -43185,6 +43185,12 @@ var BABYLON;
         function PushMaterial(name, scene) {
             var _this = _super.call(this, name, scene) || this;
             _this._normalMatrix = new BABYLON.Matrix();
+            /**
+             * Gets or sets a boolean indicating that the material is allowed to do shader hot swapping.
+             * This means that the material can keep using a previous shader while a new one is being compiled.
+             * This is mostly used when shader parallel compilation is supported (true by default)
+             */
+            _this.allowShaderHotSwapping = true;
             _this.storeEffectOnSubMeshes = true;
             return _this;
         }
@@ -43932,7 +43938,6 @@ var BABYLON;
             // Get correct effect
             if (defines.isDirty) {
                 defines.markAsProcessed();
-                scene.resetCachedMaterial();
                 // Fallbacks
                 var fallbacks = new BABYLON.EffectFallbacks();
                 if (defines.REFLECTION) {
@@ -44025,7 +44030,8 @@ var BABYLON;
                     shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines);
                 }
                 var join = defines.toString();
-                subMesh.setEffect(scene.getEngine().createEffect(shaderName, {
+                var previousEffect = subMesh.effect;
+                var effect = scene.getEngine().createEffect(shaderName, {
                     attributes: attribs,
                     uniformsNames: uniforms,
                     uniformBuffersNames: uniformBuffers,
@@ -44035,8 +44041,19 @@ var BABYLON;
                     onCompiled: this.onCompiled,
                     onError: this.onError,
                     indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
-                }, engine), defines);
-                this.buildUniformLayout();
+                }, engine);
+                if (effect) {
+                    // Use previous effect while new one is compiling
+                    if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                        effect = previousEffect;
+                        defines.markAsUnprocessed();
+                    }
+                    else {
+                        scene.resetCachedMaterial();
+                        subMesh.setEffect(effect, defines);
+                        this.buildUniformLayout();
+                    }
+                }
             }
             if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;
@@ -45980,11 +45997,19 @@ var BABYLON;
                 mesh.createNormals(true);
                 BABYLON.Tools.Warn("PBRMaterial: Normals have been created for the mesh: " + mesh.name);
             }
+            var previousEffect = subMesh.effect;
             var effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances);
             if (effect) {
-                scene.resetCachedMaterial();
-                subMesh.setEffect(effect, defines);
-                this.buildUniformLayout();
+                // Use previous effect while new one is compiling
+                if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                    effect = previousEffect;
+                    defines.markAsUnprocessed();
+                }
+                else {
+                    scene.resetCachedMaterial();
+                    subMesh.setEffect(effect, defines);
+                    this.buildUniformLayout();
+                }
             }
             if (!subMesh.effect || !subMesh.effect.isReady()) {
                 return false;

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

@@ -1728,465 +1728,6 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
-    export interface ICameraConfiguration {
-        position?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        rotation?: {
-            x: number;
-            y: number;
-            z: number;
-            w: number;
-        };
-        fov?: number;
-        fovMode?: number;
-        minZ?: number;
-        maxZ?: number;
-        inertia?: number;
-        exposure?: number;
-        pinchPrecision?: number;
-        behaviors?: {
-            [name: string]: boolean | number | ICameraBehaviorConfiguration;
-        };
-        disableCameraControl?: boolean;
-        disableCtrlForPanning?: boolean;
-        disableAutoFocus?: boolean;
-        [propName: string]: any;
-    }
-    export interface ICameraBehaviorConfiguration {
-        type: number;
-        [propName: string]: any;
-    }
-}
-declare module BabylonViewer {
-    /**
-        * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
-        */
-    export interface IColorGradingConfiguration {
-            /**
-                * Transform data string, encoded as determined by transformDataFormat.
-                */
-            transformData: string;
-            /**
-                * The encoding format of TransformData (currently only raw-base16 is supported).
-                */
-            transformDataFormat: string;
-            /**
-                * The weight of the transform
-                */
-            transformWeight: number;
-            /**
-                * Color curve colorFilterHueGlobal value
-                */
-            colorFilterHueGlobal: number;
-            /**
-                * Color curve colorFilterHueShadows value
-                */
-            colorFilterHueShadows: number;
-            /**
-                * Color curve colorFilterHueMidtones value
-                */
-            colorFilterHueMidtones: number;
-            /**
-                * Color curve colorFilterHueHighlights value
-                */
-            colorFilterHueHighlights: number;
-            /**
-                * Color curve colorFilterDensityGlobal value
-                */
-            colorFilterDensityGlobal: number;
-            /**
-                * Color curve colorFilterDensityShadows value
-                */
-            colorFilterDensityShadows: number;
-            /**
-                * Color curve colorFilterDensityMidtones value
-                */
-            colorFilterDensityMidtones: number;
-            /**
-                * Color curve colorFilterDensityHighlights value
-                */
-            colorFilterDensityHighlights: number;
-            /**
-                * Color curve saturationGlobal value
-                */
-            saturationGlobal: number;
-            /**
-                * Color curve saturationShadows value
-                */
-            saturationShadows: number;
-            /**
-                * Color curve saturationMidtones value
-                */
-            saturationMidtones: number;
-            /**
-                * Color curve saturationHighlights value
-                */
-            saturationHighlights: number;
-            /**
-                * Color curve exposureGlobal value
-                */
-            exposureGlobal: number;
-            /**
-                * Color curve exposureShadows value
-                */
-            exposureShadows: number;
-            /**
-                * Color curve exposureMidtones value
-                */
-            exposureMidtones: number;
-            /**
-                * Color curve exposureHighlights value
-                */
-            exposureHighlights: number;
-    }
-}
-declare module BabylonViewer {
-    export interface IDefaultRenderingPipelineConfiguration {
-        sharpenEnabled?: boolean;
-        bloomEnabled?: boolean;
-        bloomThreshold?: number;
-        depthOfFieldEnabled?: boolean;
-        depthOfFieldBlurLevel?: BABYLON.DepthOfFieldEffectBlurLevel;
-        fxaaEnabled?: boolean;
-        imageProcessingEnabled?: boolean;
-        defaultPipelineTextureType?: number;
-        bloomScale?: number;
-        chromaticAberrationEnabled?: boolean;
-        grainEnabled?: boolean;
-        bloomKernel?: number;
-        hardwareScaleLevel?: number;
-        bloomWeight?: number;
-        hdr?: boolean;
-        samples?: number;
-        glowLayerEnabled?: boolean;
-    }
-}
-declare module BabylonViewer {
-    export interface IGroundConfiguration {
-        size?: number;
-        receiveShadows?: boolean;
-        shadowLevel?: number;
-        shadowOnly?: boolean;
-        mirror?: boolean | {
-            sizeRatio?: number;
-            blurKernel?: number;
-            amount?: number;
-            fresnelWeight?: number;
-            fallOffDistance?: number;
-            textureType?: number;
-        };
-        texture?: string;
-        color?: {
-            r: number;
-            g: number;
-            b: number;
-        };
-        opacity?: number;
-        material?: {
-            [propName: string]: any;
-        };
-    }
-}
-declare module BabylonViewer {
-    export interface IImageProcessingConfiguration {
-        colorGradingEnabled?: boolean;
-        colorCurvesEnabled?: boolean;
-        colorCurves?: {
-            globalHue?: number;
-            globalDensity?: number;
-            globalSaturation?: number;
-            globalExposure?: number;
-            highlightsHue?: number;
-            highlightsDensity?: number;
-            highlightsSaturation?: number;
-            highlightsExposure?: number;
-            midtonesHue?: number;
-            midtonesDensity?: number;
-            midtonesSaturation?: number;
-            midtonesExposure?: number;
-            shadowsHue?: number;
-            shadowsDensity?: number;
-            shadowsSaturation?: number;
-            shadowsExposure?: number;
-        };
-        colorGradingWithGreenDepth?: boolean;
-        colorGradingBGR?: boolean;
-        exposure?: number;
-        toneMappingEnabled?: boolean;
-        contrast?: number;
-        vignetteEnabled?: boolean;
-        vignetteStretch?: number;
-        vignetteCentreX?: number;
-        vignetteCentreY?: number;
-        vignetteWeight?: number;
-        vignetteColor?: {
-            r: number;
-            g: number;
-            b: number;
-            a?: number;
-        };
-        vignetteCameraFov?: number;
-        vignetteBlendMode?: number;
-        vignetteM?: boolean;
-        applyByPostProcess?: boolean;
-        isEnabled?: boolean;
-    }
-}
-declare module BabylonViewer {
-    export interface ILightConfiguration {
-        type: number;
-        name?: string;
-        disabled?: boolean;
-        position?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        target?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        direction?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        diffuse?: {
-            r: number;
-            g: number;
-            b: number;
-        };
-        specular?: {
-            r: number;
-            g: number;
-            b: number;
-        };
-        intensity?: number;
-        intensityMode?: number;
-        radius?: number;
-        shadownEnabled?: boolean;
-        shadowConfig?: {
-            useBlurExponentialShadowMap?: boolean;
-            useBlurCloseExponentialShadowMap?: boolean;
-            useKernelBlur?: boolean;
-            blurKernel?: number;
-            blurScale?: number;
-            minZ?: number;
-            maxZ?: number;
-            frustumSize?: number;
-            angleScale?: number;
-            frustumEdgeFalloff?: number;
-            [propName: string]: any;
-        };
-        spotAngle?: number;
-        shadowFieldOfView?: number;
-        shadowBufferSize?: number;
-        shadowFrustumSize?: number;
-        shadowMinZ?: number;
-        shadowMaxZ?: number;
-        [propName: string]: any;
-        behaviors?: {
-            [name: string]: number | {
-                type: number;
-                [propName: string]: any;
-            };
-        };
-    }
-}
-declare module BabylonViewer {
-    export interface IObserversConfiguration {
-        onEngineInit?: string;
-        onSceneInit?: string;
-        onModelLoaded?: string;
-    }
-}
-declare module BabylonViewer {
-    export interface ISceneConfiguration {
-            debug?: boolean;
-            clearColor?: {
-                    r: number;
-                    g: number;
-                    b: number;
-                    a: number;
-            };
-            /** Deprecated, use environmentMap.mainColor instead. */
-            mainColor?: {
-                    r?: number;
-                    g?: number;
-                    b?: number;
-            };
-            imageProcessingConfiguration?: IImageProcessingConfiguration;
-            environmentTexture?: string;
-            colorGrading?: IColorGradingConfiguration;
-            environmentRotationY?: number;
-            /**
-                * Deprecated, please use default rendering pipeline
-                */
-            glow?: boolean | BABYLON.IGlowLayerOptions;
-            disableHdr?: boolean;
-            renderInBackground?: boolean;
-            disableCameraControl?: boolean;
-            animationPropertiesOverride?: {
-                    [propName: string]: any;
-            };
-            defaultMaterial?: {
-                    materialType: "standard" | "pbr";
-                    [propName: string]: any;
-            };
-            flags?: {
-                    shadowsEnabled?: boolean;
-                    particlesEnabled?: boolean;
-                    collisionsEnabled?: boolean;
-                    lightsEnabled?: boolean;
-                    texturesEnabled?: boolean;
-                    lensFlaresEnabled?: boolean;
-                    proceduralTexturesEnabled?: boolean;
-                    renderTargetsEnabled?: boolean;
-                    spritesEnabled?: boolean;
-                    skeletonsEnabled?: boolean;
-                    audioEnabled?: boolean;
-            };
-            assetsRootURL?: string;
-    }
-}
-declare module BabylonViewer {
-    export interface ISceneOptimizerConfiguration {
-        targetFrameRate?: number;
-        trackerDuration?: number;
-        autoGeneratePriorities?: boolean;
-        improvementMode?: boolean;
-        degradation?: string;
-        types?: {
-            texture?: ISceneOptimizerParameters;
-            hardwareScaling?: ISceneOptimizerParameters;
-            shadow?: ISceneOptimizerParameters;
-            postProcess?: ISceneOptimizerParameters;
-            lensFlare?: ISceneOptimizerParameters;
-            particles?: ISceneOptimizerParameters;
-            renderTarget?: ISceneOptimizerParameters;
-            mergeMeshes?: ISceneOptimizerParameters;
-        };
-        custom?: string;
-    }
-    export interface ISceneOptimizerParameters {
-        priority?: number;
-        maximumSize?: number;
-        step?: number;
-    }
-}
-declare module BabylonViewer {
-    export interface ISkyboxConfiguration {
-        cubeTexture?: {
-            noMipMap?: boolean;
-            gammaSpace?: boolean;
-            url?: string | Array<string>;
-        };
-        color?: {
-            r: number;
-            g: number;
-            b: number;
-        };
-        pbr?: boolean;
-        scale?: number;
-        blur?: number;
-        material?: {
-            imageProcessingConfiguration?: IImageProcessingConfiguration;
-            [propName: string]: any;
-        };
-        infiniteDistance?: boolean;
-    }
-}
-declare module BabylonViewer {
-    /**
-        * A single template configuration object
-        */
-    export interface ITemplateConfiguration {
-            /**
-                * can be either the id of the template's html element or a URL.
-                * See - http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
-                */
-            location?: string;
-            /**
-                * If no location is provided you can provide here the raw html of this template.
-                * See http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
-                */
-            html?: string;
-            id?: string;
-            /**
-                * Parameters that will be delivered to the template and will render it accordingly.
-                */
-            params?: {
-                    [key: string]: string | number | boolean | object;
-            };
-            /**
-                * Events to attach to this template.
-                * event name is the key. the value can either be a boolean (attach to the parent element)
-                * or a map of html id elements.
-                *
-                * See - http://doc.babylonjs.com/extensions/the_templating_system#event-binding
-                */
-            events?: {
-                    pointerdown?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerup?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointermove?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerover?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerout?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerenter?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerleave?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointercancel?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    click?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    dragstart?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    drop?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    [key: string]: boolean | {
-                            [id: string]: boolean;
-                    } | undefined;
-            };
-    }
-}
-declare module BabylonViewer {
-    export interface IVRConfiguration {
-        disabled?: boolean;
-        objectScaleFactor?: number;
-        disableInteractions?: boolean;
-        disableTeleportation?: boolean;
-        overrideFloorMeshName?: string;
-        vrOptions?: BABYLON.VRExperienceHelperOptions;
-        modelHeightCorrection?: number | boolean;
-        rotateUsingControllers?: boolean;
-        cameraPosition?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-    }
-}
-declare module BabylonViewer {
     /**
         * Spherical polynomial coefficients (counter part to spherical harmonic coefficients used in shader irradiance calculation)
         * @ignoreChildren

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


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


+ 1 - 492
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -1663,21 +1663,7 @@ declare module 'babylonjs-viewer/loader/plugins' {
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces' {
-    export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/defaultRenderingPipelineConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/groundConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/lightConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/modelAnimationConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/modelConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/observersConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/sceneConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/sceneOptimizerConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/templateConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/vrConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration';
+    
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration' {
@@ -1871,483 +1857,6 @@ declare module 'babylonjs-viewer/loader/plugins/extendedMaterialLoaderPlugin' {
     }
 }
 
-declare module 'babylonjs-viewer/configuration/interfaces/cameraConfiguration' {
-    export interface ICameraConfiguration {
-        position?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        rotation?: {
-            x: number;
-            y: number;
-            z: number;
-            w: number;
-        };
-        fov?: number;
-        fovMode?: number;
-        minZ?: number;
-        maxZ?: number;
-        inertia?: number;
-        exposure?: number;
-        pinchPrecision?: number;
-        behaviors?: {
-            [name: string]: boolean | number | ICameraBehaviorConfiguration;
-        };
-        disableCameraControl?: boolean;
-        disableCtrlForPanning?: boolean;
-        disableAutoFocus?: boolean;
-        [propName: string]: any;
-    }
-    export interface ICameraBehaviorConfiguration {
-        type: number;
-        [propName: string]: any;
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration' {
-    /**
-        * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
-        */
-    export interface IColorGradingConfiguration {
-            /**
-                * Transform data string, encoded as determined by transformDataFormat.
-                */
-            transformData: string;
-            /**
-                * The encoding format of TransformData (currently only raw-base16 is supported).
-                */
-            transformDataFormat: string;
-            /**
-                * The weight of the transform
-                */
-            transformWeight: number;
-            /**
-                * Color curve colorFilterHueGlobal value
-                */
-            colorFilterHueGlobal: number;
-            /**
-                * Color curve colorFilterHueShadows value
-                */
-            colorFilterHueShadows: number;
-            /**
-                * Color curve colorFilterHueMidtones value
-                */
-            colorFilterHueMidtones: number;
-            /**
-                * Color curve colorFilterHueHighlights value
-                */
-            colorFilterHueHighlights: number;
-            /**
-                * Color curve colorFilterDensityGlobal value
-                */
-            colorFilterDensityGlobal: number;
-            /**
-                * Color curve colorFilterDensityShadows value
-                */
-            colorFilterDensityShadows: number;
-            /**
-                * Color curve colorFilterDensityMidtones value
-                */
-            colorFilterDensityMidtones: number;
-            /**
-                * Color curve colorFilterDensityHighlights value
-                */
-            colorFilterDensityHighlights: number;
-            /**
-                * Color curve saturationGlobal value
-                */
-            saturationGlobal: number;
-            /**
-                * Color curve saturationShadows value
-                */
-            saturationShadows: number;
-            /**
-                * Color curve saturationMidtones value
-                */
-            saturationMidtones: number;
-            /**
-                * Color curve saturationHighlights value
-                */
-            saturationHighlights: number;
-            /**
-                * Color curve exposureGlobal value
-                */
-            exposureGlobal: number;
-            /**
-                * Color curve exposureShadows value
-                */
-            exposureShadows: number;
-            /**
-                * Color curve exposureMidtones value
-                */
-            exposureMidtones: number;
-            /**
-                * Color curve exposureHighlights value
-                */
-            exposureHighlights: number;
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/defaultRenderingPipelineConfiguration' {
-    import { DepthOfFieldEffectBlurLevel } from 'babylonjs';
-    export interface IDefaultRenderingPipelineConfiguration {
-        sharpenEnabled?: boolean;
-        bloomEnabled?: boolean;
-        bloomThreshold?: number;
-        depthOfFieldEnabled?: boolean;
-        depthOfFieldBlurLevel?: DepthOfFieldEffectBlurLevel;
-        fxaaEnabled?: boolean;
-        imageProcessingEnabled?: boolean;
-        defaultPipelineTextureType?: number;
-        bloomScale?: number;
-        chromaticAberrationEnabled?: boolean;
-        grainEnabled?: boolean;
-        bloomKernel?: number;
-        hardwareScaleLevel?: number;
-        bloomWeight?: number;
-        hdr?: boolean;
-        samples?: number;
-        glowLayerEnabled?: boolean;
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/groundConfiguration' {
-    export interface IGroundConfiguration {
-        size?: number;
-        receiveShadows?: boolean;
-        shadowLevel?: number;
-        shadowOnly?: boolean;
-        mirror?: boolean | {
-            sizeRatio?: number;
-            blurKernel?: number;
-            amount?: number;
-            fresnelWeight?: number;
-            fallOffDistance?: number;
-            textureType?: number;
-        };
-        texture?: string;
-        color?: {
-            r: number;
-            g: number;
-            b: number;
-        };
-        opacity?: number;
-        material?: {
-            [propName: string]: any;
-        };
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration' {
-    export interface IImageProcessingConfiguration {
-        colorGradingEnabled?: boolean;
-        colorCurvesEnabled?: boolean;
-        colorCurves?: {
-            globalHue?: number;
-            globalDensity?: number;
-            globalSaturation?: number;
-            globalExposure?: number;
-            highlightsHue?: number;
-            highlightsDensity?: number;
-            highlightsSaturation?: number;
-            highlightsExposure?: number;
-            midtonesHue?: number;
-            midtonesDensity?: number;
-            midtonesSaturation?: number;
-            midtonesExposure?: number;
-            shadowsHue?: number;
-            shadowsDensity?: number;
-            shadowsSaturation?: number;
-            shadowsExposure?: number;
-        };
-        colorGradingWithGreenDepth?: boolean;
-        colorGradingBGR?: boolean;
-        exposure?: number;
-        toneMappingEnabled?: boolean;
-        contrast?: number;
-        vignetteEnabled?: boolean;
-        vignetteStretch?: number;
-        vignetteCentreX?: number;
-        vignetteCentreY?: number;
-        vignetteWeight?: number;
-        vignetteColor?: {
-            r: number;
-            g: number;
-            b: number;
-            a?: number;
-        };
-        vignetteCameraFov?: number;
-        vignetteBlendMode?: number;
-        vignetteM?: boolean;
-        applyByPostProcess?: boolean;
-        isEnabled?: boolean;
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/lightConfiguration' {
-    export interface ILightConfiguration {
-        type: number;
-        name?: string;
-        disabled?: boolean;
-        position?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        target?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        direction?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        diffuse?: {
-            r: number;
-            g: number;
-            b: number;
-        };
-        specular?: {
-            r: number;
-            g: number;
-            b: number;
-        };
-        intensity?: number;
-        intensityMode?: number;
-        radius?: number;
-        shadownEnabled?: boolean;
-        shadowConfig?: {
-            useBlurExponentialShadowMap?: boolean;
-            useBlurCloseExponentialShadowMap?: boolean;
-            useKernelBlur?: boolean;
-            blurKernel?: number;
-            blurScale?: number;
-            minZ?: number;
-            maxZ?: number;
-            frustumSize?: number;
-            angleScale?: number;
-            frustumEdgeFalloff?: number;
-            [propName: string]: any;
-        };
-        spotAngle?: number;
-        shadowFieldOfView?: number;
-        shadowBufferSize?: number;
-        shadowFrustumSize?: number;
-        shadowMinZ?: number;
-        shadowMaxZ?: number;
-        [propName: string]: any;
-        behaviors?: {
-            [name: string]: number | {
-                type: number;
-                [propName: string]: any;
-            };
-        };
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/observersConfiguration' {
-    export interface IObserversConfiguration {
-        onEngineInit?: string;
-        onSceneInit?: string;
-        onModelLoaded?: string;
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/sceneConfiguration' {
-    import { IImageProcessingConfiguration } from "babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration";
-    import { IColorGradingConfiguration } from "babylonjs-viewer/configuration/interfaces/colorGradingConfiguration";
-    import { IGlowLayerOptions } from "babylonjs";
-    export interface ISceneConfiguration {
-            debug?: boolean;
-            clearColor?: {
-                    r: number;
-                    g: number;
-                    b: number;
-                    a: number;
-            };
-            /** Deprecated, use environmentMap.mainColor instead. */
-            mainColor?: {
-                    r?: number;
-                    g?: number;
-                    b?: number;
-            };
-            imageProcessingConfiguration?: IImageProcessingConfiguration;
-            environmentTexture?: string;
-            colorGrading?: IColorGradingConfiguration;
-            environmentRotationY?: number;
-            /**
-                * Deprecated, please use default rendering pipeline
-                */
-            glow?: boolean | IGlowLayerOptions;
-            disableHdr?: boolean;
-            renderInBackground?: boolean;
-            disableCameraControl?: boolean;
-            animationPropertiesOverride?: {
-                    [propName: string]: any;
-            };
-            defaultMaterial?: {
-                    materialType: "standard" | "pbr";
-                    [propName: string]: any;
-            };
-            flags?: {
-                    shadowsEnabled?: boolean;
-                    particlesEnabled?: boolean;
-                    collisionsEnabled?: boolean;
-                    lightsEnabled?: boolean;
-                    texturesEnabled?: boolean;
-                    lensFlaresEnabled?: boolean;
-                    proceduralTexturesEnabled?: boolean;
-                    renderTargetsEnabled?: boolean;
-                    spritesEnabled?: boolean;
-                    skeletonsEnabled?: boolean;
-                    audioEnabled?: boolean;
-            };
-            assetsRootURL?: string;
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/sceneOptimizerConfiguration' {
-    export interface ISceneOptimizerConfiguration {
-        targetFrameRate?: number;
-        trackerDuration?: number;
-        autoGeneratePriorities?: boolean;
-        improvementMode?: boolean;
-        degradation?: string;
-        types?: {
-            texture?: ISceneOptimizerParameters;
-            hardwareScaling?: ISceneOptimizerParameters;
-            shadow?: ISceneOptimizerParameters;
-            postProcess?: ISceneOptimizerParameters;
-            lensFlare?: ISceneOptimizerParameters;
-            particles?: ISceneOptimizerParameters;
-            renderTarget?: ISceneOptimizerParameters;
-            mergeMeshes?: ISceneOptimizerParameters;
-        };
-        custom?: string;
-    }
-    export interface ISceneOptimizerParameters {
-        priority?: number;
-        maximumSize?: number;
-        step?: number;
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration' {
-    import { IImageProcessingConfiguration } from "babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration";
-    export interface ISkyboxConfiguration {
-        cubeTexture?: {
-            noMipMap?: boolean;
-            gammaSpace?: boolean;
-            url?: string | Array<string>;
-        };
-        color?: {
-            r: number;
-            g: number;
-            b: number;
-        };
-        pbr?: boolean;
-        scale?: number;
-        blur?: number;
-        material?: {
-            imageProcessingConfiguration?: IImageProcessingConfiguration;
-            [propName: string]: any;
-        };
-        infiniteDistance?: boolean;
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/templateConfiguration' {
-    /**
-        * A single template configuration object
-        */
-    export interface ITemplateConfiguration {
-            /**
-                * can be either the id of the template's html element or a URL.
-                * See - http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
-                */
-            location?: string;
-            /**
-                * If no location is provided you can provide here the raw html of this template.
-                * See http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
-                */
-            html?: string;
-            id?: string;
-            /**
-                * Parameters that will be delivered to the template and will render it accordingly.
-                */
-            params?: {
-                    [key: string]: string | number | boolean | object;
-            };
-            /**
-                * Events to attach to this template.
-                * event name is the key. the value can either be a boolean (attach to the parent element)
-                * or a map of html id elements.
-                *
-                * See - http://doc.babylonjs.com/extensions/the_templating_system#event-binding
-                */
-            events?: {
-                    pointerdown?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerup?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointermove?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerover?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerout?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerenter?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointerleave?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    pointercancel?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    click?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    dragstart?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    drop?: boolean | {
-                            [id: string]: boolean;
-                    };
-                    [key: string]: boolean | {
-                            [id: string]: boolean;
-                    } | undefined;
-            };
-    }
-}
-
-declare module 'babylonjs-viewer/configuration/interfaces/vrConfiguration' {
-    import { VRExperienceHelperOptions } from "babylonjs";
-    export interface IVRConfiguration {
-        disabled?: boolean;
-        objectScaleFactor?: number;
-        disableInteractions?: boolean;
-        disableTeleportation?: boolean;
-        overrideFloorMeshName?: string;
-        vrOptions?: VRExperienceHelperOptions;
-        modelHeightCorrection?: number | boolean;
-        rotateUsingControllers?: boolean;
-        cameraPosition?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-    }
-}
-
 declare module 'babylonjs-viewer/labs/environmentSerializer' {
     import { Vector3 } from "babylonjs";
     import { TextureCube } from 'babylonjs-viewer/labs/texture';

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

@@ -17,6 +17,10 @@
 - Refactor of the SolidParticleSystem code for performance and code quality improvement ([barroij](https://github.com/barroij))
 - Added utility function `Tools.BuildArray` for array initialisation ([barroij](https://github.com/barroij))
 - Introduced a new `IOfflineSupport` interface to hide IndexedDB ([Deltakosh](https://github.com/deltakosh))
+- `PBRMaterial` and `StandardMaterial` now use hot swapping feature for shaders. This means they can keep using a previous shader while a new one is being compiled ([Deltakosh](https://github.com/deltakosh))
+- Performance oriented changes ([barroij](https://github.com/barroij))
+  - prevent avoidable matrix inversion or square root computation.
+  - enable a removal in O(1) from the `transformNodes`array of the Scene.
 
 ### glTF Loader
 

+ 3 - 1
gui/src/2D/controls/container.ts

@@ -266,7 +266,9 @@ export class Container extends Control {
         if (this._processMeasures(parentMeasure, context)) {
             this._localDraw(context);
 
-            this._clipForChildren(context);
+            if (this.clipChildren) {
+                this._clipForChildren(context);
+            }
 
             let computedWidth = -1;
             let computedHeight = -1;

+ 7 - 2
gui/src/2D/controls/control.ts

@@ -88,6 +88,9 @@ export class Control {
     /** Gets or sets a boolean indicating if the control can be focusable */
     public isFocusInvisible = false;
 
+    /** Gets or sets a boolean indicating if the children are clipped to the current control bounds */
+    public clipChildren = true;
+
     /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
     public shadowOffsetX = 0;
     /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */
@@ -1040,8 +1043,10 @@ export class Control {
         }
 
         // Clip
-        this._clip(context);
-        context.clip();
+        if (this.clipChildren) {
+            this._clip(context);
+            context.clip();
+        }
 
         return true;
     }

+ 4 - 3
src/Culling/babylon.boundingBox.ts

@@ -49,6 +49,7 @@
         public maximum: Vector3 = Vector3.Zero();
 
         private _worldMatrix: Matrix;
+        private static TmpVector3 = Tools.BuildArray(3, Vector3.Zero);
 
         /**
          * @hidden
@@ -89,8 +90,8 @@
             vectors[7].copyFromFloats(maxX, minY, maxZ);
 
             // OBB
-            this.maximum.addToRef(min, this.center).scaleInPlace(0.5);
-            this.maximum.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
+            max.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
 
             this._update(worldMatrix || this._worldMatrix || Matrix.Identity());
         }
@@ -101,7 +102,7 @@
          * @returns the current bounding box
          */
         public scale(factor: number): BoundingBox {
-            const tmpVectors = Tmp.Vector3;
+            const tmpVectors = BoundingBox.TmpVector3;
             const diff = this.maximum.subtractToRef(this.minimum, tmpVectors[0]);
             const len = diff.length();
             diff.normalizeFromLength(len);

+ 14 - 20
src/Culling/babylon.boundingSphere.ts

@@ -31,6 +31,8 @@ module BABYLON {
          */
         public maximum = Vector3.Zero();
 
+        private static TmpVector3 = Tools.BuildArray(3, Vector3.Zero);
+
         /**
          * Creates a new bounding sphere
          * @param min defines the minimum vector (in local space)
@@ -53,7 +55,7 @@ module BABYLON {
 
             var distance = Vector3.Distance(min, max);
 
-            Vector3.LerpToRef(min, max, 0.5, this.center);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
             this.radius = distance * 0.5;
 
             this._update(worldMatrix || _identityMatrix);
@@ -65,11 +67,11 @@ module BABYLON {
          * @returns the current bounding box
          */
         public scale(factor: number): BoundingSphere {
-            let newRadius = this.radius * factor;
-            const tmpVectors = Tmp.Vector3;
-            const tempRadiusVector = tmpVectors[0].copyFromFloats(newRadius, newRadius, newRadius);
-            let min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
-            let max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
+            const newRadius = this.radius * factor;
+            const tmpVectors = BoundingSphere.TmpVector3;
+            const tempRadiusVector = tmpVectors[0].setAll(newRadius);
+            const min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
+            const max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
 
             this.reConstruct(min, max);
 
@@ -80,7 +82,7 @@ module BABYLON {
         /** @hidden */
         public _update(world: Matrix): void {
             Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            const tempVector = Tmp.Vector3[0];
+            const tempVector = BoundingSphere.TmpVector3[0];
             Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, tempVector);
             this.radiusWorld = Math.max(Math.abs(tempVector.x), Math.abs(tempVector.y), Math.abs(tempVector.z)) * this.radius;
         }
@@ -106,13 +108,8 @@ module BABYLON {
          * @returns true if the point is inside the bounding sphere
          */
         public intersectsPoint(point: Vector3): boolean {
-            var x = this.centerWorld.x - point.x;
-            var y = this.centerWorld.y - point.y;
-            var z = this.centerWorld.z - point.z;
-
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-
-            if (this.radiusWorld < distance) {
+            const squareDistance = Vector3.DistanceSquared(this.centerWorld, point);
+            if (this.radiusWorld * this.radiusWorld < squareDistance) {
                 return false;
             }
 
@@ -127,13 +124,10 @@ module BABYLON {
          * @returns true if the speres intersect
          */
         public static Intersects(sphere0: BoundingSphere, sphere1: BoundingSphere): boolean {
-            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
-            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
-            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
-
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
+            const squareDistance = Vector3.DistanceSquared(sphere0.centerWorld, sphere1.centerWorld);
+            const radiusSum = sphere0.radiusWorld + sphere1.radiusWorld;
 
-            if (sphere0.radiusWorld + sphere1.radiusWorld < distance) {
+            if (radiusSum * radiusSum < squareDistance) {
                 return false;
             }
 

+ 18 - 11
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -861,13 +861,21 @@ module BABYLON {
             if (!engine.getCaps().standardDerivatives && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
                 mesh.createNormals(true);
                 Tools.Warn("PBRMaterial: Normals have been created for the mesh: " + mesh.name);
-                }
+            }
+
+            let previousEffect = subMesh.effect;
+            let effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances);
 
-            const effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances);
             if (effect) {
-                scene.resetCachedMaterial();
-                subMesh.setEffect(effect, defines);
-                this.buildUniformLayout();
+                // Use previous effect while new one is compiling
+                if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                    effect = previousEffect;
+                    defines.markAsUnprocessed();
+                } else {
+                    scene.resetCachedMaterial();
+                    subMesh.setEffect(effect, defines);
+                    this.buildUniformLayout();
+                }
             }
 
             if (!subMesh.effect || !subMesh.effect.isReady()) {
@@ -1134,10 +1142,10 @@ module BABYLON {
                             case Texture.CUBIC_MODE:
                             case Texture.INVCUBIC_MODE:
                             default:
-                                    defines.REFLECTIONMAP_CUBIC = true;
-                                    defines.USE_LOCAL_REFLECTIONMAP_CUBIC = (<any>reflectionTexture).boundingBoxSize ? true : false;
-                                    break;
-                            }
+                                defines.REFLECTIONMAP_CUBIC = true;
+                                defines.USE_LOCAL_REFLECTIONMAP_CUBIC = (<any>reflectionTexture).boundingBoxSize ? true : false;
+                                break;
+                        }
 
                         if (reflectionTexture.coordinatesMode !== Texture.SKYBOX_MODE) {
                             if (reflectionTexture.sphericalPolynomial) {
@@ -1424,8 +1432,7 @@ module BABYLON {
             this.bindOnlyWorldMatrix(world);
 
             // Normal Matrix
-            if (defines.OBJECTSPACE_NORMALMAP)
-            {
+            if (defines.OBJECTSPACE_NORMALMAP) {
                 world.toNormalMatrix(this._normalMatrix);
                 this.bindOnlyNormalMatrix(this._normalMatrix);
             }

+ 13 - 6
src/Materials/babylon.pushMaterial.ts

@@ -7,7 +7,14 @@ module BABYLON {
 
         protected _activeEffect: Effect;
 
-        protected _normalMatrix : Matrix = new Matrix();
+        protected _normalMatrix: Matrix = new Matrix();
+
+        /**
+         * Gets or sets a boolean indicating that the material is allowed to do shader hot swapping.
+         * This means that the material can keep using a previous shader while a new one is being compiled.
+         * This is mostly used when shader parallel compilation is supported (true by default)
+         */
+        public allowShaderHotSwapping = true;
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
@@ -30,11 +37,11 @@ module BABYLON {
             return this.isReadyForSubMesh(mesh, mesh.subMeshes[0], useInstances);
         }
 
-         /**
-         * Binds the given world matrix to the active effect
-         *
-         * @param world the matrix to bind
-         */
+        /**
+        * Binds the given world matrix to the active effect
+        *
+        * @param world the matrix to bind
+        */
         public bindOnlyWorldMatrix(world: Matrix): void {
             this._activeEffect.setMatrix("world", world);
         }

+ 19 - 9
src/Materials/babylon.standardMaterial.ts

@@ -839,9 +839,9 @@ module BABYLON {
                                 case Texture.CUBIC_MODE:
                                 case Texture.INVCUBIC_MODE:
                                 default:
-                                        defines.setReflectionMode("REFLECTIONMAP_CUBIC");
-                                        break;
-                                }
+                                    defines.setReflectionMode("REFLECTIONMAP_CUBIC");
+                                    break;
+                            }
 
                             defines.USE_LOCAL_REFLECTIONMAP_CUBIC = (<any>this._reflectionTexture).boundingBoxSize ? true : false;
                         }
@@ -983,7 +983,6 @@ module BABYLON {
             // Get correct effect
             if (defines.isDirty) {
                 defines.markAsProcessed();
-                scene.resetCachedMaterial();
 
                 // Fallbacks
                 var fallbacks = new EffectFallbacks();
@@ -1106,7 +1105,9 @@ module BABYLON {
                 }
 
                 var join = defines.toString();
-                subMesh.setEffect(scene.getEngine().createEffect(shaderName, <EffectCreationOptions>{
+
+                let previousEffect = subMesh.effect;
+                let effect = scene.getEngine().createEffect(shaderName, <EffectCreationOptions>{
                     attributes: attribs,
                     uniformsNames: uniforms,
                     uniformBuffersNames: uniformBuffers,
@@ -1116,9 +1117,19 @@ module BABYLON {
                     onCompiled: this.onCompiled,
                     onError: this.onError,
                     indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
-                }, engine), defines);
+                }, engine);
 
-                this.buildUniformLayout();
+                if (effect) {
+                    // Use previous effect while new one is compiling
+                    if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                        effect = previousEffect;
+                        defines.markAsUnprocessed();
+                    } else {
+                        scene.resetCachedMaterial();
+                        subMesh.setEffect(effect, defines);
+                        this.buildUniformLayout();
+                    }
+                }
             }
 
             if (!subMesh.effect || !subMesh.effect.isReady()) {
@@ -1225,8 +1236,7 @@ module BABYLON {
             this.bindOnlyWorldMatrix(world);
 
             // Normal Matrix
-            if (defines.OBJECTSPACE_NORMALMAP)
-            {
+            if (defines.OBJECTSPACE_NORMALMAP) {
                 world.toNormalMatrix(this._normalMatrix);
                 this.bindOnlyNormalMatrix(this._normalMatrix);
             }

+ 57 - 65
src/Mesh/babylon.transformNode.ts

@@ -93,6 +93,8 @@ module BABYLON {
 
         protected _isWorldMatrixFrozen = false;
 
+        /** @hidden */
+        public _indexInSceneTransformNodesArray = -1;
         /**
         * An event triggered after the world matrix is updated
         */
@@ -162,8 +164,8 @@ module BABYLON {
         public set rotationQuaternion(quaternion: Nullable<Quaternion>) {
             this._rotationQuaternion = quaternion;
             //reset the rotation vector.
-            if (quaternion && this.rotation.length()) {
-                this.rotation.copyFromFloats(0.0, 0.0, 0.0);
+            if (quaternion) {
+                this.rotation.setAll(0.0);
             }
         }
 
@@ -222,7 +224,7 @@ module BABYLON {
             }
 
             if (this.billboardMode !== this._cache.billboardMode || this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
-                return false;
+                return false;
             }
 
             if (this._cache.pivotMatrixUpdated) {
@@ -234,21 +236,21 @@ module BABYLON {
             }
 
             if (!this._cache.position.equals(this._position)) {
-                return false;
+                return false;
             }
 
             if (this._rotationQuaternion) {
                 if (!this._cache.rotationQuaternion.equals(this._rotationQuaternion)) {
-                    return false;
+                    return false;
                 }
             }
 
             if (!this._cache.rotation.equals(this._rotation)) {
-                return false;
+                return false;
             }
 
             if (!this._cache.scaling.equals(this._scaling)) {
-                return false;
+                return false;
             }
 
             return true;
@@ -304,7 +306,7 @@ module BABYLON {
          * @returns the current TransformNode
         */
         public setPivotMatrix(matrix: Matrix, postMultiplyPivotMatrix = true): TransformNode {
-            this._pivotMatrix = matrix.clone();
+            this._pivotMatrix.copyFrom(matrix);
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
 
@@ -391,10 +393,9 @@ module BABYLON {
                 absolutePositionZ = absolutePosition.z;
             }
             if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-                var worldPosition = new Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-                this.position = Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+                const invertParentWorldMatrix = Tmp.Matrix[0];
+                this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
+                Vector3.TransformCoordinatesFromFloatsToRef(absolutePositionX, absolutePositionY, absolutePositionZ, invertParentWorldMatrix, this.position);
             } else {
                 this.position.x = absolutePositionX;
                 this.position.y = absolutePositionY;
@@ -420,9 +421,8 @@ module BABYLON {
          */
         public getPositionExpressedInLocalSpace(): Vector3 {
             this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
-
+            const invLocalWorldMatrix = Tmp.Matrix[0];
+            this._localWorld.invertToRef(invLocalWorldMatrix);
             return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         }
 
@@ -571,34 +571,18 @@ module BABYLON {
             if (!node && !this.parent) {
                 return this;
             }
-            if (!node) {
-                var rotation = Tmp.Quaternion[0];
-                var position = Tmp.Vector3[0];
-                var scale = Tmp.Vector3[1];
 
+            var quatRotation = Tmp.Quaternion[0];
+            var position = Tmp.Vector3[0];
+            var scale = Tmp.Vector3[1];
+
+            if (!node) {
                 if (this.parent && this.parent.computeWorldMatrix) {
                     this.parent.computeWorldMatrix(true);
                 }
                 this.computeWorldMatrix(true);
-                this.getWorldMatrix().decompose(scale, rotation, position);
-
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                } else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
-
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                this.getWorldMatrix().decompose(scale, quatRotation, position);
             } else {
-                var rotation = Tmp.Quaternion[0];
-                var position = Tmp.Vector3[0];
-                var scale = Tmp.Vector3[1];
                 var diffMatrix = Tmp.Matrix[0];
                 var invParentMatrix = Tmp.Matrix[1];
 
@@ -607,23 +591,18 @@ module BABYLON {
 
                 node.getWorldMatrix().invertToRef(invParentMatrix);
                 this.getWorldMatrix().multiplyToRef(invParentMatrix, diffMatrix);
-                diffMatrix.decompose(scale, rotation, position);
-
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                } else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                diffMatrix.decompose(scale, quatRotation, position);
+            }
 
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(quatRotation);
+            } else {
+                quatRotation.toEulerAnglesToRef(this.rotation);
             }
 
+            this.scaling.copyFrom(scale);
+            this.position.copyFrom(position);
+
             this.parent = node;
             return this;
         }
@@ -693,8 +672,8 @@ module BABYLON {
         public rotate(axis: Vector3, amount: number, space?: Space): TransformNode {
             axis.normalize();
             if (!this.rotationQuaternion) {
-                this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = Vector3.Zero();
+                this.rotationQuaternion = this.rotation.toQuaternion();
+                this.rotation.setAll(0);
             }
             var rotationQuaternion: Quaternion;
             if (!space || (space as any) === Space.LOCAL) {
@@ -703,8 +682,8 @@ module BABYLON {
             }
             else {
                 if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
+                    const invertParentWorldMatrix = Tmp.Matrix[0];
+                    this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
                     axis = Vector3.TransformNormal(axis, invertParentWorldMatrix);
                 }
                 rotationQuaternion = Quaternion.RotationAxisToRef(axis, amount, TransformNode._rotationAxisCache);
@@ -727,19 +706,32 @@ module BABYLON {
             axis.normalize();
             if (!this.rotationQuaternion) {
                 this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation.copyFromFloats(0, 0, 0);
+                this.rotation.setAll(0);
             }
-            point.subtractToRef(this.position, Tmp.Vector3[0]);
-            Matrix.TranslationToRef(Tmp.Vector3[0].x, Tmp.Vector3[0].y, Tmp.Vector3[0].z, Tmp.Matrix[0]);
-            Tmp.Matrix[0].invertToRef(Tmp.Matrix[2]);
-            Matrix.RotationAxisToRef(axis, amount, Tmp.Matrix[1]);
-            Tmp.Matrix[2].multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[2]);
-            Tmp.Matrix[2].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[2]);
 
-            Tmp.Matrix[2].decompose(Tmp.Vector3[0], Tmp.Quaternion[0], Tmp.Vector3[1]);
+            const tmpVector = Tmp.Vector3[0];
+            const finalScale = Tmp.Vector3[1];
+            const finalTranslation = Tmp.Vector3[2];
+
+            const finalRotation = Tmp.Quaternion[0];
+
+            const translationMatrix = Tmp.Matrix[0]; // T
+            const translationMatrixInv = Tmp.Matrix[1]; // T'
+            const rotationMatrix = Tmp.Matrix[2]; // R
+            const finalMatrix = Tmp.Matrix[3]; // T' x R x T
+
+            point.subtractToRef(this.position, tmpVector);
+            Matrix.TranslationToRef(tmpVector.x, tmpVector.y, tmpVector.z, translationMatrix); // T
+            Matrix.TranslationToRef(-tmpVector.x, -tmpVector.y, -tmpVector.z, translationMatrixInv); // T'
+            Matrix.RotationAxisToRef(axis, amount, rotationMatrix); // R
+
+            translationMatrixInv.multiplyToRef(rotationMatrix, finalMatrix); // T' x R
+            finalMatrix.multiplyToRef(translationMatrix, finalMatrix);  // T' x R x T
+
+            finalMatrix.decompose(finalScale, finalRotation, finalTranslation);
 
-            this.position.addInPlace(Tmp.Vector3[1]);
-            Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+            this.position.addInPlace(finalTranslation);
+            finalRotation.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
 
             return this;
         }

+ 14 - 4
src/Particles/babylon.solidParticleSystem.ts

@@ -301,13 +301,23 @@ module BABYLON {
             var index = 0;
             var idx = 0;
             const tmpNormal = Tmp.Vector3[0];
-            const rotMatrix = Tmp.Matrix[0];
-            const invertedRotMatrix = Tmp.Matrix[1];
+            const quaternion = Tmp.Quaternion[0];
+            const invertedRotMatrix = Tmp.Matrix[0];
             for (var p = 0; p < this.particles.length; p++) {
                 const particle = this.particles[p];
                 const shape = particle._model._shape;
-                particle.getRotationMatrix(rotMatrix);
-                rotMatrix.invertToRef(invertedRotMatrix);
+
+                // computing the inverse of the rotation matrix from the quaternion
+                // is equivalent to computing the matrix of the inverse quaternion, i.e of the conjugate quaternion
+                if (particle.rotationQuaternion) {
+                    particle.rotationQuaternion.conjugateToRef(quaternion);
+                }
+                else {
+                    const rotation = particle.rotation;
+                    Quaternion.RotationYawPitchRollToRef(rotation.y, rotation.x, rotation.z, quaternion);
+                    quaternion.conjugateInPlace();
+                }
+                quaternion.toRotationMatrix(invertedRotMatrix);
 
                 for (var pt = 0; pt < shape.length; pt++) {
                     idx = index + pt * 3;

+ 3 - 0
src/babylon.abstractScene.ts

@@ -155,6 +155,9 @@ module BABYLON {
 
         /**
         * All of the tranform nodes added to this scene
+        * In the context a the Scene, it is not supposed to be modified manually.
+        * Any addition or removal should be done using the addTransformNode and removeTransformNode Scene methods.
+        * Note also that the order of the TransformNode wihin the array is not significant and might change.
         * @see http://doc.babylonjs.com/how_to/transformnode
         */
         public transformNodes = new Array<TransformNode>();

+ 10 - 3
src/babylon.scene.ts

@@ -3000,6 +3000,7 @@ module BABYLON {
          * @param newTransformNode defines the transform node to add
          */
         public addTransformNode(newTransformNode: TransformNode) {
+            newTransformNode._indexInSceneTransformNodesArray = this.transformNodes.length;
             this.transformNodes.push(newTransformNode);
 
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
@@ -3011,10 +3012,16 @@ module BABYLON {
          * @returns the index where the transform node was in the transform node list
          */
         public removeTransformNode(toRemove: TransformNode): number {
-            var index = this.transformNodes.indexOf(toRemove);
+            var index = toRemove._indexInSceneTransformNodesArray;
             if (index !== -1) {
-                // Remove from the scene if found
-                this.transformNodes.splice(index, 1);
+                if (index !== this.transformNodes.length - 1) {
+                    const lastNode = this.transformNodes[this.transformNodes.length - 1];
+                    this.transformNodes[index] = lastNode;
+                    lastNode._indexInSceneTransformNodesArray = index;
+                }
+
+                toRemove._indexInSceneTransformNodesArray = -1;
+                this.transformNodes.pop();
             }
 
             this.onTransformNodeRemovedObservable.notifyObservers(toRemove);

BIN
tests/validation/ReferenceImages/sps.png


+ 6 - 0
tests/validation/config.json

@@ -2,6 +2,12 @@
   "root": "https://rawgit.com/BabylonJS/Website/master",
   "tests": [
     {
+      "title": "Solid particle system",
+      "playgroundId": "#WCDZS#92",
+      "renderCount": 150,
+      "referenceImage": "sps.png"
+    },
+    {
       "title": "Simulate pointer",
       "playgroundId": "#8MGKWK#78",
       "referenceImage": "simulatePointer.png"

+ 19 - 18
tests/validation/validation.js

@@ -7,7 +7,7 @@ var config;
 var justOnce;
 
 var threshold = 25;
-var errorRatio = 2.5;
+var errorCountThreshold = 400;
 
 // Overload the random to make it deterministic
 var seed = 100000,
@@ -15,7 +15,7 @@ var seed = 100000,
     prime = 37,
     maximum = Math.pow(2, 50);
 
-Math.random = function () {
+Math.random = function() {
     seed *= constant;
     seed += prime;
     seed %= maximum;
@@ -49,9 +49,10 @@ function compare(renderData, referenceCanvas) {
     referenceContext.putImageData(referenceData, 0, 0);
 
     if (differencesCount) {
-        console.log("Pixel difference: " + differencesCount + " pixels.")
+        console.log("Pixel difference: " + differencesCount + " pixels.");
     }
-    return (differencesCount * 100) / (width * height) > errorRatio;
+
+    return differencesCount > errorCountThreshold;
 }
 
 function getRenderData(canvas, engine) {
@@ -137,12 +138,12 @@ function evaluate(test, resultCanvas, result, renderImage, index, waitRing, done
 function processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done) {
     currentScene.useConstantAnimationDeltaTime = true;
     var renderCount = test.renderCount || 1;
-   
-    currentScene.executeWhenReady(function () {
+
+    currentScene.executeWhenReady(function() {
         if (currentScene.activeCamera && currentScene.activeCamera.useAutoRotationBehavior) {
             currentScene.activeCamera.useAutoRotationBehavior = false;
         }
-        engine.runRenderLoop(function () {
+        engine.runRenderLoop(function() {
             try {
                 currentScene.render();
                 renderCount--;
@@ -199,7 +200,7 @@ function runTest(index, done) {
 
     var resultContext = resultCanvas.getContext("2d");
     var img = new Image();
-    img.onload = function () {
+    img.onload = function() {
         resultCanvas.width = img.width;
         resultCanvas.height = img.height;
         resultContext.drawImage(img, 0, 0);
@@ -214,12 +215,12 @@ function runTest(index, done) {
     location.href = "#" + container.id;
 
     if (test.sceneFolder) {
-        BABYLON.SceneLoader.Load(config.root + test.sceneFolder, test.sceneFilename, engine, function (newScene) {
+        BABYLON.SceneLoader.Load(config.root + test.sceneFolder, test.sceneFilename, engine, function(newScene) {
             currentScene = newScene;
             processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
         },
             null,
-            function (loadedScene, msg) {
+            function(loadedScene, msg) {
                 console.error(msg);
                 done(false);
             });
@@ -234,7 +235,7 @@ function runTest(index, done) {
         var snippetUrl = "//babylonjs-api2.azurewebsites.net/snippets";
         var pgRoot = "/Playground"
 
-        var retryTime = 30*1000;
+        var retryTime = 30 * 1000;
         var maxRetry = 2;
         var retry = 0;
 
@@ -253,7 +254,7 @@ function runTest(index, done) {
 
         var loadPG = function() {
             var xmlHttp = new XMLHttpRequest();
-            xmlHttp.onreadystatechange = function () {
+            xmlHttp.onreadystatechange = function() {
                 if (xmlHttp.readyState === 4) {
                     try {
                         xmlHttp.onreadystatechange = null;
@@ -265,16 +266,16 @@ function runTest(index, done) {
                         code = code.replace(/"scenes\//g, "\"" + pgRoot + "/scenes/");
                         currentScene = eval(code + "\r\ncreateScene(engine)");
 
-                        if(currentScene.then){
+                        if (currentScene.then) {
                             // Handle if createScene returns a promise
-                            currentScene.then(function(scene){
+                            currentScene.then(function(scene) {
                                 currentScene = scene;
                                 processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
-                            }).catch(function(e){
+                            }).catch(function(e) {
                                 console.error(e);
                                 onError();
                             })
-                        }else{
+                        } else {
                             // Handle if createScene returns a scene
                             processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
                         }
@@ -285,7 +286,7 @@ function runTest(index, done) {
                     }
                 }
             }
-            xmlHttp.onerror = function () {
+            xmlHttp.onerror = function() {
                 console.error("Network error during test load.");
                 onError();
             }
@@ -341,7 +342,7 @@ function runTest(index, done) {
                 }
             }
         };
-        request.onerror = function () {
+        request.onerror = function() {
             console.error("Network error during test load.");
             done(false);
         }