Browse Source

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

David 7 years ago
parent
commit
fd128f665a
58 changed files with 43350 additions and 35591 deletions
  1. 12022 10885
      Playground/babylon.d.txt
  2. 3 0
      Tools/Gulp/config.json
  3. 8 1
      Tools/Gulp/gulpfile.js
  4. 53 53
      Viewer/dist/viewer.js
  5. 53 53
      Viewer/dist/viewer.min.js
  6. 153 133
      Viewer/src/configuration/configuration.ts
  7. 32 174
      Viewer/src/viewer/defaultViewer.ts
  8. 493 155
      Viewer/src/viewer/viewer.ts
  9. 12431 11333
      dist/preview release/babylon.d.ts
  10. 48 48
      dist/preview release/babylon.js
  11. 1028 66
      dist/preview release/babylon.max.js
  12. 49 49
      dist/preview release/babylon.worker.js
  13. 11999 10901
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  14. 49 49
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  15. 1028 66
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  16. 1028 66
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  17. 1028 66
      dist/preview release/es6.js
  18. 3 3
      dist/preview release/gui/babylon.gui.min.js
  19. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  20. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  21. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  22. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  23. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  24. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  25. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  26. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  27. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  28. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  29. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  30. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  31. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  32. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  33. 249 0
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  34. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  35. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  36. 249 0
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  37. 2 1321
      dist/preview release/typedocValidationBaseline.json
  38. 53 53
      dist/preview release/viewer/babylon.viewer.js
  39. 8 3
      dist/preview release/what's new.md
  40. 111 2
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  41. 67 0
      src/Materials/PBR/babylon.pbrMaterial.ts
  42. 9 0
      src/Materials/PBR/babylon.pbrMetallicRoughnessMaterial.ts
  43. 9 0
      src/Materials/PBR/babylon.pbrSpecularGlossinessMaterial.ts
  44. 1 1
      src/Materials/Textures/babylon.mirrorTexture.ts
  45. 396 4
      src/Materials/babylon.effect.ts
  46. 474 6
      src/Materials/babylon.material.ts
  47. 1 1
      src/Mesh/babylon.mesh.ts
  48. 14 20
      src/Mesh/babylon.transformNode.ts
  49. 6 0
      src/Particles/babylon.solidParticle.ts
  50. 42 9
      src/Particles/babylon.solidParticleSystem.ts
  51. 2 2
      src/Physics/Plugins/babylon.cannonJSPlugin.ts
  52. 12 9
      src/PostProcess/babylon.postProcess.ts
  53. 93 19
      src/Tools/babylon.observable.ts
  54. 10 11
      src/babylon.assetContainer.ts
  55. BIN
      tests/validation/ReferenceImages/LightProjectionTexture.png
  56. BIN
      tests/validation/ReferenceImages/gltfMaterialSpecularGlossiness.png
  57. BIN
      tests/validation/ReferenceImages/gltfPrimitiveAttribute.png
  58. 5 0
      tests/validation/config.json

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


+ 3 - 0
Tools/Gulp/config.json

@@ -1527,6 +1527,9 @@
                     "../../serializers/src/glTF/2.0/babylon.glTFData.ts",
                     "../../serializers/src/glTF/2.0/babylon.glTFData.ts",
                     "../../serializers/src/glTF/2.0/babylon.glTFMaterial.ts"
                     "../../serializers/src/glTF/2.0/babylon.glTFMaterial.ts"
                 ],
                 ],
+                "extraDeclarations": [
+                    "../../dist/babylon.glTF2Interface.d.ts"
+                ],
                 "output": "babylon.glTF2Serializer.js"
                 "output": "babylon.glTF2Serializer.js"
             }
             }
         ],
         ],

+ 8 - 1
Tools/Gulp/gulpfile.js

@@ -405,7 +405,14 @@ var buildExternalLibrary = function (library, settings, watch) {
             .pipe(gulp.dest(outputDirectory));
             .pipe(gulp.dest(outputDirectory));
         /*}*/
         /*}*/
 
 
-        var dts = tsProcess.dts
+        let preDts;
+        if (library.extraDeclarations) {
+            preDts = merge2([tsProcess.dts, gulp.src(library.extraDeclarations)])
+        } else {
+            preDts = tsProcess.dts;
+        }
+
+        var dts = preDts
             .pipe(concat(library.output))
             .pipe(concat(library.output))
             .pipe(replace(referenceSearchRegex, ""))
             .pipe(replace(referenceSearchRegex, ""))
             .pipe(rename({ extname: ".d.ts" }))
             .pipe(rename({ extname: ".d.ts" }))

File diff suppressed because it is too large
+ 53 - 53
Viewer/dist/viewer.js


File diff suppressed because it is too large
+ 53 - 53
Viewer/dist/viewer.min.js


+ 153 - 133
Viewer/src/configuration/configuration.ts

@@ -15,143 +15,20 @@ export interface ViewerConfiguration {
     };
     };
 
 
     // names of functions in the window context.
     // names of functions in the window context.
-    observers?: {
-        onEngineInit?: string;
-        onSceneInit?: string;
-        onModelLoaded?: string;
-    }
+    observers?: IObserversConfiguration;
 
 
     canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
     canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
 
 
-    model?: {
-        url?: string;
-        loader?: string; // obj, gltf?
-        position?: { x: number, y: number, z: number };
-        rotation?: { x: number, y: number, z: number, w: number };
-        scaling?: { x: number, y: number, z: number };
-        parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
-
-        title: string;
-        subtitle?: string;
-        thumbnail?: string; // URL or data-url
-
-        [propName: string]: any; // further configuration, like title and creator
-    } | string;
-
-    scene?: {
-        debug?: boolean;
-        autoRotate?: boolean;
-        rotationSpeed?: number;
-        defaultCamera?: boolean;
-        defaultLight?: boolean;
-        clearColor?: { r: number, g: number, b: number, a: number };
-        imageProcessingConfiguration?: IImageProcessingConfiguration;
-        environmentTexture?: string;
-    },
-    optimizer?: {
-        targetFrameRate?: number;
-        trackerDuration?: number;
-        autoGeneratePriorities?: boolean;
-        improvementMode?: boolean;
-        degradation?: string; // low, moderate, high
-        types?: {
-            texture?: SceneOptimizerParameters;
-            hardwareScaling?: SceneOptimizerParameters;
-            shadow?: SceneOptimizerParameters;
-            postProcess?: SceneOptimizerParameters;
-            lensFlare?: SceneOptimizerParameters;
-            particles?: SceneOptimizerParameters;
-            renderTarget?: SceneOptimizerParameters;
-            mergeMeshes?: SceneOptimizerParameters;
-        }
-    },
-    // at the moment, support only a single camera.
-    camera?: {
-        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;
-        behaviors?: {
-            [name: string]: number | {
-                type: number;
-                [propName: string]: any;
-            };
-        };
-
-        [propName: string]: any;
-    },
-    skybox?: {
-        cubeTexture?: {
-            noMipMap?: boolean;
-            gammaSpace?: boolean;
-            url?: string | Array<string>;
-        };
-        color?: { r: number, g: number, b: number };
-        pbr?: boolean; // deprecated
-        scale?: number;
-        blur?: number; // deprecated
-        material?: {
-            imageProcessingConfiguration?: IImageProcessingConfiguration;
-        };
-        infiniteDIstance?: boolean;
-
-    };
-
-    ground?: boolean | {
-        size?: number;
-        receiveShadows?: boolean;
-        shadowLevel?: number;
-        shadowOnly?: boolean; // deprecated
-        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?: { // deprecated!
-            [propName: string]: any;
-        };
+    model?: IModelConfiguration | string;
 
 
-    };
-    lights?: {
-        [name: string]: {
-            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;
-            radius?: number;
-            shadownEnabled?: boolean; // only on specific lights!
-            shadowConfig?: {
-                useBlurExponentialShadowMap?: boolean;
-                useKernelBlur?: boolean;
-                blurKernel?: number;
-                blurScale?: number;
-                [propName: string]: any;
-            }
-            [propName: string]: any;
+    scene?: ISceneConfiguration;
+    optimizer?: ISceneOptimizerConfiguration | boolean;
+    // at the moment, support only a single camera.
+    camera?: ICameraConfiguration,
+    skybox?: boolean | ISkyboxConfiguration;
 
 
-            // no behaviors for light at the moment, but allowing configuration for future reference.
-            behaviors?: {
-                [name: string]: number | {
-                    type: number;
-                    [propName: string]: any;
-                };
-            };
-        }
-    },
+    ground?: boolean | IGroundConfiguration;
+    lights?: { [name: string]: boolean | ILightConfiguration },
     // engine configuration. optional!
     // engine configuration. optional!
     engine?: {
     engine?: {
         antialiasing?: boolean;
         antialiasing?: boolean;
@@ -189,7 +66,150 @@ export interface ViewerConfiguration {
     }
     }
 }
 }
 
 
-export interface SceneOptimizerParameters {
+export interface IModelConfiguration {
+    url: string;
+    loader?: string; // obj, gltf?
+    position?: { x: number, y: number, z: number };
+    rotation?: { x: number, y: number, z: number, w?: number };
+    scaling?: { x: number, y: number, z: number };
+    parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
+
+    castShadow?: boolean;
+
+    title: string;
+    subtitle?: string;
+    thumbnail?: string; // URL or data-url
+
+    // [propName: string]: any; // further configuration, like title and creator
+}
+
+export interface ISkyboxConfiguration {
+    cubeTexture?: {
+        noMipMap?: boolean;
+        gammaSpace?: boolean;
+        url?: string | Array<string>;
+    };
+    color?: { r: number, g: number, b: number };
+    pbr?: boolean; // deprecated
+    scale?: number;
+    blur?: number; // deprecated
+    material?: {
+        imageProcessingConfiguration?: IImageProcessingConfiguration;
+    };
+    infiniteDIstance?: boolean;
+
+}
+
+export interface IGroundConfiguration {
+    size?: number;
+    receiveShadows?: boolean;
+    shadowLevel?: number;
+    shadowOnly?: boolean; // deprecated
+    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?: { // deprecated!
+        [propName: string]: any;
+    };
+}
+
+export interface ISceneConfiguration {
+    debug?: boolean;
+    autoRotate?: boolean; // deprecated
+    rotationSpeed?: number; // deprecated
+    defaultCamera?: boolean; // deprecated
+    defaultLight?: boolean; // deprecated
+    clearColor?: { r: number, g: number, b: number, a: number };
+    imageProcessingConfiguration?: IImageProcessingConfiguration;
+    environmentTexture?: string;
+}
+
+export interface ISceneOptimizerConfiguration {
+    targetFrameRate?: number;
+    trackerDuration?: number;
+    autoGeneratePriorities?: boolean;
+    improvementMode?: boolean;
+    degradation?: string; // low, moderate, high
+    types?: {
+        texture?: ISceneOptimizerParameters;
+        hardwareScaling?: ISceneOptimizerParameters;
+        shadow?: ISceneOptimizerParameters;
+        postProcess?: ISceneOptimizerParameters;
+        lensFlare?: ISceneOptimizerParameters;
+        particles?: ISceneOptimizerParameters;
+        renderTarget?: ISceneOptimizerParameters;
+        mergeMeshes?: ISceneOptimizerParameters;
+    }
+}
+
+export interface IObserversConfiguration {
+    onEngineInit?: string;
+    onSceneInit?: string;
+    onModelLoaded?: string;
+}
+
+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;
+    behaviors?: {
+        [name: string]: number | {
+            type: number;
+            [propName: string]: any;
+        };
+    };
+
+    [propName: string]: any;
+}
+
+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; // only on specific lights!
+    shadowConfig?: {
+        useBlurExponentialShadowMap?: boolean;
+        useKernelBlur?: boolean;
+        blurKernel?: number;
+        blurScale?: number;
+        minZ?: number;
+        maxZ?: number;
+        frustumSize?: number;
+        angleScale?: number;
+        [propName: string]: any;
+    }
+    [propName: string]: any;
+
+    // no behaviors for light at the moment, but allowing configuration for future reference.
+    behaviors?: {
+        [name: string]: number | {
+            type: number;
+            [propName: string]: any;
+        };
+    };
+}
+
+export interface ISceneOptimizerParameters {
     priority?: number;
     priority?: number;
     maximumSize?: number;
     maximumSize?: number;
     step?: number;
     step?: number;

+ 32 - 174
Viewer/src/viewer/defaultViewer.ts

@@ -1,6 +1,6 @@
 
 
 
 
-import { ViewerConfiguration } from './../configuration/configuration';
+import { ViewerConfiguration, IModelConfiguration, ILightConfiguration } from './../configuration/configuration';
 import { Template, EventCallback } from './../templateManager';
 import { Template, EventCallback } from './../templateManager';
 import { AbstractViewer } from './viewer';
 import { AbstractViewer } from './viewer';
 import { SpotLight, MirrorTexture, Plane, ShadowGenerator, Texture, BackgroundMaterial, Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
 import { SpotLight, MirrorTexture, Plane, ShadowGenerator, Texture, BackgroundMaterial, Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
@@ -8,8 +8,6 @@ import { CameraBehavior } from '../interfaces';
 
 
 export class DefaultViewer extends AbstractViewer {
 export class DefaultViewer extends AbstractViewer {
 
 
-    public camera: ArcRotateCamera;
-
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = { extends: 'default' }) {
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = { extends: 'default' }) {
         super(containerElement, initialConfiguration);
         super(containerElement, initialConfiguration);
         this.onModelLoadedObservable.add(this.onModelLoaded);
         this.onModelLoadedObservable.add(this.onModelLoaded);
@@ -105,6 +103,34 @@ export class DefaultViewer extends AbstractViewer {
         this.containerElement.style.display = 'flex';
         this.containerElement.style.display = 'flex';
     }
     }
 
 
+    protected configureModel(modelConfiguration: Partial<IModelConfiguration>) {
+        super.configureModel(modelConfiguration);
+
+        let navbar = this.templateManager.getTemplate('navBar');
+        if (!navbar) return;
+
+        let metadataContainer = navbar.parent.querySelector('#model-metadata');
+        if (metadataContainer) {
+            if (modelConfiguration.title !== undefined) {
+                let element = metadataContainer.querySelector('span.model-title');
+                if (element) {
+                    element.innerHTML = modelConfiguration.title;
+                }
+            }
+
+            if (modelConfiguration.subtitle !== undefined) {
+                let element = metadataContainer.querySelector('span.model-subtitle');
+                if (element) {
+                    element.innerHTML = modelConfiguration.subtitle;
+                }
+            }
+
+            if (modelConfiguration.thumbnail !== undefined) {
+                (<HTMLDivElement>metadataContainer.querySelector('.thumbnail')).style.backgroundImage = `url('${modelConfiguration.thumbnail}')`;
+            }
+        }
+    }
+
     public loadModel(model: any = this.configuration.model): Promise<Scene> {
     public loadModel(model: any = this.configuration.model): Promise<Scene> {
         this.showLoadingScreen();
         this.showLoadingScreen();
         return super.loadModel(model, true).catch((error) => {
         return super.loadModel(model, true).catch((error) => {
@@ -116,10 +142,6 @@ export class DefaultViewer extends AbstractViewer {
     }
     }
 
 
     private onModelLoaded = (meshes: Array<AbstractMesh>) => {
     private onModelLoaded = (meshes: Array<AbstractMesh>) => {
-
-        // here we could set the navbar's model information:
-        this.setModelMetaData();
-
         // with a short timeout, making sure everything is there already.
         // with a short timeout, making sure everything is there already.
         let hideLoadingDelay = 500;
         let hideLoadingDelay = 500;
         if (this.configuration.lab && this.configuration.lab.hideLoadingDelay !== undefined) {
         if (this.configuration.lab && this.configuration.lab.hideLoadingDelay !== undefined) {
@@ -129,48 +151,11 @@ export class DefaultViewer extends AbstractViewer {
             this.hideLoadingScreen();
             this.hideLoadingScreen();
         }, hideLoadingDelay);
         }, hideLoadingDelay);
 
 
-
-        // recreate the camera
-        this.scene.createDefaultCameraOrLight(true, true, true);
-        this.camera = <ArcRotateCamera>this.scene.activeCamera;
-
         meshes[0].rotation.y += Math.PI;
         meshes[0].rotation.y += Math.PI;
 
 
-        this.setupCamera(meshes);
-        this.setupLights(meshes);
-
         return; //this.initEnvironment(meshes);
         return; //this.initEnvironment(meshes);
     }
     }
 
 
-    private setModelMetaData() {
-        let navbar = this.templateManager.getTemplate('navBar');
-        if (!navbar) return;
-
-        let metadataContainer = navbar.parent.querySelector('#model-metadata');
-
-        //title
-        if (metadataContainer && typeof this.configuration.model === 'object') {
-            if (this.configuration.model.title) {
-                let element = metadataContainer.querySelector('span.model-title');
-                if (element) {
-                    element.innerHTML = this.configuration.model.title;
-                }
-            }
-
-            if (this.configuration.model.subtitle) {
-                let element = metadataContainer.querySelector('span.model-subtitle');
-                if (element) {
-                    element.innerHTML = this.configuration.model.subtitle;
-                }
-            }
-
-            if (this.configuration.model.thumbnail) {
-                (<HTMLDivElement>metadataContainer.querySelector('.thumbnail')).style.backgroundImage = `url('${this.configuration.model.thumbnail}')`;
-            }
-        }
-
-    }
-
     /*protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
     /*protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
         if (this.configuration.skybox) {
         if (this.configuration.skybox) {
             // Define a general environment textue
             // Define a general environment textue
@@ -360,10 +345,9 @@ export class DefaultViewer extends AbstractViewer {
         }));
         }));
     }
     }
 
 
-    private setupLights(focusMeshes: Array<AbstractMesh> = []) {
-
-        let sceneConfig = this.configuration.scene || { defaultLight: true };
-
+    protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        super.configureLights(lightsConfiguration, focusMeshes);
+        console.log("flashlight", this.configuration.lab);
         // labs feature - flashlight
         // labs feature - flashlight
         if (this.configuration.lab && this.configuration.lab.flashlight) {
         if (this.configuration.lab && this.configuration.lab.flashlight) {
             let pointerPosition = BABYLON.Vector3.Zero();
             let pointerPosition = BABYLON.Vector3.Zero();
@@ -409,131 +393,5 @@ export class DefaultViewer extends AbstractViewer {
             this.scene.registerBeforeRender(updateFlashlightFunction);
             this.scene.registerBeforeRender(updateFlashlightFunction);
             this.registeredOnBeforerenderFunctions.push(updateFlashlightFunction);
             this.registeredOnBeforerenderFunctions.push(updateFlashlightFunction);
         }
         }
-
-        if (!sceneConfig.defaultLight && (this.configuration.lights && Object.keys(this.configuration.lights).length)) {
-            // remove old lights
-            this.scene.lights.forEach(l => {
-                l.dispose();
-            });
-
-            Object.keys(this.configuration.lights).forEach((name, idx) => {
-                let lightConfig = this.configuration.lights && this.configuration.lights[name] || { name: name, type: 0 };
-                lightConfig.name = name;
-                let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
-                if (!constructor) return;
-                let light = constructor();
-
-                //enabled
-                if (light.isEnabled() !== !lightConfig.disabled) {
-                    light.setEnabled(!lightConfig.disabled);
-                }
-
-                this.extendClassWithConfig(light, lightConfig);
-
-                //position. Some lights don't support shadows
-                if (light instanceof ShadowLight) {
-                    if (lightConfig.shadowEnabled && this.maxShadows) {
-                        var shadowGenerator = new ShadowGenerator(512, light);
-                        this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
-                        // add the focues meshes to the shadow list
-                        let shadownMap = shadowGenerator.getShadowMap();
-                        if (!shadownMap) return;
-                        let renderList = shadownMap.renderList;
-                        for (var index = 0; index < focusMeshes.length; index++) {
-                            renderList && renderList.push(focusMeshes[index]);
-                        }
-                    }
-                }
-            });
-        }
-    }
-
-    private setupCamera(focusMeshes: Array<AbstractMesh> = []) {
-
-        let cameraConfig = this.configuration.camera || {};
-        let sceneConfig = this.configuration.scene || { autoRotate: false, defaultCamera: true };
-
-        if (!this.configuration.camera && sceneConfig.defaultCamera) {
-            if (sceneConfig.autoRotate) {
-                this.camera.useAutoRotationBehavior = true;
-            }
-            return;
-        }
-
-        if (cameraConfig.position) {
-            this.camera.position.copyFromFloats(cameraConfig.position.x || 0, cameraConfig.position.y || 0, cameraConfig.position.z || 0);
-        }
-
-        if (cameraConfig.rotation) {
-            this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
-        }
-
-        this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
-        this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
-
-        if (cameraConfig.behaviors) {
-            for (let name in cameraConfig.behaviors) {
-                this.setCameraBehavior(cameraConfig.behaviors[name], focusMeshes);
-            }
-        };
-
-        if (sceneConfig.autoRotate) {
-            this.camera.useAutoRotationBehavior = true;
-        }
-
-        const sceneExtends = this.scene.getWorldExtends();
-        const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
-        const sceneDiagonalLenght = sceneDiagonal.length();
-        this.camera.upperRadiusLimit = sceneDiagonalLenght * 3;
-    }
-
-    private setCameraBehavior(behaviorConfig: number | {
-        type: number;
-        [propName: string]: any;
-    }, payload: any) {
-
-        let behavior: Behavior<ArcRotateCamera> | null;
-        let type = (typeof behaviorConfig !== "object") ? behaviorConfig : behaviorConfig.type;
-
-        let config: { [propName: string]: any } = (typeof behaviorConfig === "object") ? behaviorConfig : {};
-
-        // constructing behavior
-        switch (type) {
-            case CameraBehavior.AUTOROTATION:
-                behavior = new AutoRotationBehavior();
-                break;
-            case CameraBehavior.BOUNCING:
-                behavior = new BouncingBehavior();
-                break;
-            case CameraBehavior.FRAMING:
-                behavior = new FramingBehavior();
-                break;
-            default:
-                behavior = null;
-                break;
-        }
-
-        if (behavior) {
-            if (typeof behaviorConfig === "object") {
-                this.extendClassWithConfig(behavior, behaviorConfig);
-            }
-            this.camera.addBehavior(behavior);
-        }
-
-        // post attach configuration. Some functionalities require the attached camera.
-        switch (type) {
-            case CameraBehavior.AUTOROTATION:
-                break;
-            case CameraBehavior.BOUNCING:
-                break;
-            case CameraBehavior.FRAMING:
-                if (config.zoomOnBoundingInfo) {
-                    //payload is an array of meshes
-                    let meshes = <Array<AbstractMesh>>payload;
-                    let bounding = meshes[0].getHierarchyBoundingVectors();
-                    (<FramingBehavior>behavior).zoomOnBoundingInfo(bounding.min, bounding.max);
-                }
-                break;
-        }
     }
     }
 }
 }

+ 493 - 155
Viewer/src/viewer/viewer.ts

@@ -1,8 +1,11 @@
 import { viewerManager } from './viewerManager';
 import { viewerManager } from './viewerManager';
 import { TemplateManager } from './../templateManager';
 import { TemplateManager } from './../templateManager';
 import configurationLoader from './../configuration/loader';
 import configurationLoader from './../configuration/loader';
-import { CubeTexture, Color3, IEnvironmentHelperOptions, EnvironmentHelper, Effect, SceneOptimizer, SceneOptimizerOptions, Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database, SceneLoaderProgressEvent, ISceneLoaderPlugin, ISceneLoaderPluginAsync } from 'babylonjs';
-import { ViewerConfiguration } from '../configuration/configuration';
+import { CubeTexture, Color3, IEnvironmentHelperOptions, EnvironmentHelper, Effect, SceneOptimizer, SceneOptimizerOptions, Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database, SceneLoaderProgressEvent, ISceneLoaderPlugin, ISceneLoaderPluginAsync, Quaternion, Light, ShadowLight, ShadowGenerator, Tags, AutoRotationBehavior, BouncingBehavior, FramingBehavior, Behavior } from 'babylonjs';
+import { ViewerConfiguration, ISceneConfiguration, ISceneOptimizerConfiguration, IObserversConfiguration, IModelConfiguration, ISkyboxConfiguration, IGroundConfiguration, ILightConfiguration, ICameraConfiguration } from '../configuration/configuration';
+
+import * as deepmerge from '../../assets/deepmerge.min.js';
+import { CameraBehavior } from 'src/interfaces';
 
 
 export abstract class AbstractViewer {
 export abstract class AbstractViewer {
 
 
@@ -10,6 +13,7 @@ export abstract class AbstractViewer {
 
 
     public engine: Engine;
     public engine: Engine;
     public scene: Scene;
     public scene: Scene;
+    public camera: ArcRotateCamera;
     public sceneOptimizer: SceneOptimizer;
     public sceneOptimizer: SceneOptimizer;
     public baseId: string;
     public baseId: string;
 
 
@@ -35,6 +39,7 @@ export abstract class AbstractViewer {
     public onEngineInitObservable: Observable<Engine>;
     public onEngineInitObservable: Observable<Engine>;
     public onModelLoadedObservable: Observable<AbstractMesh[]>;
     public onModelLoadedObservable: Observable<AbstractMesh[]>;
     public onModelLoadProgressObservable: Observable<SceneLoaderProgressEvent>;
     public onModelLoadProgressObservable: Observable<SceneLoaderProgressEvent>;
+    public onModelLoadErrorObservable: Observable<{ message: string; exception: any }>;
     public onLoaderInitObservable: Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
     public onLoaderInitObservable: Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
     public onInitDoneObservable: Observable<AbstractViewer>;
     public onInitDoneObservable: Observable<AbstractViewer>;
 
 
@@ -54,6 +59,7 @@ export abstract class AbstractViewer {
         this.onEngineInitObservable = new Observable();
         this.onEngineInitObservable = new Observable();
         this.onModelLoadedObservable = new Observable();
         this.onModelLoadedObservable = new Observable();
         this.onModelLoadProgressObservable = new Observable();
         this.onModelLoadProgressObservable = new Observable();
+        this.onModelLoadErrorObservable = new Observable();
         this.onInitDoneObservable = new Observable();
         this.onInitDoneObservable = new Observable();
         this.onLoaderInitObservable = new Observable();
         this.onLoaderInitObservable = new Observable();
 
 
@@ -70,19 +76,10 @@ export abstract class AbstractViewer {
         // extend the configuration
         // extend the configuration
         configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
         configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
             this.configuration = configuration;
             this.configuration = configuration;
-
-            // adding preconfigured functions
             if (this.configuration.observers) {
             if (this.configuration.observers) {
-                if (this.configuration.observers.onEngineInit) {
-                    this.onEngineInitObservable.add(window[this.configuration.observers.onEngineInit]);
-                }
-                if (this.configuration.observers.onSceneInit) {
-                    this.onSceneInitObservable.add(window[this.configuration.observers.onSceneInit]);
-                }
-                if (this.configuration.observers.onModelLoaded) {
-                    this.onModelLoadedObservable.add(window[this.configuration.observers.onModelLoaded]);
-                }
+                this.configureObservers(this.configuration.observers);
             }
             }
+            //this.updateConfiguration(configuration);
 
 
             // initialize the templates
             // initialize the templates
             let templateConfiguration = this.configuration.templates || {};
             let templateConfiguration = this.configuration.templates || {};
@@ -123,7 +120,415 @@ export abstract class AbstractViewer {
     }
     }
 
 
     protected render = (): void => {
     protected render = (): void => {
-        this.scene && this.scene.render();
+        this.scene && this.scene.activeCamera && this.scene.render();
+    }
+
+    /**
+     * Update the current viewer configuration with new values.
+     * Only provided information will be updated, old configuration values will be kept.
+     * If this.configuration was manually changed, you can trigger this function with no parameters, 
+     * and the entire configuration will be updated. 
+     * @param newConfiguration 
+     */
+    public updateConfiguration(newConfiguration: Partial<ViewerConfiguration> = this.configuration) {
+        // update scene configuration
+        if (newConfiguration.scene) {
+            this.configureScene(newConfiguration.scene);
+        }
+        // optimizer
+        if (newConfiguration.optimizer) {
+            this.configureOptimizer(newConfiguration.optimizer);
+        }
+
+        // observers in configuration
+        if (newConfiguration.observers) {
+            this.configureObservers(newConfiguration.observers);
+        }
+
+        // configure model
+        if (newConfiguration.model && typeof newConfiguration.model === 'object') {
+            this.configureModel(newConfiguration.model);
+        }
+
+        // lights
+        if (newConfiguration.lights) {
+            this.configureLights(newConfiguration.lights);
+        }
+
+        // environment
+        if (newConfiguration.skybox !== undefined || newConfiguration.ground !== undefined) {
+            this.configureEnvironment(newConfiguration.skybox, newConfiguration.ground);
+        }
+
+        // update this.configuration with the new data
+        this.configuration = deepmerge(this.configuration || {}, newConfiguration);
+    }
+
+    protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean) {
+        if (!skyboxConifguration && !groundConfiguration) {
+            if (this.environmentHelper) {
+                this.environmentHelper.dispose();
+            };
+            return Promise.resolve(this.scene);
+        }
+
+        const options: Partial<IEnvironmentHelperOptions> = {
+            createGround: !!groundConfiguration,
+            createSkybox: !!skyboxConifguration,
+            setupImageProcessing: false // will be done at the scene level!
+        };
+
+        if (groundConfiguration) {
+            let groundConfig = (typeof groundConfiguration === 'boolean') ? {} : groundConfiguration;
+
+            let groundSize = groundConfig.size || (typeof skyboxConifguration === 'object' && skyboxConifguration.scale);
+            if (groundSize) {
+                options.groundSize = groundSize;
+            }
+
+            options.enableGroundShadow = groundConfig === true || groundConfig.receiveShadows;
+            if (groundConfig.shadowLevel) {
+                options.groundShadowLevel = groundConfig.shadowLevel;
+            }
+            options.enableGroundMirror = !!groundConfig.mirror;
+            if (groundConfig.texture) {
+                options.groundTexture = groundConfig.texture;
+            }
+            if (groundConfig.color) {
+                options.groundColor = new Color3(groundConfig.color.r, groundConfig.color.g, groundConfig.color.b)
+            }
+
+            if (groundConfig.mirror) {
+                options.enableGroundMirror = true;
+                // to prevent undefines
+                if (typeof groundConfig.mirror === "object") {
+                    if (groundConfig.mirror.amount)
+                        options.groundMirrorAmount = groundConfig.mirror.amount;
+                    if (groundConfig.mirror.sizeRatio)
+                        options.groundMirrorSizeRatio = groundConfig.mirror.sizeRatio;
+                    if (groundConfig.mirror.blurKernel)
+                        options.groundMirrorBlurKernel = groundConfig.mirror.blurKernel;
+                    if (groundConfig.mirror.fresnelWeight)
+                        options.groundMirrorFresnelWeight = groundConfig.mirror.fresnelWeight;
+                    if (groundConfig.mirror.fallOffDistance)
+                        options.groundMirrorFallOffDistance = groundConfig.mirror.fallOffDistance;
+                    if (this.defaultHighpTextureType !== undefined)
+                        options.groundMirrorTextureType = this.defaultHighpTextureType;
+                }
+            }
+
+        }
+
+        let postInitSkyboxMaterial = false;
+        if (skyboxConifguration) {
+            let conf = skyboxConifguration === true ? {} : skyboxConifguration;
+            if (conf.material && conf.material.imageProcessingConfiguration) {
+                options.setupImageProcessing = false; // will be configured later manually.
+            }
+            let skyboxSize = conf.scale;
+            if (skyboxSize) {
+                options.skyboxSize = skyboxSize;
+            }
+            options.sizeAuto = !options.skyboxSize;
+            if (conf.color) {
+                options.skyboxColor = new Color3(conf.color.r, conf.color.g, conf.color.b)
+            }
+            if (conf.cubeTexture && conf.cubeTexture.url) {
+                if (typeof conf.cubeTexture.url === "string") {
+                    options.skyboxTexture = conf.cubeTexture.url;
+                } else {
+                    // init later!
+                    postInitSkyboxMaterial = true;
+                }
+            }
+
+            if (conf.material && conf.material.imageProcessingConfiguration) {
+                postInitSkyboxMaterial = true;
+            }
+        }
+
+        if (!this.environmentHelper) {
+            this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
+        } else {
+            // there might be a new scene! we need to dispose.
+
+            // get the scene used by the envHelper
+            let scene: Scene = this.environmentHelper.rootMesh.getScene();
+            // is it a different scene? Oh no!
+            if (scene !== this.scene) {
+                this.environmentHelper.dispose();
+                this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
+            } else {
+                this.environmentHelper.updateOptions(options)!;
+            }
+        }
+
+        if (postInitSkyboxMaterial) {
+            let skyboxMaterial = this.environmentHelper.skyboxMaterial;
+            if (skyboxMaterial) {
+                if (typeof skyboxConifguration === 'object' && skyboxConifguration.material && skyboxConifguration.material.imageProcessingConfiguration) {
+                    this.extendClassWithConfig(skyboxMaterial.imageProcessingConfiguration, skyboxConifguration.material.imageProcessingConfiguration);
+                }
+            }
+        }
+    }
+
+    protected configureScene(sceneConfig: ISceneConfiguration, optimizerConfig?: ISceneOptimizerConfiguration) {
+        // sanity check!
+        if (!this.scene) {
+            return;
+        }
+        if (sceneConfig.debug) {
+            this.scene.debugLayer.show();
+        } else {
+            if (this.scene.debugLayer.isVisible()) {
+                this.scene.debugLayer.hide();
+            }
+        }
+
+        if (sceneConfig.clearColor) {
+            let cc = sceneConfig.clearColor;
+            let oldcc = this.scene.clearColor;
+            if (cc.r !== undefined) {
+                oldcc.r = cc.r;
+            }
+            if (cc.g !== undefined) {
+                oldcc.g = cc.g
+            }
+            if (cc.b !== undefined) {
+                oldcc.b = cc.b
+            }
+            if (cc.a !== undefined) {
+                oldcc.a = cc.a
+            }
+        }
+
+        // image processing configuration - optional.
+        if (sceneConfig.imageProcessingConfiguration) {
+            this.extendClassWithConfig(this.scene.imageProcessingConfiguration, sceneConfig.imageProcessingConfiguration);
+        }
+        if (sceneConfig.environmentTexture) {
+            if (this.scene.environmentTexture) {
+                this.scene.environmentTexture.dispose();
+            }
+            const environmentTexture = CubeTexture.CreateFromPrefilteredData(sceneConfig.environmentTexture, this.scene);
+            this.scene.environmentTexture = environmentTexture;
+        }
+
+        if (sceneConfig.autoRotate) {
+            this.camera.useAutoRotationBehavior = true;
+        }
+    }
+
+    protected configureOptimizer(optimizerConfig: ISceneOptimizerConfiguration | boolean) {
+        if (typeof optimizerConfig === 'boolean') {
+            if (this.sceneOptimizer) {
+                this.sceneOptimizer.stop();
+                this.sceneOptimizer.dispose();
+                delete this.sceneOptimizer;
+            }
+            if (optimizerConfig) {
+                this.sceneOptimizer = new SceneOptimizer(this.scene);
+                this.sceneOptimizer.start();
+            }
+        } else {
+            let optimizerOptions: SceneOptimizerOptions = new SceneOptimizerOptions(optimizerConfig.targetFrameRate, optimizerConfig.trackerDuration);
+            // check for degradation
+            if (optimizerConfig.degradation) {
+                switch (optimizerConfig.degradation) {
+                    case "low":
+                        optimizerOptions = SceneOptimizerOptions.LowDegradationAllowed(optimizerConfig.targetFrameRate);
+                        break;
+                    case "moderate":
+                        optimizerOptions = SceneOptimizerOptions.ModerateDegradationAllowed(optimizerConfig.targetFrameRate);
+                        break;
+                    case "hight":
+                        optimizerOptions = SceneOptimizerOptions.HighDegradationAllowed(optimizerConfig.targetFrameRate);
+                        break;
+                }
+            }
+            if (this.sceneOptimizer) {
+                this.sceneOptimizer.stop();
+                this.sceneOptimizer.dispose()
+            }
+            this.sceneOptimizer = new SceneOptimizer(this.scene, optimizerOptions, optimizerConfig.autoGeneratePriorities, optimizerConfig.improvementMode);
+            this.sceneOptimizer.start();
+        }
+    }
+
+    protected configureObservers(observersConfiguration: IObserversConfiguration) {
+        if (observersConfiguration.onEngineInit) {
+            this.onEngineInitObservable.add(window[observersConfiguration.onEngineInit]);
+        } else {
+            if (observersConfiguration.onEngineInit === '' && this.configuration.observers && this.configuration.observers!.onEngineInit) {
+                this.onEngineInitObservable.removeCallback(window[this.configuration.observers!.onEngineInit!]);
+            }
+        }
+        if (observersConfiguration.onSceneInit) {
+            this.onSceneInitObservable.add(window[observersConfiguration.onSceneInit]);
+        } else {
+            if (observersConfiguration.onSceneInit === '' && this.configuration.observers && this.configuration.observers!.onSceneInit) {
+                this.onSceneInitObservable.removeCallback(window[this.configuration.observers!.onSceneInit!]);
+            }
+        }
+        if (observersConfiguration.onModelLoaded) {
+            this.onModelLoadedObservable.add(window[observersConfiguration.onModelLoaded]);
+        } else {
+            if (observersConfiguration.onModelLoaded === '' && this.configuration.observers && this.configuration.observers!.onModelLoaded) {
+                this.onModelLoadedObservable.removeCallback(window[this.configuration.observers!.onModelLoaded!]);
+            }
+        }
+    }
+
+    protected configureCamera(cameraConfig: ICameraConfiguration, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        if (!this.scene.activeCamera) {
+            this.scene.createDefaultCamera(true, true, true);
+            this.camera = <ArcRotateCamera>this.scene.activeCamera!;
+        }
+        if (cameraConfig.position) {
+            this.camera.position.copyFromFloats(cameraConfig.position.x || 0, cameraConfig.position.y || 0, cameraConfig.position.z || 0);
+        }
+
+        if (cameraConfig.rotation) {
+            this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
+        }
+
+        this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
+        this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
+
+        if (cameraConfig.behaviors) {
+            for (let name in cameraConfig.behaviors) {
+                this.setCameraBehavior(cameraConfig.behaviors[name], focusMeshes);
+            }
+        };
+
+        const sceneExtends = this.scene.getWorldExtends();
+        const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
+        const sceneDiagonalLenght = sceneDiagonal.length();
+        this.camera.upperRadiusLimit = sceneDiagonalLenght * 3;
+    }
+
+    protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        // sanity check!
+        if (!Object.keys(lightsConfiguration).length) return;
+
+        let lightsAvailable: Array<string> = this.scene.lights.map(light => light.name);
+
+        Object.keys(lightsConfiguration).forEach((name, idx) => {
+            let lightConfig: ILightConfiguration = { type: 0 };
+            if (typeof lightsConfiguration[name] === 'object') {
+                lightConfig = <ILightConfiguration>lightsConfiguration[name];
+            }
+
+            lightConfig.name = name;
+
+            let light;
+            // light is not already available
+            if (lightsAvailable.indexOf(name) === -1) {
+                let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
+                if (!constructor) return;
+                light = constructor();
+            } else {
+                // available? get it from the scene
+                light = this.scene.getLightByName(name);
+                lightsAvailable = lightsAvailable.filter(ln => ln !== name);
+            }
+
+            // if config set the light to false, dispose it.
+            if (lightsConfiguration[name] === false) {
+                light.dispose();
+                return;
+            }
+
+            //enabled
+            if (light.isEnabled() !== !lightConfig.disabled) {
+                light.setEnabled(!lightConfig.disabled);
+            }
+
+            this.extendClassWithConfig(light, lightConfig);
+
+            //position. Some lights don't support shadows
+            if (light instanceof ShadowLight) {
+                let shadowGenerator = light.getShadowGenerator();
+                if (lightConfig.shadowEnabled && this.maxShadows) {
+                    if (!shadowGenerator) {
+                        shadowGenerator = new ShadowGenerator(512, light);
+                    }
+                    this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
+                    // add the focues meshes to the shadow list
+                    let shadownMap = shadowGenerator.getShadowMap();
+                    if (!shadownMap) return;
+                    let renderList = shadownMap.renderList;
+                    for (var index = 0; index < focusMeshes.length; index++) {
+                        if (Tags.MatchesQuery(focusMeshes[index], 'castShadow')) {
+                            // renderList && renderList.push(focusMeshes[index]);
+                        }
+                    }
+                } else if (shadowGenerator) {
+                    shadowGenerator.dispose();
+                }
+            }
+        });
+
+        // remove the unneeded lights
+        /*lightsAvailable.forEach(name => {
+            let light = this.scene.getLightByName(name);
+            if (light) {
+                light.dispose();
+            }
+        });*/
+    }
+
+    protected configureModel(modelConfiguration: Partial<IModelConfiguration>, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        let meshesWithNoParent: Array<AbstractMesh> = focusMeshes.filter(m => !m.parent);
+        let updateMeshesWithNoParent = (variable: string, value: any, param?: string) => {
+            meshesWithNoParent.forEach(mesh => {
+                if (param) {
+                    mesh[variable][param] = value;
+                } else {
+                    mesh[variable] = value;
+                }
+            });
+        }
+        let updateXYZ = (variable: string, configValues: { x: number, y: number, z: number, w?: number }) => {
+            if (configValues.x !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.x, 'x');
+            }
+            if (configValues.y !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.y, 'y');
+            }
+            if (configValues.z !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.z, 'z');
+            }
+            if (configValues.w !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.w, 'w');
+            }
+        }
+        // position?
+        if (modelConfiguration.position) {
+            updateXYZ('position', modelConfiguration.position);
+        }
+        if (modelConfiguration.rotation) {
+            if (modelConfiguration.rotation.w) {
+                meshesWithNoParent.forEach(mesh => {
+                    if (!mesh.rotationQuaternion) {
+                        mesh.rotationQuaternion = new Quaternion();
+                    }
+                })
+                updateXYZ('rotationQuaternion', modelConfiguration.rotation);
+            } else {
+                updateXYZ('rotation', modelConfiguration.rotation);
+            }
+        }
+        if (modelConfiguration.scaling) {
+            updateXYZ('scaling', modelConfiguration.scaling);
+        }
+
+        if (modelConfiguration.castShadow) {
+            focusMeshes.forEach(mesh => {
+                Tags.AddTagsTo(mesh, 'castShadow');
+            });
+        }
     }
     }
 
 
     public dispose() {
     public dispose() {
@@ -233,48 +638,17 @@ export abstract class AbstractViewer {
         // create a new scene
         // create a new scene
         this.scene = new Scene(this.engine);
         this.scene = new Scene(this.engine);
         // make sure there is a default camera and light.
         // make sure there is a default camera and light.
-        this.scene.createDefaultCameraOrLight(true, true, true);
+        this.scene.createDefaultLight(true);
+
         if (this.configuration.scene) {
         if (this.configuration.scene) {
-            if (this.configuration.scene.debug) {
-                this.scene.debugLayer.show();
-            }
+            this.configureScene(this.configuration.scene);
 
 
             // Scene optimizer
             // Scene optimizer
             if (this.configuration.optimizer) {
             if (this.configuration.optimizer) {
-
-                let optimizerConfig = this.configuration.optimizer;
-                let optimizerOptions: SceneOptimizerOptions = new SceneOptimizerOptions(optimizerConfig.targetFrameRate, optimizerConfig.trackerDuration);
-                // check for degradation
-                if (optimizerConfig.degradation) {
-                    switch (optimizerConfig.degradation) {
-                        case "low":
-                            optimizerOptions = SceneOptimizerOptions.LowDegradationAllowed(optimizerConfig.targetFrameRate);
-                            break;
-                        case "moderate":
-                            optimizerOptions = SceneOptimizerOptions.ModerateDegradationAllowed(optimizerConfig.targetFrameRate);
-                            break;
-                        case "hight":
-                            optimizerOptions = SceneOptimizerOptions.HighDegradationAllowed(optimizerConfig.targetFrameRate);
-                            break;
-                    }
-                }
-
-                this.sceneOptimizer = new SceneOptimizer(this.scene, optimizerOptions, optimizerConfig.autoGeneratePriorities, optimizerConfig.improvementMode);
-                this.sceneOptimizer.start();
-            }
-
-            // image processing configuration - optional.
-            if (this.configuration.scene.imageProcessingConfiguration) {
-                this.extendClassWithConfig(this.scene.imageProcessingConfiguration, this.configuration.scene.imageProcessingConfiguration);
-            }
-            if (this.configuration.scene.environmentTexture) {
-                const environmentTexture = CubeTexture.CreateFromPrefilteredData(this.configuration.scene.environmentTexture, this.scene);
-                this.scene.environmentTexture = environmentTexture;
+                this.configureOptimizer(this.configuration.optimizer);
             }
             }
         }
         }
 
 
-
-
         return Promise.resolve(this.scene);
         return Promise.resolve(this.scene);
     }
     }
 
 
@@ -287,8 +661,14 @@ export abstract class AbstractViewer {
         let plugin = (typeof model === 'string') ? undefined : model.loader;
         let plugin = (typeof model === 'string') ? undefined : model.loader;
 
 
         return Promise.resolve(this.scene).then((scene) => {
         return Promise.resolve(this.scene).then((scene) => {
-            if (!scene || clearScene) return this.initScene();
-            else return this.scene!;
+            if (!scene) return this.initScene();
+
+            if (clearScene) {
+                scene.meshes.forEach(mesh => {
+                    mesh.dispose();
+                });
+            }
+            return scene!;
         }).then(() => {
         }).then(() => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
                 this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
                 this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
@@ -297,14 +677,23 @@ export abstract class AbstractViewer {
                     this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
                     this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
                 }, (e, m, exception) => {
                 }, (e, m, exception) => {
                     // console.log(m, exception);
                     // console.log(m, exception);
-                    reject(m);
+                    this.onModelLoadErrorObservable.notifyObserversWithPromise({ message: m, exception: exception }).then(() => {
+                        reject(exception);
+                    });
                 }, plugin)!;
                 }, plugin)!;
                 this.onLoaderInitObservable.notifyObserversWithPromise(this.lastUsedLoader);
                 this.onLoaderInitObservable.notifyObserversWithPromise(this.lastUsedLoader);
             });
             });
         }).then((meshes: Array<AbstractMesh>) => {
         }).then((meshes: Array<AbstractMesh>) => {
             return this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
             return this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
                 .then(() => {
                 .then(() => {
-                    this.initEnvironment();
+                    // update the models' configuration
+                    this.configureModel(model, meshes);
+                    this.configureLights(this.configuration.lights);
+
+                    if (this.configuration.camera) {
+                        this.configureCamera(this.configuration.camera, meshes);
+                    }
+                    return this.initEnvironment(meshes);
                 }).then(() => {
                 }).then(() => {
                     return this.scene;
                     return this.scene;
                 });
                 });
@@ -312,108 +701,7 @@ export abstract class AbstractViewer {
     }
     }
 
 
     protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
     protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
-        if (!this.configuration.skybox && !this.configuration.ground) {
-            if (this.environmentHelper) {
-                this.environmentHelper.dispose();
-            };
-            return Promise.resolve(this.scene);
-        }
-
-        const options: Partial<IEnvironmentHelperOptions> = {
-            createGround: !!this.configuration.ground,
-            createSkybox: !!this.configuration.skybox,
-            setupImageProcessing: false // will be done at the scene level!
-        };
-
-        if (this.configuration.ground) {
-            let groundConfig = (typeof this.configuration.ground === 'boolean') ? {} : this.configuration.ground;
-
-            let groundSize = groundConfig.size || (this.configuration.skybox && this.configuration.skybox.scale);
-            if (groundSize) {
-                options.groundSize = groundSize;
-            }
-
-            options.enableGroundShadow = this.configuration.ground === true || groundConfig.receiveShadows;
-            if (groundConfig.shadowLevel) {
-                options.groundShadowLevel = groundConfig.shadowLevel;
-            }
-            options.enableGroundMirror = !!groundConfig.mirror;
-            if (groundConfig.texture) {
-                options.groundTexture = groundConfig.texture;
-            }
-            if (groundConfig.color) {
-                options.groundColor = new Color3(groundConfig.color.r, groundConfig.color.g, groundConfig.color.b)
-            }
-
-            if (groundConfig.mirror) {
-                options.enableGroundMirror = true;
-                // to prevent undefines
-                if (typeof groundConfig.mirror === "object") {
-                    if (groundConfig.mirror.amount)
-                        options.groundMirrorAmount = groundConfig.mirror.amount;
-                    if (groundConfig.mirror.sizeRatio)
-                        options.groundMirrorSizeRatio = groundConfig.mirror.sizeRatio;
-                    if (groundConfig.mirror.blurKernel)
-                        options.groundMirrorBlurKernel = groundConfig.mirror.blurKernel;
-                    if (groundConfig.mirror.fresnelWeight)
-                        options.groundMirrorFresnelWeight = groundConfig.mirror.fresnelWeight;
-                    if (groundConfig.mirror.fallOffDistance)
-                        options.groundMirrorFallOffDistance = groundConfig.mirror.fallOffDistance;
-                    if (this.defaultHighpTextureType !== undefined)
-                        options.groundMirrorTextureType = this.defaultHighpTextureType;
-                }
-            }
-
-        }
-
-        let postInitSkyboxMaterial = false;
-        if (this.configuration.skybox) {
-            let conf = this.configuration.skybox;
-            if (conf.material && conf.material.imageProcessingConfiguration) {
-                options.setupImageProcessing = false; // will be configured later manually.
-            }
-            let skyboxSize = this.configuration.skybox.scale;
-            if (skyboxSize) {
-                options.skyboxSize = skyboxSize;
-            }
-            options.sizeAuto = !options.skyboxSize;
-            if (conf.color) {
-                options.skyboxColor = new Color3(conf.color.r, conf.color.g, conf.color.b)
-            }
-            if (conf.cubeTexture && conf.cubeTexture.url) {
-                if (typeof conf.cubeTexture.url === "string") {
-                    options.skyboxTexture = conf.cubeTexture.url;
-                } else {
-                    // init later!
-                    postInitSkyboxMaterial = true;
-                }
-            }
-
-            if (conf.material && conf.material.imageProcessingConfiguration) {
-                postInitSkyboxMaterial = true;
-            }
-        }
-
-        if (!this.environmentHelper) {
-            this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
-        }
-        else {
-            // there might be a new scene! we need to dispose.
-            // Need to decide if a scene should stay or be disposed.
-            this.environmentHelper.dispose();
-            //this.environmentHelper.updateOptions(options);
-            this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
-        }
-        console.log(options);
-
-        if (postInitSkyboxMaterial) {
-            let skyboxMaterial = this.environmentHelper.skyboxMaterial;
-            if (skyboxMaterial) {
-                if (this.configuration.skybox && this.configuration.skybox.material && this.configuration.skybox.material.imageProcessingConfiguration) {
-                    this.extendClassWithConfig(skyboxMaterial.imageProcessingConfiguration, this.configuration.skybox.material.imageProcessingConfiguration);
-                }
-            }
-        }
+        this.configureEnvironment(this.configuration.skybox, this.configuration.ground);
 
 
         return Promise.resolve(this.scene);
         return Promise.resolve(this.scene);
     }
     }
@@ -492,4 +780,54 @@ export abstract class AbstractViewer {
             }
             }
         });
         });
     }
     }
+
+    private setCameraBehavior(behaviorConfig: number | {
+        type: number;
+        [propName: string]: any;
+    }, payload: any) {
+
+        let behavior: Behavior<ArcRotateCamera> | null;
+        let type = (typeof behaviorConfig !== "object") ? behaviorConfig : behaviorConfig.type;
+
+        let config: { [propName: string]: any } = (typeof behaviorConfig === "object") ? behaviorConfig : {};
+
+        // constructing behavior
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                behavior = new AutoRotationBehavior();
+                break;
+            case CameraBehavior.BOUNCING:
+                behavior = new BouncingBehavior();
+                break;
+            case CameraBehavior.FRAMING:
+                behavior = new FramingBehavior();
+                break;
+            default:
+                behavior = null;
+                break;
+        }
+
+        if (behavior) {
+            if (typeof behaviorConfig === "object") {
+                this.extendClassWithConfig(behavior, behaviorConfig);
+            }
+            this.camera.addBehavior(behavior);
+        }
+
+        // post attach configuration. Some functionalities require the attached camera.
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                break;
+            case CameraBehavior.BOUNCING:
+                break;
+            case CameraBehavior.FRAMING:
+                if (config.zoomOnBoundingInfo) {
+                    //payload is an array of meshes
+                    let meshes = <Array<AbstractMesh>>payload;
+                    let bounding = meshes[0].getHierarchyBoundingVectors();
+                    (<FramingBehavior>behavior).zoomOnBoundingInfo(bounding.min, bounding.max);
+                }
+                break;
+        }
+    }
 }
 }

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


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


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


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


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


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


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


File diff suppressed because it is too large
+ 1028 - 66
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


File diff suppressed because it is too large
+ 1028 - 66
dist/preview release/es6.js


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


+ 249 - 0
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -1,3 +1,252 @@
+declare module BABYLON.GLTF2 {
+    const enum AccessorComponentType {
+        BYTE = 5120,
+        UNSIGNED_BYTE = 5121,
+        SHORT = 5122,
+        UNSIGNED_SHORT = 5123,
+        UNSIGNED_INT = 5125,
+        FLOAT = 5126,
+    }
+    const enum AccessorType {
+        SCALAR = "SCALAR",
+        VEC2 = "VEC2",
+        VEC3 = "VEC3",
+        VEC4 = "VEC4",
+        MAT2 = "MAT2",
+        MAT3 = "MAT3",
+        MAT4 = "MAT4",
+    }
+    const enum AnimationChannelTargetPath {
+        TRANSLATION = "translation",
+        ROTATION = "rotation",
+        SCALE = "scale",
+        WEIGHTS = "weights",
+    }
+    const enum AnimationInterpolation {
+        LINEAR = "LINEAR",
+        STEP = "STEP",
+        CUBICSPLINE = "CUBICSPLINE",
+    }
+    const enum CameraType {
+        PERSPECTIVE = "perspective",
+        ORTHOGRAPHIC = "orthographic",
+    }
+    const enum ImageMimeType {
+        JPEG = "image/jpeg",
+        PNG = "image/png",
+    }
+    const enum MaterialAlphaMode {
+        OPAQUE = "OPAQUE",
+        MASK = "MASK",
+        BLEND = "BLEND",
+    }
+    const enum MeshPrimitiveMode {
+        POINTS = 0,
+        LINES = 1,
+        LINE_LOOP = 2,
+        LINE_STRIP = 3,
+        TRIANGLES = 4,
+        TRIANGLE_STRIP = 5,
+        TRIANGLE_FAN = 6,
+    }
+    const enum TextureMagFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+    }
+    const enum TextureMinFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+        NEAREST_MIPMAP_NEAREST = 9984,
+        LINEAR_MIPMAP_NEAREST = 9985,
+        NEAREST_MIPMAP_LINEAR = 9986,
+        LINEAR_MIPMAP_LINEAR = 9987,
+    }
+    const enum TextureWrapMode {
+        CLAMP_TO_EDGE = 33071,
+        MIRRORED_REPEAT = 33648,
+        REPEAT = 10497,
+    }
+    interface IProperty {
+        extensions?: {
+            [key: string]: any;
+        };
+        extras?: any;
+    }
+    interface IChildRootProperty extends IProperty {
+        name?: string;
+    }
+    interface IAccessorSparseIndices extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+    }
+    interface IAccessorSparseValues extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+    }
+    interface IAccessorSparse extends IProperty {
+        count: number;
+        indices: IAccessorSparseIndices;
+        values: IAccessorSparseValues;
+    }
+    interface IAccessor extends IChildRootProperty {
+        bufferView?: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+        normalized?: boolean;
+        count: number;
+        type: AccessorType;
+        max?: number[];
+        min?: number[];
+        sparse?: IAccessorSparse;
+    }
+    interface IAnimationChannel extends IProperty {
+        sampler: number;
+        target: IAnimationChannelTarget;
+    }
+    interface IAnimationChannelTarget extends IProperty {
+        node: number;
+        path: AnimationChannelTargetPath;
+    }
+    interface IAnimationSampler extends IProperty {
+        input: number;
+        interpolation?: AnimationInterpolation;
+        output: number;
+    }
+    interface IAnimation extends IChildRootProperty {
+        channels: IAnimationChannel[];
+        samplers: IAnimationSampler[];
+    }
+    interface IAsset extends IChildRootProperty {
+        copyright?: string;
+        generator?: string;
+        version: string;
+        minVersion?: string;
+    }
+    interface IBuffer extends IChildRootProperty {
+        uri?: string;
+        byteLength: number;
+    }
+    interface IBufferView extends IChildRootProperty {
+        buffer: number;
+        byteOffset?: number;
+        byteLength: number;
+        byteStride?: number;
+    }
+    interface ICameraOrthographic extends IProperty {
+        xmag: number;
+        ymag: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICameraPerspective extends IProperty {
+        aspectRatio: number;
+        yfov: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICamera extends IChildRootProperty {
+        orthographic?: ICameraOrthographic;
+        perspective?: ICameraPerspective;
+        type: CameraType;
+    }
+    interface IImage extends IChildRootProperty {
+        uri?: string;
+        mimeType?: ImageMimeType;
+        bufferView?: number;
+    }
+    interface IMaterialNormalTextureInfo extends ITextureInfo {
+        scale?: number;
+    }
+    interface IMaterialOcclusionTextureInfo extends ITextureInfo {
+        strength?: number;
+    }
+    interface IMaterialPbrMetallicRoughness {
+        baseColorFactor?: number[];
+        baseColorTexture?: ITextureInfo;
+        metallicFactor?: number;
+        roughnessFactor?: number;
+        metallicRoughnessTexture?: ITextureInfo;
+    }
+    interface IMaterial extends IChildRootProperty {
+        pbrMetallicRoughness?: IMaterialPbrMetallicRoughness;
+        normalTexture?: IMaterialNormalTextureInfo;
+        occlusionTexture?: IMaterialOcclusionTextureInfo;
+        emissiveTexture?: ITextureInfo;
+        emissiveFactor?: number[];
+        alphaMode?: MaterialAlphaMode;
+        alphaCutoff?: number;
+        doubleSided?: boolean;
+    }
+    interface IMeshPrimitive extends IProperty {
+        attributes: {
+            [name: string]: number;
+        };
+        indices?: number;
+        material?: number;
+        mode?: MeshPrimitiveMode;
+        targets?: {
+            [name: string]: number;
+        }[];
+    }
+    interface IMesh extends IChildRootProperty {
+        primitives: IMeshPrimitive[];
+        weights?: number[];
+    }
+    interface INode extends IChildRootProperty {
+        camera?: number;
+        children?: number[];
+        skin?: number;
+        matrix?: number[];
+        mesh?: number;
+        rotation?: number[];
+        scale?: number[];
+        translation?: number[];
+        weights?: number[];
+    }
+    interface ISampler extends IChildRootProperty {
+        magFilter?: TextureMagFilter;
+        minFilter?: TextureMinFilter;
+        wrapS?: TextureWrapMode;
+        wrapT?: TextureWrapMode;
+    }
+    interface IScene extends IChildRootProperty {
+        nodes: number[];
+    }
+    interface ISkin extends IChildRootProperty {
+        inverseBindMatrices?: number;
+        skeleton?: number;
+        joints: number[];
+    }
+    interface ITexture extends IChildRootProperty {
+        sampler?: number;
+        source: number;
+    }
+    interface ITextureInfo {
+        index: number;
+        texCoord?: number;
+    }
+    interface IGLTF extends IProperty {
+        accessors?: IAccessor[];
+        animations?: IAnimation[];
+        asset: IAsset;
+        buffers?: IBuffer[];
+        bufferViews?: IBufferView[];
+        cameras?: ICamera[];
+        extensionsUsed?: string[];
+        extensionsRequired?: string[];
+        images?: IImage[];
+        materials?: IMaterial[];
+        meshes?: IMesh[];
+        nodes?: INode[];
+        samplers?: ISampler[];
+        scene?: number;
+        scenes?: IScene[];
+        skins?: ISkin[];
+        textures?: ITexture[];
+    }
+}
+
 
 
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**

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


+ 249 - 0
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -12,6 +12,255 @@ declare module BABYLON {
     }
     }
 }
 }
 
 
+declare module BABYLON.GLTF2 {
+    const enum AccessorComponentType {
+        BYTE = 5120,
+        UNSIGNED_BYTE = 5121,
+        SHORT = 5122,
+        UNSIGNED_SHORT = 5123,
+        UNSIGNED_INT = 5125,
+        FLOAT = 5126,
+    }
+    const enum AccessorType {
+        SCALAR = "SCALAR",
+        VEC2 = "VEC2",
+        VEC3 = "VEC3",
+        VEC4 = "VEC4",
+        MAT2 = "MAT2",
+        MAT3 = "MAT3",
+        MAT4 = "MAT4",
+    }
+    const enum AnimationChannelTargetPath {
+        TRANSLATION = "translation",
+        ROTATION = "rotation",
+        SCALE = "scale",
+        WEIGHTS = "weights",
+    }
+    const enum AnimationInterpolation {
+        LINEAR = "LINEAR",
+        STEP = "STEP",
+        CUBICSPLINE = "CUBICSPLINE",
+    }
+    const enum CameraType {
+        PERSPECTIVE = "perspective",
+        ORTHOGRAPHIC = "orthographic",
+    }
+    const enum ImageMimeType {
+        JPEG = "image/jpeg",
+        PNG = "image/png",
+    }
+    const enum MaterialAlphaMode {
+        OPAQUE = "OPAQUE",
+        MASK = "MASK",
+        BLEND = "BLEND",
+    }
+    const enum MeshPrimitiveMode {
+        POINTS = 0,
+        LINES = 1,
+        LINE_LOOP = 2,
+        LINE_STRIP = 3,
+        TRIANGLES = 4,
+        TRIANGLE_STRIP = 5,
+        TRIANGLE_FAN = 6,
+    }
+    const enum TextureMagFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+    }
+    const enum TextureMinFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+        NEAREST_MIPMAP_NEAREST = 9984,
+        LINEAR_MIPMAP_NEAREST = 9985,
+        NEAREST_MIPMAP_LINEAR = 9986,
+        LINEAR_MIPMAP_LINEAR = 9987,
+    }
+    const enum TextureWrapMode {
+        CLAMP_TO_EDGE = 33071,
+        MIRRORED_REPEAT = 33648,
+        REPEAT = 10497,
+    }
+    interface IProperty {
+        extensions?: {
+            [key: string]: any;
+        };
+        extras?: any;
+    }
+    interface IChildRootProperty extends IProperty {
+        name?: string;
+    }
+    interface IAccessorSparseIndices extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+    }
+    interface IAccessorSparseValues extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+    }
+    interface IAccessorSparse extends IProperty {
+        count: number;
+        indices: IAccessorSparseIndices;
+        values: IAccessorSparseValues;
+    }
+    interface IAccessor extends IChildRootProperty {
+        bufferView?: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+        normalized?: boolean;
+        count: number;
+        type: AccessorType;
+        max?: number[];
+        min?: number[];
+        sparse?: IAccessorSparse;
+    }
+    interface IAnimationChannel extends IProperty {
+        sampler: number;
+        target: IAnimationChannelTarget;
+    }
+    interface IAnimationChannelTarget extends IProperty {
+        node: number;
+        path: AnimationChannelTargetPath;
+    }
+    interface IAnimationSampler extends IProperty {
+        input: number;
+        interpolation?: AnimationInterpolation;
+        output: number;
+    }
+    interface IAnimation extends IChildRootProperty {
+        channels: IAnimationChannel[];
+        samplers: IAnimationSampler[];
+    }
+    interface IAsset extends IChildRootProperty {
+        copyright?: string;
+        generator?: string;
+        version: string;
+        minVersion?: string;
+    }
+    interface IBuffer extends IChildRootProperty {
+        uri?: string;
+        byteLength: number;
+    }
+    interface IBufferView extends IChildRootProperty {
+        buffer: number;
+        byteOffset?: number;
+        byteLength: number;
+        byteStride?: number;
+    }
+    interface ICameraOrthographic extends IProperty {
+        xmag: number;
+        ymag: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICameraPerspective extends IProperty {
+        aspectRatio: number;
+        yfov: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICamera extends IChildRootProperty {
+        orthographic?: ICameraOrthographic;
+        perspective?: ICameraPerspective;
+        type: CameraType;
+    }
+    interface IImage extends IChildRootProperty {
+        uri?: string;
+        mimeType?: ImageMimeType;
+        bufferView?: number;
+    }
+    interface IMaterialNormalTextureInfo extends ITextureInfo {
+        scale?: number;
+    }
+    interface IMaterialOcclusionTextureInfo extends ITextureInfo {
+        strength?: number;
+    }
+    interface IMaterialPbrMetallicRoughness {
+        baseColorFactor?: number[];
+        baseColorTexture?: ITextureInfo;
+        metallicFactor?: number;
+        roughnessFactor?: number;
+        metallicRoughnessTexture?: ITextureInfo;
+    }
+    interface IMaterial extends IChildRootProperty {
+        pbrMetallicRoughness?: IMaterialPbrMetallicRoughness;
+        normalTexture?: IMaterialNormalTextureInfo;
+        occlusionTexture?: IMaterialOcclusionTextureInfo;
+        emissiveTexture?: ITextureInfo;
+        emissiveFactor?: number[];
+        alphaMode?: MaterialAlphaMode;
+        alphaCutoff?: number;
+        doubleSided?: boolean;
+    }
+    interface IMeshPrimitive extends IProperty {
+        attributes: {
+            [name: string]: number;
+        };
+        indices?: number;
+        material?: number;
+        mode?: MeshPrimitiveMode;
+        targets?: {
+            [name: string]: number;
+        }[];
+    }
+    interface IMesh extends IChildRootProperty {
+        primitives: IMeshPrimitive[];
+        weights?: number[];
+    }
+    interface INode extends IChildRootProperty {
+        camera?: number;
+        children?: number[];
+        skin?: number;
+        matrix?: number[];
+        mesh?: number;
+        rotation?: number[];
+        scale?: number[];
+        translation?: number[];
+        weights?: number[];
+    }
+    interface ISampler extends IChildRootProperty {
+        magFilter?: TextureMagFilter;
+        minFilter?: TextureMinFilter;
+        wrapS?: TextureWrapMode;
+        wrapT?: TextureWrapMode;
+    }
+    interface IScene extends IChildRootProperty {
+        nodes: number[];
+    }
+    interface ISkin extends IChildRootProperty {
+        inverseBindMatrices?: number;
+        skeleton?: number;
+        joints: number[];
+    }
+    interface ITexture extends IChildRootProperty {
+        sampler?: number;
+        source: number;
+    }
+    interface ITextureInfo {
+        index: number;
+        texCoord?: number;
+    }
+    interface IGLTF extends IProperty {
+        accessors?: IAccessor[];
+        animations?: IAnimation[];
+        asset: IAsset;
+        buffers?: IBuffer[];
+        bufferViews?: IBufferView[];
+        cameras?: ICamera[];
+        extensionsUsed?: string[];
+        extensionsRequired?: string[];
+        images?: IImage[];
+        materials?: IMaterial[];
+        meshes?: IMesh[];
+        nodes?: INode[];
+        samplers?: ISampler[];
+        scene?: number;
+        scenes?: IScene[];
+        skins?: ISkin[];
+        textures?: ITexture[];
+    }
+}
+
 
 
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**

File diff suppressed because it is too large
+ 2 - 1321
dist/preview release/typedocValidationBaseline.json


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


+ 8 - 3
dist/preview release/what's new.md

@@ -7,7 +7,7 @@
 - `WebVRCamera` now supports GearVR ([brianzinn](https://github.com/brianzinn))
 - `WebVRCamera` now supports GearVR ([brianzinn](https://github.com/brianzinn))
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
 - Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
-- Introduced Projection Texture on SpotLight (`spotLight.projectedLightTexture`) ([lostink](https://github.com/lostink))
+- Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture) ([lostink](https://github.com/lostink))
 
 
 ## Updates
 ## Updates
 - Tons of functions and classes received the code comments they deserved (All the community)
 - Tons of functions and classes received the code comments they deserved (All the community)
@@ -25,7 +25,7 @@
    ([carloslanderas](https://github.com/carloslanderas))
    ([carloslanderas](https://github.com/carloslanderas))
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
    ([carloslanderas](https://github.com/carloslanderas))
    ([carloslanderas](https://github.com/carloslanderas))
-- `AssetsManager` will now clear its `tasks` lsit from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))tasks ([deltakosh](https://github.com/deltakosh))
+- `AssetsManager` will now clear its `tasks` lsit from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))
 - Added documentation to WebVRCamera and VRExperienceHelper ([trevordev](https://github.com/trevordev))
 - Added documentation to WebVRCamera and VRExperienceHelper ([trevordev](https://github.com/trevordev))
 - Introduced `isStroke` on `HighlightLayerOptions` which makes the highlight solid ([PixelsCommander](https://github.com/pixelscommander))
 - Introduced `isStroke` on `HighlightLayerOptions` which makes the highlight solid ([PixelsCommander](https://github.com/pixelscommander))
 - (Viewer) There is now an option to paste payload instead of a URL for configuration ([RaananW](https://github.com/RaananW))
 - (Viewer) There is now an option to paste payload instead of a URL for configuration ([RaananW](https://github.com/RaananW))
@@ -41,11 +41,16 @@
 - Gulp process now supports multiple outputs when using webpack. ([RaananW](https://github.com/RaananW))
 - Gulp process now supports multiple outputs when using webpack. ([RaananW](https://github.com/RaananW))
 - (Viewer) Scene Optimizer intergrated in viewer. ([RaananW](https://github.com/RaananW))
 - (Viewer) Scene Optimizer intergrated in viewer. ([RaananW](https://github.com/RaananW))
 - (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
 - (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
-- Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager classes ([trevordev](https://github.com/trevordev))
+- 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 internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
 - (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
 - (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))
+- (Viewer) It is now possible to update parts of the configuration without rcreating the objects. ([RaananW](https://github.com/RaananW))
+- (Gulp) extra/external declarations can be prepended to final declarations during build. ([RaananW](https://github.com/RaananW))
 
 
 ## Bug fixes
 ## Bug fixes
+- `setPivotMatrix` ws not setting pivot correctly. This is now fixed. We also introduced a new `setPreTransformMatrix` to reproduce the sometimes needed behavior of the previous `setPivotMatrix` function ([deltakosh](https://github.com/deltakosh))
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
 - Fixed a bug with merging vertex data ([bghgary](https://github.com/bghgary))
 - Fixed a bug with merging vertex data ([bghgary](https://github.com/bghgary))
 
 

+ 111 - 2
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -1,4 +1,7 @@
 module BABYLON {
 module BABYLON {
+    /**
+     * Manages the defines for the PBR Material.
+     */
     class PBRMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
     class PBRMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         public PBR = true;
         public PBR = true;
 
 
@@ -125,11 +128,17 @@
 
 
         public FORCENORMALFORWARD = false;
         public FORCENORMALFORWARD = false;
 
 
+        /**
+         * Initializes the PBR Material defines.
+         */
         constructor() {
         constructor() {
             super();
             super();
             this.rebuild();
             this.rebuild();
         }
         }
 
 
+        /**
+         * Resets the PBR Material defines.
+         */
         public reset(): void {
         public reset(): void {
             super.reset();
             super.reset();
             this.ALPHATESTVALUE = 0.5;
             this.ALPHATESTVALUE = 0.5;
@@ -170,6 +179,9 @@
          */
          */
         protected _specularIntensity: number = 1.0;
         protected _specularIntensity: number = 1.0;
 
 
+        /**
+         * This stores the direct, emissive, environment, and specular light intensities into a Vector4.
+         */
         private _lightingInfos: Vector4 = new Vector4(this._directIntensity, this._emissiveIntensity, this._environmentIntensity, this._specularIntensity);
         private _lightingInfos: Vector4 = new Vector4(this._directIntensity, this._emissiveIntensity, this._environmentIntensity, this._specularIntensity);
 
 
         /**
         /**
@@ -192,12 +204,24 @@
          */
          */
         protected _ambientTextureStrength: number = 1.0;
         protected _ambientTextureStrength: number = 1.0;
 
 
+        /**
+         * Stores the alpha values in a texture.
+         */
         protected _opacityTexture: BaseTexture;
         protected _opacityTexture: BaseTexture;
 
 
+        /**
+         * Stores the reflection values in a texture.
+         */
         protected _reflectionTexture: BaseTexture;
         protected _reflectionTexture: BaseTexture;
 
 
+        /**
+         * Stores the refraction values in a texture.
+         */
         protected _refractionTexture: BaseTexture;
         protected _refractionTexture: BaseTexture;
 
 
+        /**
+         * Stores the emissive values in a texture.
+         */
         protected _emissiveTexture: BaseTexture;
         protected _emissiveTexture: BaseTexture;
 
 
         /**
         /**
@@ -228,10 +252,19 @@
          */
          */
         protected _microSurfaceTexture: BaseTexture;
         protected _microSurfaceTexture: BaseTexture;
 
 
+        /**
+         * Stores surface normal data used to displace a mesh in a texture.
+         */
         protected _bumpTexture: BaseTexture;
         protected _bumpTexture: BaseTexture;
 
 
+        /**
+         * Stores the pre-calculated light information of a mesh in a texture.
+         */
         protected _lightmapTexture: BaseTexture;
         protected _lightmapTexture: BaseTexture;
 
 
+        /**
+         * The color of a material in ambient lighting.
+         */
         protected _ambientColor = new Color3(0, 0, 0);
         protected _ambientColor = new Color3(0, 0, 0);
 
 
         /**
         /**
@@ -244,8 +277,14 @@
          */
          */
         protected _reflectivityColor = new Color3(1, 1, 1);
         protected _reflectivityColor = new Color3(1, 1, 1);
 
 
+        /**
+         * The color applied when light is reflected from a material.
+         */
         protected _reflectionColor = new Color3(1, 1, 1);
         protected _reflectionColor = new Color3(1, 1, 1);
 
 
+        /**
+         * The color applied when light is emitted from a material.
+         */
         protected _emissiveColor = new Color3(0, 0, 0);
         protected _emissiveColor = new Color3(0, 0, 0);
 
 
         /**
         /**
@@ -269,6 +308,9 @@
          */
          */
         protected _linkRefractionWithTransparency = false;
         protected _linkRefractionWithTransparency = false;
 
 
+        /**
+         * Specifies that the material will use the light map as a show map.
+         */
         protected _useLightmapAsShadowmap = false;
         protected _useLightmapAsShadowmap = false;
 
 
         /**
         /**
@@ -471,8 +513,19 @@
             });
             });
         }
         }
 
 
+        /**
+         * Stores the available render targets.
+         */
         private _renderTargets = new SmartArray<RenderTargetTexture>(16);
         private _renderTargets = new SmartArray<RenderTargetTexture>(16);
+
+        /**
+         * Sets the global ambient color for the material used in lighting calculations.
+         */
         private _globalAmbientColor = new Color3(0, 0, 0);
         private _globalAmbientColor = new Color3(0, 0, 0);
+
+        /**
+         * Enables the use of logarithmic depth buffers, which is good for wide depth buffers.
+         */
         private _useLogarithmicDepth: boolean;
         private _useLogarithmicDepth: boolean;
 
 
         /**
         /**
@@ -504,15 +557,24 @@
             this._environmentBRDFTexture = TextureTools.GetEnvironmentBRDFTexture(scene);
             this._environmentBRDFTexture = TextureTools.GetEnvironmentBRDFTexture(scene);
         }
         }
 
 
+        /**
+         * Gets the name of the material class.
+         */
         public getClassName(): string {
         public getClassName(): string {
             return "PBRBaseMaterial";
             return "PBRBaseMaterial";
         }
         }
 
 
+        /**
+         * Enabled the use of logarithmic depth buffers, which is good for wide depth buffers.
+         */
         @serialize()
         @serialize()
         public get useLogarithmicDepth(): boolean {
         public get useLogarithmicDepth(): boolean {
             return this._useLogarithmicDepth;
             return this._useLogarithmicDepth;
         }
         }
 
 
+        /**
+         * Enabled the use of logarithmic depth buffers, which is good for wide depth buffers.
+         */
         public set useLogarithmicDepth(value: boolean) {
         public set useLogarithmicDepth(value: boolean) {
             this._useLogarithmicDepth = value && this.getScene().getEngine().getCaps().fragmentDepthSupported;
             this._useLogarithmicDepth = value && this.getScene().getEngine().getCaps().fragmentDepthSupported;
         }
         }
@@ -561,7 +623,8 @@
         }
         }
 
 
         /**
         /**
-         * Specifies whether or not this material should be rendered in alpha blend mode for the given mesh.
+         * Specifies if the mesh will require alpha blending.
+         * @param mesh - BJS mesh.
          */
          */
         public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
         public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
             if (this._disableAlphaBlending) {
             if (this._disableAlphaBlending) {
@@ -593,12 +656,25 @@
             return this._albedoTexture != null && this._albedoTexture.hasAlpha && this._useAlphaFromAlbedoTexture && this._transparencyMode !== PBRMaterial.PBRMATERIAL_OPAQUE;
             return this._albedoTexture != null && this._albedoTexture.hasAlpha && this._useAlphaFromAlbedoTexture && this._transparencyMode !== PBRMaterial.PBRMATERIAL_OPAQUE;
         }
         }
 
 
+        /**
+         * Gets the texture used for the alpha test.
+         */
         public getAlphaTestTexture(): BaseTexture {
         public getAlphaTestTexture(): BaseTexture {
             return this._albedoTexture;
             return this._albedoTexture;
         }
         }
 
 
+        /**
+         * Stores the reflectivity values based on metallic roughness workflow.
+         */
         private static _scaledReflectivity = new Color3();
         private static _scaledReflectivity = new Color3();
 
 
+        /**
+         * Specifies that the submesh is ready to be used.
+         * @param mesh - BJS mesh.
+         * @param subMesh - A submesh of the BJS mesh.  Used to check if it is ready. 
+         * @param useInstances - Specifies that instances should be used.
+         * @returns - boolean indicating that the submesh is ready or not.
+         */
         public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {
         public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {
             if (subMesh.effect && this.isFrozen) {
             if (subMesh.effect && this.isFrozen) {
                 if (this._wasPreviouslyReady) {
                 if (this._wasPreviouslyReady) {
@@ -1121,6 +1197,9 @@
             return true;
             return true;
         }
         }
 
 
+        /**
+         * Initializes the uniform buffer layout for the shader.
+         */
         public buildUniformLayout(): void {
         public buildUniformLayout(): void {
             // Order is important !
             // Order is important !
             this._uniformBuffer.addUniform("vAlbedoInfos", 2);
             this._uniformBuffer.addUniform("vAlbedoInfos", 2);
@@ -1158,7 +1237,9 @@
             this._uniformBuffer.create();
             this._uniformBuffer.create();
         }
         }
 
 
-
+        /**
+         * Unbinds the textures.
+         */
         public unbind(): void {
         public unbind(): void {
             if (this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
             if (this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
                 this._uniformBuffer.setTexture("reflectionSampler", null);
                 this._uniformBuffer.setTexture("reflectionSampler", null);
@@ -1171,10 +1252,20 @@
             super.unbind();
             super.unbind();
         }
         }
 
 
+        /**
+         * Binds to the world matrix.
+         * @param world - The world matrix.
+         */
         public bindOnlyWorldMatrix(world: Matrix): void {
         public bindOnlyWorldMatrix(world: Matrix): void {
             this._activeEffect.setMatrix("world", world);
             this._activeEffect.setMatrix("world", world);
         }
         }
 
 
+        /**
+         * Binds the submesh data.
+         * @param world - The world matrix.
+         * @param mesh - The BJS mesh.
+         * @param subMesh - A submesh of the BJS mesh.
+         */
         public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
         public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
             var scene = this.getScene();
             var scene = this.getScene();
 
 
@@ -1449,6 +1540,10 @@
             this._afterBind(mesh);
             this._afterBind(mesh);
         }
         }
 
 
+        /**
+         * Returns the animatable textures.
+         * @returns - Array of animatable textures.
+         */
         public getAnimatables(): IAnimatable[] {
         public getAnimatables(): IAnimatable[] {
             var results = [];
             var results = [];
 
 
@@ -1494,6 +1589,10 @@
             return results;
             return results;
         }
         }
 
 
+        /**
+         * Returns the texture used for reflections.
+         * @returns - Reflection texture if present.  Otherwise, returns the environment texture.
+         */
         private _getReflectionTexture(): BaseTexture {
         private _getReflectionTexture(): BaseTexture {
             if (this._reflectionTexture) {
             if (this._reflectionTexture) {
                 return this._reflectionTexture;
                 return this._reflectionTexture;
@@ -1502,6 +1601,11 @@
             return this.getScene().environmentTexture;
             return this.getScene().environmentTexture;
         }
         }
 
 
+        /**
+         * Returns the texture used for refraction or null if none is used.
+         * @returns - Refection texture if present.  If no refraction texture and refraction 
+         * is linked with transparency, returns environment texture.  Otherwise, returns null.
+         */
         private _getRefractionTexture(): Nullable<BaseTexture> {
         private _getRefractionTexture(): Nullable<BaseTexture> {
             if (this._refractionTexture) {
             if (this._refractionTexture) {
                 return this._refractionTexture;
                 return this._refractionTexture;
@@ -1514,6 +1618,11 @@
             return null;
             return null;
         }
         }
 
 
+        /**
+         * Disposes the resources of the material.
+         * @param forceDisposeEffect - Forces the disposal of effects.
+         * @param forceDisposeTextures - Forces the disposal of all textures.
+         */
         public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
         public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
             if (forceDisposeTextures) {
             if (forceDisposeTextures) {
                 if (this._albedoTexture) {
                 if (this._albedoTexture) {

+ 67 - 0
src/Materials/PBR/babylon.pbrMaterial.ts

@@ -15,7 +15,11 @@
             return this._PBRMATERIAL_OPAQUE;
             return this._PBRMATERIAL_OPAQUE;
         }
         }
 
 
+        /**
+         * Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
+         */
         private static _PBRMATERIAL_ALPHATEST = 1;
         private static _PBRMATERIAL_ALPHATEST = 1;
+
         /**
         /**
          * PBRMaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
          * PBRMaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
          */
          */
@@ -23,7 +27,11 @@
             return this._PBRMATERIAL_ALPHATEST;
             return this._PBRMATERIAL_ALPHATEST;
         }
         }
 
 
+        /**
+         * Represents the value for Alpha Blend.  Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
+         */
         private static _PBRMATERIAL_ALPHABLEND = 2;
         private static _PBRMATERIAL_ALPHABLEND = 2;
+
         /**
         /**
          * PBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
          * PBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
          */
          */
@@ -31,7 +39,12 @@
             return this._PBRMATERIAL_ALPHABLEND;
             return this._PBRMATERIAL_ALPHABLEND;
         }
         }
 
 
+        /**
+         * Represents the value for Alpha Test and Blend.  Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
+         * They are also discarded below the alpha cutoff threshold to improve performances.
+         */
         private static _PBRMATERIAL_ALPHATESTANDBLEND = 3;
         private static _PBRMATERIAL_ALPHATESTANDBLEND = 3;
+
         /**
         /**
          * PBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
          * PBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
          * They are also discarded below the alpha cutoff threshold to improve performances.
          * They are also discarded below the alpha cutoff threshold to improve performances.
@@ -100,14 +113,23 @@
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public ambientTextureStrength: number = 1.0;
         public ambientTextureStrength: number = 1.0;
 
 
+        /**
+         * Stores the alpha values in a texture.
+         */
         @serializeAsTexture()
         @serializeAsTexture()
         @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
         public opacityTexture: BaseTexture;
         public opacityTexture: BaseTexture;
 
 
+        /**
+         * Stores the reflection values in a texture.
+         */
         @serializeAsTexture()
         @serializeAsTexture()
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionTexture: Nullable<BaseTexture>;
         public reflectionTexture: Nullable<BaseTexture>;
 
 
+        /**
+         * Stores the emissive values in a texture.
+         */
         @serializeAsTexture()
         @serializeAsTexture()
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public emissiveTexture: BaseTexture;
         public emissiveTexture: BaseTexture;
@@ -150,18 +172,30 @@
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public microSurfaceTexture: BaseTexture;
         public microSurfaceTexture: BaseTexture;
 
 
+        /**
+         * Stores surface normal data used to displace a mesh in a texture.
+         */
         @serializeAsTexture()
         @serializeAsTexture()
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public bumpTexture: BaseTexture;
         public bumpTexture: BaseTexture;
 
 
+        /**
+         * Stores the pre-calculated light information of a mesh in a texture.
+         */
         @serializeAsTexture()
         @serializeAsTexture()
         @expandToProperty("_markAllSubMeshesAsTexturesDirty", null)
         @expandToProperty("_markAllSubMeshesAsTexturesDirty", null)
         public lightmapTexture: BaseTexture;
         public lightmapTexture: BaseTexture;
 
 
+        /**
+         * Stores the refracted light information in a texture.
+         */
         @serializeAsTexture()
         @serializeAsTexture()
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public refractionTexture: BaseTexture;
         public refractionTexture: BaseTexture;
 
 
+        /**
+         * The color of a material in ambient lighting.
+         */
         @serializeAsColor3("ambient")
         @serializeAsColor3("ambient")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public ambientColor = new Color3(0, 0, 0);
         public ambientColor = new Color3(0, 0, 0);
@@ -180,10 +214,16 @@
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectivityColor = new Color3(1, 1, 1);
         public reflectivityColor = new Color3(1, 1, 1);
 
 
+        /**
+         * The color reflected from the material.
+         */
         @serializeAsColor3("reflection")
         @serializeAsColor3("reflection")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionColor = new Color3(1.0, 1.0, 1.0);
         public reflectionColor = new Color3(1.0, 1.0, 1.0);
 
 
+        /**
+         * The color emitted from the material.
+         */
         @serializeAsColor3("emissive")
         @serializeAsColor3("emissive")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public emissiveColor = new Color3(0, 0, 0);
         public emissiveColor = new Color3(0, 0, 0);
@@ -560,10 +600,17 @@
             this._environmentBRDFTexture = TextureTools.GetEnvironmentBRDFTexture(scene);
             this._environmentBRDFTexture = TextureTools.GetEnvironmentBRDFTexture(scene);
         }
         }
 
 
+        /**
+         * Returns the name of this material class.
+         */
         public getClassName(): string {
         public getClassName(): string {
             return "PBRMaterial";
             return "PBRMaterial";
         }
         }
 
 
+        /**
+         * Returns an array of the actively used textures.
+         * @returns - Array of BaseTextures
+         */
         public getActiveTextures(): BaseTexture[] {
         public getActiveTextures(): BaseTexture[] {
             var activeTextures = super.getActiveTextures();
             var activeTextures = super.getActiveTextures();
 
 
@@ -614,6 +661,11 @@
             return activeTextures;
             return activeTextures;
         }
         }
 
 
+        /**
+         * Checks to see if a texture is used in the material.
+         * @param texture - Base texture to use.
+         * @returns - Boolean specifying if a texture is used in the material.
+         */
         public hasTexture(texture: BaseTexture): boolean {
         public hasTexture(texture: BaseTexture): boolean {
             if (super.hasTexture(texture)) {
             if (super.hasTexture(texture)) {
                 return true;
                 return true;
@@ -662,6 +714,10 @@
             return false;
             return false;
         }
         }
 
 
+        /**
+         * Makes a duplicate of the current material.
+         * @param name - name to use for the new material.
+         */
         public clone(name: string): PBRMaterial {
         public clone(name: string): PBRMaterial {
             var clone = SerializationHelper.Clone(() => new PBRMaterial(name, this.getScene()), this);
             var clone = SerializationHelper.Clone(() => new PBRMaterial(name, this.getScene()), this);
 
 
@@ -671,6 +727,10 @@
             return clone;
             return clone;
         }
         }
 
 
+        /**
+         * Serializes this PBR Material.
+         * @returns - An object with the serialized material.
+         */
         public serialize(): any {
         public serialize(): any {
             var serializationObject = SerializationHelper.Serialize(this);
             var serializationObject = SerializationHelper.Serialize(this);
             serializationObject.customType = "BABYLON.PBRMaterial";
             serializationObject.customType = "BABYLON.PBRMaterial";
@@ -678,6 +738,13 @@
         }
         }
 
 
         // Statics
         // Statics
+        /**
+         * Parses a PBR Material from a serialized object.
+         * @param source - Serialized object.
+         * @param scene - BJS scene instance.
+         * @param rootUrl - url for the scene object
+         * @returns - PBRMaterial
+         */
         public static Parse(source: any, scene: Scene, rootUrl: string): PBRMaterial {
         public static Parse(source: any, scene: Scene, rootUrl: string): PBRMaterial {
             return SerializationHelper.Parse(() => new PBRMaterial(source.name, scene), source, scene, rootUrl);
             return SerializationHelper.Parse(() => new PBRMaterial(source.name, scene), source, scene, rootUrl);
         }
         }

+ 9 - 0
src/Materials/PBR/babylon.pbrMetallicRoughnessMaterial.ts

@@ -87,6 +87,11 @@
             return activeTextures;
             return activeTextures;
         }
         }
 
 
+        /**
+         * Checks to see if a texture is used in the material.
+         * @param texture - Base texture to use.
+         * @returns - Boolean specifying if a texture is used in the material.
+         */
         public hasTexture(texture: BaseTexture): boolean {
         public hasTexture(texture: BaseTexture): boolean {
             if (super.hasTexture(texture)) {
             if (super.hasTexture(texture)) {
                 return true;
                 return true;
@@ -103,6 +108,10 @@
             return false;
             return false;
         }
         }
 
 
+        /**
+         * Makes a duplicate of the current material.
+         * @param name - name to use for the new material.
+         */
         public clone(name: string): PBRMetallicRoughnessMaterial {
         public clone(name: string): PBRMetallicRoughnessMaterial {
             var clone = SerializationHelper.Clone(() => new PBRMetallicRoughnessMaterial(name, this.getScene()), this);
             var clone = SerializationHelper.Clone(() => new PBRMetallicRoughnessMaterial(name, this.getScene()), this);
 
 

+ 9 - 0
src/Materials/PBR/babylon.pbrSpecularGlossinessMaterial.ts

@@ -78,6 +78,11 @@
             return activeTextures;
             return activeTextures;
         }
         }
 
 
+        /**
+         * Checks to see if a texture is used in the material.
+         * @param texture - Base texture to use.
+         * @returns - Boolean specifying if a texture is used in the material.
+         */
         public hasTexture(texture: BaseTexture): boolean {
         public hasTexture(texture: BaseTexture): boolean {
             if (super.hasTexture(texture)) {
             if (super.hasTexture(texture)) {
                 return true;
                 return true;
@@ -94,6 +99,10 @@
             return false;
             return false;
         }
         }
 
 
+        /**
+         * Makes a duplicate of the current material.
+         * @param name - name to use for the new material.
+         */
         public clone(name: string): PBRSpecularGlossinessMaterial {
         public clone(name: string): PBRSpecularGlossinessMaterial {
             var clone = SerializationHelper.Clone(() => new PBRSpecularGlossinessMaterial(name, this.getScene()), this);
             var clone = SerializationHelper.Clone(() => new PBRSpecularGlossinessMaterial(name, this.getScene()), this);
 
 

+ 1 - 1
src/Materials/Textures/babylon.mirrorTexture.ts

@@ -125,7 +125,7 @@
                 this._blurX.autoClear = false;
                 this._blurX.autoClear = false;
 
 
                 if (this._blurRatio === 1 && this.samples < 2 && this._texture) {
                 if (this._blurRatio === 1 && this.samples < 2 && this._texture) {
-                    this._blurX.outputTexture = this._texture;
+                    this._blurX.inputTexture = this._texture;
                 } else {
                 } else {
                     this._blurX.alwaysForcePOT = true;
                     this._blurX.alwaysForcePOT = true;
                 }
                 }

+ 396 - 4
src/Materials/babylon.effect.ts

@@ -1,4 +1,8 @@
 module BABYLON {
 module BABYLON {
+    /**
+	 * EffectFallbacks can be used to add fallbacks (properties to disable) to certain properties when desired to improve performance.
+     * (Eg. Start at high quality with reflection and fog, if fps is low, remove reflection, if still low remove fog)
+     */
     export class EffectFallbacks {
     export class EffectFallbacks {
         private _defines: { [key: string]: Array<String> } = {};
         private _defines: { [key: string]: Array<String> } = {};
 
 
@@ -7,10 +11,18 @@
 
 
         private _mesh: Nullable<AbstractMesh>;
         private _mesh: Nullable<AbstractMesh>;
 
 
+        /**
+         * Removes the fallback from the bound mesh.
+         */
         public unBindMesh() {
         public unBindMesh() {
             this._mesh = null;
             this._mesh = null;
         }
         }
 
 
+        /**
+         * Adds a fallback on the specified property.
+         * @param rank The rank of the fallback (Lower ranks will be fallbacked to first)
+         * @param define The name of the define in the shader
+         */
         public addFallback(rank: number, define: string): void {
         public addFallback(rank: number, define: string): void {
             if (!this._defines[rank]) {
             if (!this._defines[rank]) {
                 if (rank < this._currentRank) {
                 if (rank < this._currentRank) {
@@ -27,6 +39,11 @@
             this._defines[rank].push(define);
             this._defines[rank].push(define);
         }
         }
 
 
+        /**
+         * Sets the mesh to use CPU skinning when needing to fallback.
+         * @param rank The rank of the fallback (Lower ranks will be fallbacked to first)
+         * @param mesh The mesh to use the fallbacks.
+         */
         public addCPUSkinningFallback(rank: number, mesh: AbstractMesh) {
         public addCPUSkinningFallback(rank: number, mesh: AbstractMesh) {
             this._mesh = mesh;
             this._mesh = mesh;
 
 
@@ -38,10 +55,18 @@
             }
             }
         }
         }
 
 
+        /**
+         * Checks to see if more fallbacks are still availible.
+         */
         public get isMoreFallbacks(): boolean {
         public get isMoreFallbacks(): boolean {
             return this._currentRank <= this._maxRank;
             return this._currentRank <= this._maxRank;
         }
         }
 
 
+        /**
+         * Removes the defines that shoould be removed when falling back.
+         * @param currentDefines The current define statements for the shader.
+         * @returns The resulting defines with defines of the current rank removed.
+         */
         public reduce(currentDefines: string): string {
         public reduce(currentDefines: string): string {
             // First we try to switch to CPU skinning
             // 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) {
@@ -73,29 +98,95 @@
         }
         }
     }
     }
 
 
+    /**
+	 * Options to be used when creating an effect.
+     */
     export class EffectCreationOptions {
     export class EffectCreationOptions {
+        /**
+         * Atrributes that will be used in the shader.
+         */
         public attributes: string[];
         public attributes: string[];
+        /**
+         * Uniform varible names that will be set in the shader.
+         */
         public uniformsNames: string[];
         public uniformsNames: string[];
+        /**
+         * Uniform buffer varible names that will be set in the shader.
+         */
         public uniformBuffersNames: string[];
         public uniformBuffersNames: string[];
+        /**
+         * Sampler texture variable names that will be set in the shader.
+         */
         public samplers: string[];
         public samplers: string[];
+        /**
+         * Define statements that will be set in the shader.
+         */
         public defines: any;
         public defines: any;
+        /**
+         * Possible fallbacks for this effect to improve performance when needed.
+         */
         public fallbacks: Nullable<EffectFallbacks>;
         public fallbacks: Nullable<EffectFallbacks>;
+        /**
+         * Callback that will be called when the shader is compiled.
+         */
         public onCompiled: Nullable<(effect: Effect) => void>;
         public onCompiled: Nullable<(effect: Effect) => void>;
+        /**
+         * Callback that will be called if an error occurs during shader compilation.
+         */
         public onError: Nullable<(effect: Effect, errors: string) => void>;
         public onError: Nullable<(effect: Effect, errors: string) => void>;
+        /**
+         * Parameters to be used with Babylons include syntax to iterate over an array (eg. {lights: 10})
+         */
         public indexParameters: any;
         public indexParameters: any;
+        /**
+         * Max number of lights that can be used in the shader.
+         */
         public maxSimultaneousLights: number;
         public maxSimultaneousLights: number;
+        /**
+         * See https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/transformFeedbackVaryings
+         */
         public transformFeedbackVaryings: Nullable<string[]>;
         public transformFeedbackVaryings: Nullable<string[]>;
     }
     }
 
 
+    /**
+     * Effect containing vertex and fragment shader that can be executed on an object.
+     */
     export class Effect {
     export class Effect {
+        /**
+         * Name of the effect.
+         */
         public name: any;
         public name: any;
+        /**
+         * String container all the define statements that should be set on the shader.
+         */
         public defines: string;
         public defines: string;
+        /**
+         * Callback that will be called when the shader is compiled.
+         */
         public onCompiled: Nullable<(effect: Effect) => void>;
         public onCompiled: Nullable<(effect: Effect) => void>;
+        /**
+         * Callback that will be called if an error occurs during shader compilation.
+         */
         public onError: Nullable<(effect: Effect, errors: string) => void>;
         public onError: Nullable<(effect: Effect, errors: string) => void>;
+        /**
+         * Callback that will be called when effect is bound.
+         */
         public onBind: Nullable<(effect: Effect) => void>;
         public onBind: Nullable<(effect: Effect) => void>;
+        /**
+         * Unique ID of the effect.
+         */
         public uniqueId = 0;
         public uniqueId = 0;
+        /**
+         * Observable that will be called when the shader is compiled.
+         */
         public onCompileObservable = new Observable<Effect>();
         public onCompileObservable = new Observable<Effect>();
+        /**
+         * Observable that will be called if an error occurs during shader compilation.
+         */
         public onErrorObservable = new Observable<Effect>();
         public onErrorObservable = new Observable<Effect>();
+        /**
+         * Observable that will be called when effect is bound.
+         */
         public onBindObservable = new Observable<Effect>();
         public onBindObservable = new Observable<Effect>();
 
 
         private static _uniqueIdSeed = 0;
         private static _uniqueIdSeed = 0;
@@ -108,6 +199,9 @@
         private _attributesNames: string[];
         private _attributesNames: string[];
         private _attributes: number[];
         private _attributes: number[];
         private _uniforms: Nullable<WebGLUniformLocation>[];
         private _uniforms: Nullable<WebGLUniformLocation>[];
+        /**
+         * Key for the effect.
+         */
         public _key: string;
         public _key: string;
         private _indexParameters: any;
         private _indexParameters: any;
         private _fallbacks: Nullable<EffectFallbacks>;
         private _fallbacks: Nullable<EffectFallbacks>;
@@ -117,10 +211,27 @@
         private _fragmentSourceCodeOverride: string;
         private _fragmentSourceCodeOverride: string;
         private _transformFeedbackVaryings: Nullable<string[]>;
         private _transformFeedbackVaryings: Nullable<string[]>;
 
 
+        /**
+         * Compiled shader to webGL program.
+         */
         public _program: WebGLProgram;
         public _program: WebGLProgram;
         private _valueCache: { [key: string]: any };
         private _valueCache: { [key: string]: any };
         private static _baseCache: { [key: number]: WebGLBuffer } = {};
         private static _baseCache: { [key: number]: WebGLBuffer } = {};
 
 
+        /**
+         * Instantiates an effect.
+         * An effect can be used to create/manage/execute vertex and fragment shaders.
+         * @param baseName Name of the effect.
+         * @param attributesNamesOrOptions List of attribute names that will be passed to the shader or set of all options to create the effect.
+         * @param uniformsNamesOrEngine List of uniform variable names that will be passed to the shader or the engine that will be used to render effect.
+         * @param samplers List of sampler variables that will be passed to the shader.
+         * @param engine Engine to be used to render the effect
+         * @param defines Define statements to be added to the shader.
+         * @param fallbacks Possible fallbacks for this effect to improve performance when needed.
+         * @param onCompiled Callback that will be called when the shader is compiled.
+         * @param onError Callback that will be called if an error occurs during shader compilation.
+         * @param indexParameters Parameters to be used with Babylons include syntax to iterate over an array (eg. {lights: 10})
+         */
         constructor(baseName: any, attributesNamesOrOptions: string[] | EffectCreationOptions, uniformsNamesOrEngine: string[] | Engine, samplers: Nullable<string[]> = null, engine?: Engine, defines: Nullable<string> = null,
         constructor(baseName: any, attributesNamesOrOptions: string[] | EffectCreationOptions, uniformsNamesOrEngine: string[] | Engine, samplers: Nullable<string[]> = null, engine?: Engine, defines: Nullable<string> = null,
             fallbacks: Nullable<EffectFallbacks> = null, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, indexParameters?: any) {
             fallbacks: Nullable<EffectFallbacks> = null, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, indexParameters?: any) {
             this.name = baseName;
             this.name = baseName;
@@ -212,58 +323,110 @@
             });
             });
         }
         }
 
 
+        /**
+         * Unique key for this effect
+         */
         public get key(): string {
         public get key(): string {
             return this._key;
             return this._key;
         }
         }
 
 
-        // Properties
+        /**
+         * If the effect has been compiled and prepared.
+         * @returns if the effect is compiled and prepared.
+         */
         public isReady(): boolean {
         public isReady(): boolean {
             return this._isReady;
             return this._isReady;
         }
         }
 
 
+        /**
+         * The engine the effect was initialized with.
+         * @returns the engine.
+         */
         public getEngine(): Engine {
         public getEngine(): Engine {
             return this._engine;
             return this._engine;
         }
         }
 
 
+        /**
+         * The compiled webGL program for the effect
+         * @returns the webGL program.
+         */
         public getProgram(): WebGLProgram {
         public getProgram(): WebGLProgram {
             return this._program;
             return this._program;
         }
         }
-
+        /**
+         * The set of names of attribute variables for the shader.
+         * @returns An array of attribute names.
+         */
         public getAttributesNames(): string[] {
         public getAttributesNames(): string[] {
             return this._attributesNames;
             return this._attributesNames;
         }
         }
 
 
+        /**
+         * Returns the attribute at the given index.
+         * @param index The index of the attribute.
+         * @returns The location of the attribute.
+         */
         public getAttributeLocation(index: number): number {
         public getAttributeLocation(index: number): number {
             return this._attributes[index];
             return this._attributes[index];
         }
         }
 
 
+        /**
+         * Returns the attribute based on the name of the variable.
+         * @param name of the attribute to look up.
+         * @returns the attribute location.
+         */
         public getAttributeLocationByName(name: string): number {
         public getAttributeLocationByName(name: string): number {
             var index = this._attributesNames.indexOf(name);
             var index = this._attributesNames.indexOf(name);
 
 
             return this._attributes[index];
             return this._attributes[index];
         }
         }
 
 
+        /**
+         * The number of attributes.
+         * @returns the numnber of attributes.
+         */
         public getAttributesCount(): number {
         public getAttributesCount(): number {
             return this._attributes.length;
             return this._attributes.length;
         }
         }
 
 
+        /**
+         * Gets the index of a uniform variable.
+         * @param uniformName of the uniform to look up.
+         * @returns the index.
+         */
         public getUniformIndex(uniformName: string): number {
         public getUniformIndex(uniformName: string): number {
             return this._uniformsNames.indexOf(uniformName);
             return this._uniformsNames.indexOf(uniformName);
         }
         }
 
 
+        /**
+         * Returns the attribute based on the name of the variable.
+         * @param uniformName of the uniform to look up.
+         * @returns the location of the uniform.
+         */
         public getUniform(uniformName: string): Nullable<WebGLUniformLocation> {
         public getUniform(uniformName: string): Nullable<WebGLUniformLocation> {
             return this._uniforms[this._uniformsNames.indexOf(uniformName)];
             return this._uniforms[this._uniformsNames.indexOf(uniformName)];
         }
         }
 
 
+        /**
+         * Returns an array of sampler variable names
+         * @returns The array of sampler variable neames.
+         */
         public getSamplers(): string[] {
         public getSamplers(): string[] {
             return this._samplers;
             return this._samplers;
         }
         }
 
 
+        /**
+         * The error from the last compilation.
+         * @returns the error string.
+         */
         public getCompilationError(): string {
         public getCompilationError(): string {
             return this._compilationError;
             return this._compilationError;
         }
         }
 
 
-        // Methods
+        /**
+         * Adds a callback to the onCompiled observable and call the callback imediatly if already ready.
+         * @param func The callback to be used.
+         */
         public executeWhenCompiled(func: (effect: Effect) => void): void {
         public executeWhenCompiled(func: (effect: Effect) => void): void {
             if (this.isReady()) {
             if (this.isReady()) {
                 func(this);
                 func(this);
@@ -521,6 +684,13 @@
             return source;
             return source;
         }
         }
 
 
+        /**
+         * Recompiles the webGL program
+         * @param vertexSourceCode The source code for the vertex shader.
+         * @param fragmentSourceCode The source code for the fragment shader.
+         * @param onCompiled Callback called when completed.
+         * @param onError Callback called on error.
+         */
         public _rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void) {
         public _rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void) {
             this._isReady = false;
             this._isReady = false;
 
 
@@ -545,11 +715,19 @@
             this._prepareEffect();
             this._prepareEffect();
         }
         }
 
 
+        /**
+         * Gets the uniform locations of the the specified variable names
+         * @param names THe names of the variables to lookup.
+         * @returns Array of locations in the same order as variable names.
+         */
         public getSpecificUniformLocations(names: string[]): Nullable<WebGLUniformLocation>[] {
         public getSpecificUniformLocations(names: string[]): Nullable<WebGLUniformLocation>[] {
             let engine = this._engine;
             let engine = this._engine;
             return engine.getUniforms(this._program, names);
             return engine.getUniforms(this._program, names);
         }
         }
 
 
+        /**
+         * Prepares the effect
+         */
         public _prepareEffect() {
         public _prepareEffect() {
             let attributesNames = this._attributesNames;
             let attributesNames = this._attributesNames;
             let defines = this.defines;
             let defines = this.defines;
@@ -648,18 +826,35 @@
             }
             }
         }
         }
 
 
+        /**
+         * Checks if the effect is supported. (Must be called after compilation)
+         */
         public get isSupported(): boolean {
         public get isSupported(): boolean {
             return this._compilationError === "";
             return this._compilationError === "";
         }
         }
 
 
+        /**
+         * Binds a texture to the engine to be used as output of the shader.
+         * @param channel Name of the output variable.
+         * @param texture Texture to bind.
+         */
         public _bindTexture(channel: string, texture: InternalTexture): void {
         public _bindTexture(channel: string, texture: InternalTexture): void {
             this._engine._bindTexture(this._samplers.indexOf(channel), texture);
             this._engine._bindTexture(this._samplers.indexOf(channel), texture);
         }
         }
 
 
+        /**
+         * Sets a texture on the engine to be used in the shader.
+         * @param channel Name of the sampler variable.
+         * @param texture Texture to set.
+         */
         public setTexture(channel: string, texture: Nullable<BaseTexture>): void {
         public setTexture(channel: string, texture: Nullable<BaseTexture>): void {
             this._engine.setTexture(this._samplers.indexOf(channel), this.getUniform(channel), texture);
             this._engine.setTexture(this._samplers.indexOf(channel), this.getUniform(channel), texture);
         }
         }
-
+        /**
+         * Sets an array of textures on the engine to be used in the shader.
+         * @param channel Name of the variable.
+         * @param textures Textures to set.
+         */
         public setTextureArray(channel: string, textures: BaseTexture[]): void {
         public setTextureArray(channel: string, textures: BaseTexture[]): void {
             if (this._samplers.indexOf(channel + "Ex") === -1) {
             if (this._samplers.indexOf(channel + "Ex") === -1) {
                 var initialPos = this._samplers.indexOf(channel);
                 var initialPos = this._samplers.indexOf(channel);
@@ -671,10 +866,16 @@
             this._engine.setTextureArray(this._samplers.indexOf(channel), this.getUniform(channel), textures);
             this._engine.setTextureArray(this._samplers.indexOf(channel), this.getUniform(channel), textures);
         }
         }
 
 
+        /**
+         * Sets a texture to be the input of the specified post process. (To use the output, pass in the next post process in the pipeline)
+         * @param channel Name of the sampler variable.
+         * @param postProcess Post process to get the input texture from.
+         */
         public setTextureFromPostProcess(channel: string, postProcess: Nullable<PostProcess>): void {
         public setTextureFromPostProcess(channel: string, postProcess: Nullable<PostProcess>): void {
             this._engine.setTextureFromPostProcess(this._samplers.indexOf(channel), postProcess);
             this._engine.setTextureFromPostProcess(this._samplers.indexOf(channel), postProcess);
         }
         }
 
 
+        /** @ignore */
         public _cacheMatrix(uniformName: string, matrix: Matrix): boolean {
         public _cacheMatrix(uniformName: string, matrix: Matrix): boolean {
             var cache = this._valueCache[uniformName];
             var cache = this._valueCache[uniformName];
             var flag = matrix.updateFlag;
             var flag = matrix.updateFlag;
@@ -687,6 +888,7 @@
             return true;
             return true;
         }
         }
 
 
+        /** @ignore */
         public _cacheFloat2(uniformName: string, x: number, y: number): boolean {
         public _cacheFloat2(uniformName: string, x: number, y: number): boolean {
             var cache = this._valueCache[uniformName];
             var cache = this._valueCache[uniformName];
             if (!cache) {
             if (!cache) {
@@ -708,6 +910,7 @@
             return changed;
             return changed;
         }
         }
 
 
+        /** @ignore */
         public _cacheFloat3(uniformName: string, x: number, y: number, z: number): boolean {
         public _cacheFloat3(uniformName: string, x: number, y: number, z: number): boolean {
             var cache = this._valueCache[uniformName];
             var cache = this._valueCache[uniformName];
             if (!cache) {
             if (!cache) {
@@ -733,6 +936,7 @@
             return changed;
             return changed;
         }
         }
 
 
+        /** @ignore */
         public _cacheFloat4(uniformName: string, x: number, y: number, z: number, w: number): boolean {
         public _cacheFloat4(uniformName: string, x: number, y: number, z: number, w: number): boolean {
             var cache = this._valueCache[uniformName];
             var cache = this._valueCache[uniformName];
             if (!cache) {
             if (!cache) {
@@ -762,6 +966,11 @@
             return changed;
             return changed;
         }
         }
 
 
+        /**
+         * Binds a buffer to a uniform.
+         * @param buffer Buffer to bind.
+         * @param name Name of the uniform variable to bind to.
+         */
         public bindUniformBuffer(buffer: WebGLBuffer, name: string): void {
         public bindUniformBuffer(buffer: WebGLBuffer, name: string): void {
             let bufferName = this._uniformBuffersNames[name];
             let bufferName = this._uniformBuffersNames[name];
             if (bufferName === undefined || Effect._baseCache[bufferName] === buffer) {
             if (bufferName === undefined || Effect._baseCache[bufferName] === buffer) {
@@ -771,10 +980,21 @@
             this._engine.bindUniformBufferBase(buffer, bufferName);
             this._engine.bindUniformBufferBase(buffer, bufferName);
         }
         }
 
 
+        /**
+         * Binds block to a uniform.
+         * @param blockName Name of the block to bind.
+         * @param index Index to bind.
+         */
         public bindUniformBlock(blockName: string, index: number): void {
         public bindUniformBlock(blockName: string, index: number): void {
             this._engine.bindUniformBlock(this._program, blockName, index);
             this._engine.bindUniformBlock(this._program, blockName, index);
         }
         }
 
 
+        /**
+         * Sets an interger value on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param value Value to be set.
+         * @returns this effect.
+         */
         public setInt(uniformName: string, value: number): Effect {
         public setInt(uniformName: string, value: number): Effect {
             var cache = this._valueCache[uniformName];
             var cache = this._valueCache[uniformName];
             if (cache !== undefined && cache === value)
             if (cache !== undefined && cache === value)
@@ -787,6 +1007,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an int array on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setIntArray(uniformName: string, array: Int32Array): Effect {
         public setIntArray(uniformName: string, array: Int32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setIntArray(this.getUniform(uniformName), array);
             this._engine.setIntArray(this.getUniform(uniformName), array);
@@ -794,6 +1020,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an int array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setIntArray2(uniformName: string, array: Int32Array): Effect {
         public setIntArray2(uniformName: string, array: Int32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setIntArray2(this.getUniform(uniformName), array);
             this._engine.setIntArray2(this.getUniform(uniformName), array);
@@ -801,6 +1033,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an int array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setIntArray3(uniformName: string, array: Int32Array): Effect {
         public setIntArray3(uniformName: string, array: Int32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setIntArray3(this.getUniform(uniformName), array);
             this._engine.setIntArray3(this.getUniform(uniformName), array);
@@ -808,6 +1046,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an int array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setIntArray4(uniformName: string, array: Int32Array): Effect {
         public setIntArray4(uniformName: string, array: Int32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setIntArray4(this.getUniform(uniformName), array);
             this._engine.setIntArray4(this.getUniform(uniformName), array);
@@ -815,6 +1059,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an float array on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setFloatArray(uniformName: string, array: Float32Array): Effect {
         public setFloatArray(uniformName: string, array: Float32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setFloatArray(this.getUniform(uniformName), array);
             this._engine.setFloatArray(this.getUniform(uniformName), array);
@@ -822,6 +1072,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an float array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setFloatArray2(uniformName: string, array: Float32Array): Effect {
         public setFloatArray2(uniformName: string, array: Float32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setFloatArray2(this.getUniform(uniformName), array);
             this._engine.setFloatArray2(this.getUniform(uniformName), array);
@@ -829,6 +1085,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an float array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setFloatArray3(uniformName: string, array: Float32Array): Effect {
         public setFloatArray3(uniformName: string, array: Float32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setFloatArray3(this.getUniform(uniformName), array);
             this._engine.setFloatArray3(this.getUniform(uniformName), array);
@@ -836,6 +1098,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an float array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setFloatArray4(uniformName: string, array: Float32Array): Effect {
         public setFloatArray4(uniformName: string, array: Float32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setFloatArray4(this.getUniform(uniformName), array);
             this._engine.setFloatArray4(this.getUniform(uniformName), array);
@@ -843,6 +1111,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an array on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setArray(uniformName: string, array: number[]): Effect {
         public setArray(uniformName: string, array: number[]): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setArray(this.getUniform(uniformName), array);
             this._engine.setArray(this.getUniform(uniformName), array);
@@ -850,6 +1124,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setArray2(uniformName: string, array: number[]): Effect {
         public setArray2(uniformName: string, array: number[]): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setArray2(this.getUniform(uniformName), array);
             this._engine.setArray2(this.getUniform(uniformName), array);
@@ -857,6 +1137,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setArray3(uniformName: string, array: number[]): Effect {
         public setArray3(uniformName: string, array: number[]): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setArray3(this.getUniform(uniformName), array);
             this._engine.setArray3(this.getUniform(uniformName), array);
@@ -864,6 +1150,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets an array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
+         * @param uniformName Name of the variable.
+         * @param array array to be set.
+         * @returns this effect.
+         */
         public setArray4(uniformName: string, array: number[]): Effect {
         public setArray4(uniformName: string, array: number[]): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setArray4(this.getUniform(uniformName), array);
             this._engine.setArray4(this.getUniform(uniformName), array);
@@ -871,6 +1163,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets matrices on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param matrices matrices to be set.
+         * @returns this effect.
+         */
         public setMatrices(uniformName: string, matrices: Float32Array): Effect {
         public setMatrices(uniformName: string, matrices: Float32Array): Effect {
             if (!matrices) {
             if (!matrices) {
                 return this;
                 return this;
@@ -882,6 +1180,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets matrix on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param matrix matrix to be set.
+         * @returns this effect.
+         */
         public setMatrix(uniformName: string, matrix: Matrix): Effect {
         public setMatrix(uniformName: string, matrix: Matrix): Effect {
             if (this._cacheMatrix(uniformName, matrix)) {
             if (this._cacheMatrix(uniformName, matrix)) {
                 this._engine.setMatrix(this.getUniform(uniformName), matrix);
                 this._engine.setMatrix(this.getUniform(uniformName), matrix);
@@ -889,6 +1193,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a 3x3 matrix on a uniform variable. (Speicified as [1,2,3,4,5,6,7,8,9] will result in [1,2,3][4,5,6][7,8,9] matrix)
+         * @param uniformName Name of the variable.
+         * @param matrix matrix to be set.
+         * @returns this effect.
+         */
         public setMatrix3x3(uniformName: string, matrix: Float32Array): Effect {
         public setMatrix3x3(uniformName: string, matrix: Float32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setMatrix3x3(this.getUniform(uniformName), matrix);
             this._engine.setMatrix3x3(this.getUniform(uniformName), matrix);
@@ -896,6 +1206,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a 2x2 matrix on a uniform variable. (Speicified as [1,2,3,4] will result in [1,2][3,4] matrix)
+         * @param uniformName Name of the variable.
+         * @param matrix matrix to be set.
+         * @returns this effect.
+         */
         public setMatrix2x2(uniformName: string, matrix: Float32Array): Effect {
         public setMatrix2x2(uniformName: string, matrix: Float32Array): Effect {
             this._valueCache[uniformName] = null;
             this._valueCache[uniformName] = null;
             this._engine.setMatrix2x2(this.getUniform(uniformName), matrix);
             this._engine.setMatrix2x2(this.getUniform(uniformName), matrix);
@@ -903,6 +1219,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a float on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param value value to be set.
+         * @returns this effect.
+         */
         public setFloat(uniformName: string, value: number): Effect {
         public setFloat(uniformName: string, value: number): Effect {
             var cache = this._valueCache[uniformName];
             var cache = this._valueCache[uniformName];
             if (cache !== undefined && cache === value)
             if (cache !== undefined && cache === value)
@@ -915,6 +1237,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a boolean on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param bool value to be set.
+         * @returns this effect.
+         */
         public setBool(uniformName: string, bool: boolean): Effect {
         public setBool(uniformName: string, bool: boolean): Effect {
             var cache = this._valueCache[uniformName];
             var cache = this._valueCache[uniformName];
             if (cache !== undefined && cache === bool)
             if (cache !== undefined && cache === bool)
@@ -927,6 +1255,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a Vector2 on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param vector2 vector2 to be set.
+         * @returns this effect.
+         */
         public setVector2(uniformName: string, vector2: Vector2): Effect {
         public setVector2(uniformName: string, vector2: Vector2): Effect {
             if (this._cacheFloat2(uniformName, vector2.x, vector2.y)) {
             if (this._cacheFloat2(uniformName, vector2.x, vector2.y)) {
                 this._engine.setFloat2(this.getUniform(uniformName), vector2.x, vector2.y);
                 this._engine.setFloat2(this.getUniform(uniformName), vector2.x, vector2.y);
@@ -934,6 +1268,13 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a float2 on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param x First float in float2.
+         * @param y Second float in float2.
+         * @returns this effect.
+         */
         public setFloat2(uniformName: string, x: number, y: number): Effect {
         public setFloat2(uniformName: string, x: number, y: number): Effect {
             if (this._cacheFloat2(uniformName, x, y)) {
             if (this._cacheFloat2(uniformName, x, y)) {
                 this._engine.setFloat2(this.getUniform(uniformName), x, y);
                 this._engine.setFloat2(this.getUniform(uniformName), x, y);
@@ -941,6 +1282,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a Vector3 on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param vector3 Value to be set.
+         * @returns this effect.
+         */
         public setVector3(uniformName: string, vector3: Vector3): Effect {
         public setVector3(uniformName: string, vector3: Vector3): Effect {
             if (this._cacheFloat3(uniformName, vector3.x, vector3.y, vector3.z)) {
             if (this._cacheFloat3(uniformName, vector3.x, vector3.y, vector3.z)) {
                 this._engine.setFloat3(this.getUniform(uniformName), vector3.x, vector3.y, vector3.z);
                 this._engine.setFloat3(this.getUniform(uniformName), vector3.x, vector3.y, vector3.z);
@@ -948,6 +1295,14 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a float3 on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param x First float in float3.
+         * @param y Second float in float3.
+         * @param z Third float in float3.
+         * @returns this effect.
+         */
         public setFloat3(uniformName: string, x: number, y: number, z: number): Effect {
         public setFloat3(uniformName: string, x: number, y: number, z: number): Effect {
             if (this._cacheFloat3(uniformName, x, y, z)) {
             if (this._cacheFloat3(uniformName, x, y, z)) {
                 this._engine.setFloat3(this.getUniform(uniformName), x, y, z);
                 this._engine.setFloat3(this.getUniform(uniformName), x, y, z);
@@ -955,6 +1310,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a Vector4 on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param vector4 Value to be set.
+         * @returns this effect.
+         */
         public setVector4(uniformName: string, vector4: Vector4): Effect {
         public setVector4(uniformName: string, vector4: Vector4): Effect {
             if (this._cacheFloat4(uniformName, vector4.x, vector4.y, vector4.z, vector4.w)) {
             if (this._cacheFloat4(uniformName, vector4.x, vector4.y, vector4.z, vector4.w)) {
                 this._engine.setFloat4(this.getUniform(uniformName), vector4.x, vector4.y, vector4.z, vector4.w);
                 this._engine.setFloat4(this.getUniform(uniformName), vector4.x, vector4.y, vector4.z, vector4.w);
@@ -962,6 +1323,15 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a float4 on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param x First float in float4.
+         * @param y Second float in float4.
+         * @param z Third float in float4.
+         * @param w Fourth float in float4.
+         * @returns this effect.
+         */
         public setFloat4(uniformName: string, x: number, y: number, z: number, w: number): Effect {
         public setFloat4(uniformName: string, x: number, y: number, z: number, w: number): Effect {
             if (this._cacheFloat4(uniformName, x, y, z, w)) {
             if (this._cacheFloat4(uniformName, x, y, z, w)) {
                 this._engine.setFloat4(this.getUniform(uniformName), x, y, z, w);
                 this._engine.setFloat4(this.getUniform(uniformName), x, y, z, w);
@@ -969,6 +1339,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a Color3 on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param color3 Value to be set.
+         * @returns this effect.
+         */
         public setColor3(uniformName: string, color3: Color3): Effect {
         public setColor3(uniformName: string, color3: Color3): Effect {
 
 
             if (this._cacheFloat3(uniformName, color3.r, color3.g, color3.b)) {
             if (this._cacheFloat3(uniformName, color3.r, color3.g, color3.b)) {
@@ -977,6 +1353,13 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Sets a Color4 on a uniform variable.
+         * @param uniformName Name of the variable.
+         * @param color3 Value to be set.
+         * @param alpha Alpha value to be set.
+         * @returns this effect.
+         */
         public setColor4(uniformName: string, color3: Color3, alpha: number): Effect {
         public setColor4(uniformName: string, color3: Color3, alpha: number): Effect {
             if (this._cacheFloat4(uniformName, color3.r, color3.g, color3.b, alpha)) {
             if (this._cacheFloat4(uniformName, color3.r, color3.g, color3.b, alpha)) {
                 this._engine.setColor4(this.getUniform(uniformName), color3, alpha);
                 this._engine.setColor4(this.getUniform(uniformName), color3, alpha);
@@ -985,9 +1368,18 @@
         }
         }
 
 
         // Statics
         // Statics
+        /**
+         * Store of each shader (The can be looked up using effect.key)
+         */
         public static ShadersStore: { [key: string]: string } = {};
         public static ShadersStore: { [key: string]: string } = {};
+        /**
+         * Store of each included file for a shader (The can be looked up using effect.key)
+         */
         public static IncludesShadersStore: { [key: string]: string } = {};
         public static IncludesShadersStore: { [key: string]: string } = {};
 
 
+        /**
+         * Resets the cache of effects.
+         */
         public static ResetCache() {
         public static ResetCache() {
             Effect._baseCache = {};
             Effect._baseCache = {};
         }
         }

File diff suppressed because it is too large
+ 474 - 6
src/Materials/babylon.material.ts


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

@@ -2382,7 +2382,7 @@
             mesh.scaling = Vector3.FromArray(parsedMesh.scaling);
             mesh.scaling = Vector3.FromArray(parsedMesh.scaling);
 
 
             if (parsedMesh.localMatrix) {
             if (parsedMesh.localMatrix) {
-                mesh.setPivotMatrix(Matrix.FromArray(parsedMesh.localMatrix));
+                mesh.setPreTransformMatrix(Matrix.FromArray(parsedMesh.localMatrix));
             } else if (parsedMesh.pivotMatrix) {
             } else if (parsedMesh.pivotMatrix) {
                 mesh.setPivotMatrix(Matrix.FromArray(parsedMesh.pivotMatrix));
                 mesh.setPivotMatrix(Matrix.FromArray(parsedMesh.pivotMatrix));
             }
             }

+ 14 - 20
src/Mesh/babylon.transformNode.ts

@@ -208,12 +208,21 @@ module BABYLON {
         }
         }
 
 
         /**
         /**
+         * Sets a new matrix to apply before all other transformation
+         * @param matrix defines the transform matrix
+         * @returns the current TransformNode
+         */
+        public setPreTransformMatrix(matrix: Matrix): TransformNode {
+            return this.setPivotMatrix(matrix, false);
+        }
+
+        /**
          * Sets a new pivot matrix to the current node
          * Sets a new pivot matrix to the current node
          * @param matrix defines the new pivot matrix to use
          * @param matrix defines the new pivot matrix to use
-         * @param postMultiplyPivotMatrix defines if the pivot matrix must be cancelled in the world matrix. By default the pivot matrix is just applied at the beginning of the world matrix. When this parameter is set to true, the inverse of the pivot matrix is also applied at the end to cancel the transformation effect
+         * @param postMultiplyPivotMatrix defines if the pivot matrix must be cancelled in the world matrix. When this parameter is set to true (default), the inverse of the pivot matrix is also applied at the end to cancel the transformation effect
          * @returns the current TransformNode
          * @returns the current TransformNode
         */
         */
-        public setPivotMatrix(matrix: Matrix, postMultiplyPivotMatrix = false): TransformNode {
+        public setPivotMatrix(matrix: Matrix, postMultiplyPivotMatrix = true): TransformNode {
             this._pivotMatrix = matrix.clone();
             this._pivotMatrix = matrix.clone();
             this._cache.pivotMatrixUpdated = true;
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
@@ -401,10 +410,9 @@ module BABYLON {
          * Sets a new pivot point to the current node
          * Sets a new pivot point to the current node
          * @param point defines the new pivot point to use
          * @param point defines the new pivot point to use
          * @param space defines if the point is in world or local space (local by default)
          * @param space defines if the point is in world or local space (local by default)
-         * @param postMultiplyPivotMatrix defines if the pivot transformation must be cancelled in the world matrix. By default the pivot matrix is just applied at the beginning of the world matrix. When this parameter is set to true, the inverse of the pivot matrix is also applied at the end to cancel the transformation effect
          * @returns the current TransformNode
          * @returns the current TransformNode
         */        
         */        
-        public setPivotPoint(point: Vector3, space: Space = Space.LOCAL, postMultiplyPivotMatrix = false): TransformNode {
+        public setPivotPoint(point: Vector3, space: Space = Space.LOCAL): TransformNode {
             if (this.getScene().getRenderId() == 0) {
             if (this.getScene().getRenderId() == 0) {
                 this.computeWorldMatrix(true);
                 this.computeWorldMatrix(true);
             }
             }
@@ -417,21 +425,7 @@ module BABYLON {
                 point = Vector3.TransformCoordinates(point, tmat);
                 point = Vector3.TransformCoordinates(point, tmat);
             }
             }
 
 
-            Vector3.TransformCoordinatesToRef(point, wm, this.position);
-            this._pivotMatrix.m[12] = -point.x;
-            this._pivotMatrix.m[13] = -point.y;
-            this._pivotMatrix.m[14] = -point.z;
-
-            if (this._postMultiplyPivotMatrix) {
-                if (!this._pivotMatrixInverse) {
-                    this._pivotMatrixInverse = Matrix.Invert(this._pivotMatrix);
-                } else {
-                    this._pivotMatrix.invertToRef(this._pivotMatrixInverse);
-                }
-            }
-
-            this._cache.pivotMatrixUpdated = true;
-            return this;
+            return this.setPivotMatrix(Matrix.Translation(point.x, point.y, point.z), true);
         }
         }
 
 
         /**
         /**
@@ -955,7 +949,7 @@ module BABYLON {
             }
             }
 
 
             if (parsedTransformNode.localMatrix) {
             if (parsedTransformNode.localMatrix) {
-                transformNode.setPivotMatrix(Matrix.FromArray(parsedTransformNode.localMatrix));
+                transformNode.setPreTransformMatrix(Matrix.FromArray(parsedTransformNode.localMatrix));
             } else if (parsedTransformNode.pivotMatrix) {
             } else if (parsedTransformNode.pivotMatrix) {
                 transformNode.setPivotMatrix(Matrix.FromArray(parsedTransformNode.pivotMatrix));
                 transformNode.setPivotMatrix(Matrix.FromArray(parsedTransformNode.pivotMatrix));
             }
             }

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

@@ -41,6 +41,12 @@ module BABYLON {
          */
          */
         public pivot: Vector3 = Vector3.Zero();
         public pivot: Vector3 = Vector3.Zero();
         /**
         /**
+         * Must the particle be translated from its pivot point in its local space ?
+         * In this case, the pivot point is set at the origin of the particle local space and the particle is translated.  
+         * Default : false
+         */
+        public translateFromPivot: boolean = false;
+        /**
          * Is the particle active or not ?
          * Is the particle active or not ?
          */
          */
         public alive: boolean = true;
         public alive: boolean = true;

+ 42 - 9
src/Particles/babylon.solidParticleSystem.ts

@@ -133,6 +133,7 @@
                     return (p2.sqDistance - p1.sqDistance);
                     return (p2.sqDistance - p1.sqDistance);
                 };
                 };
             private _needs32Bits: boolean = false;
             private _needs32Bits: boolean = false;
+            private _pivotBackTranslation: Vector3 = Vector3.Zero();
 
 
             /**
             /**
              * Creates a SPS (Solid Particle System) object.
              * Creates a SPS (Solid Particle System) object.
@@ -373,6 +374,7 @@
                 this._copy.uvs.z = 1.0;
                 this._copy.uvs.z = 1.0;
                 this._copy.uvs.w = 1.0;
                 this._copy.uvs.w = 1.0;
                 this._copy.color = null;
                 this._copy.color = null;
+                this._copy.translateFromPivot = false;
             }
             }
     
     
             // _meshBuilder : inserts the shape model in the global SPS mesh
             // _meshBuilder : inserts the shape model in the global SPS mesh
@@ -397,6 +399,13 @@
                     this._quaternionRotationYPR();
                     this._quaternionRotationYPR();
                 }
                 }
                 this._quaternionToRotationMatrix();
                 this._quaternionToRotationMatrix();
+                
+                if (this._copy.translateFromPivot) {
+                    this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
+                }
+                else {
+                    this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                }
     
     
                 for (i = 0; i < shape.length; i++) {
                 for (i = 0; i < shape.length; i++) {
                     this._vertex.x = shape[i].x;
                     this._vertex.x = shape[i].x;
@@ -411,11 +420,13 @@
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.z *= this._copy.scaling.z;
                     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._copy.pivot.x;
+                    this._vertex.y -= this._copy.pivot.y;
+                    this._vertex.z -= this._copy.pivot.z;
     
     
                     Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                     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);
                     positions.push(this._copy.position.x + this._rotated.x, this._copy.position.y + this._rotated.y, this._copy.position.z + this._rotated.z);
                     if (meshUV) {
                     if (meshUV) {
                         uvs.push((this._copy.uvs.z - this._copy.uvs.x) * meshUV[u] + this._copy.uvs.x, (this._copy.uvs.w - this._copy.uvs.y) * meshUV[u + 1] + this._copy.uvs.y);
                         uvs.push((this._copy.uvs.z - this._copy.uvs.x) * meshUV[u] + this._copy.uvs.x, (this._copy.uvs.w - this._copy.uvs.y) * meshUV[u + 1] + this._copy.uvs.y);
@@ -570,6 +581,13 @@
                     this._quaternionRotationYPR();
                     this._quaternionRotationYPR();
                 }
                 }
                 this._quaternionToRotationMatrix();
                 this._quaternionToRotationMatrix();
+
+                if (this._copy.translateFromPivot) {
+                    this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
+                }
+                else {
+                    this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                }
     
     
                 this._shape = particle._model._shape;
                 this._shape = particle._model._shape;
                 for (var pt = 0; pt < this._shape.length; pt++) {
                 for (var pt = 0; pt < this._shape.length; pt++) {
@@ -585,11 +603,12 @@
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.z *= this._copy.scaling.z;
                     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._copy.pivot.x;
+                    this._vertex.y -= this._copy.pivot.y;
+                    this._vertex.z -= this._copy.pivot.z;
     
     
                     Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                     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;
                     this._positions32[particle._pos + pt * 3] = this._copy.position.x + this._rotated.x;
                     this._positions32[particle._pos + pt * 3 + 1] = this._copy.position.y + this._rotated.y;
                     this._positions32[particle._pos + pt * 3 + 1] = this._copy.position.y + this._rotated.y;
@@ -759,6 +778,16 @@
                             this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
                             this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
                         }
                         }
        
        
+                        if (this._particle.translateFromPivot) {
+                            this._pivotBackTranslation.x = 0.0;
+                            this._pivotBackTranslation.y = 0.0;
+                            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;
+                        }
                         // particle vertex loop
                         // particle vertex loop
                         for (pt = 0; pt < this._shape.length; pt++) {
                         for (pt = 0; pt < this._shape.length; pt++) {
                             idx = index + pt * 3;
                             idx = index + pt * 3;
@@ -778,14 +807,18 @@
                             this._vertex.y *= this._particle.scaling.y;
                             this._vertex.y *= this._particle.scaling.y;
                             this._vertex.z *= this._particle.scaling.z;
                             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._particle.pivot.x;
+                            this._vertex.y -= this._particle.pivot.y;
+                            this._vertex.z -= this._particle.pivot.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.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.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.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] = 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 + 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 + 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;

+ 2 - 2
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -435,7 +435,7 @@
 
 
                 //calculate the new center using a pivot (since this.BJSCANNON.js doesn't center height maps)
                 //calculate the new center using a pivot (since this.BJSCANNON.js doesn't center height maps)
                 var p = Matrix.Translation(boundingInfo.boundingBox.extendSizeWorld.x, 0, -boundingInfo.boundingBox.extendSizeWorld.z);
                 var p = Matrix.Translation(boundingInfo.boundingBox.extendSizeWorld.x, 0, -boundingInfo.boundingBox.extendSizeWorld.z);
-                mesh.setPivotMatrix(p);
+                mesh.setPreTransformMatrix(p);
                 mesh.computeWorldMatrix(true);
                 mesh.computeWorldMatrix(true);
 
 
                 //calculate the translation
                 //calculate the translation
@@ -448,7 +448,7 @@
                 //rotation is back
                 //rotation is back
                 mesh.rotationQuaternion = rotationQuaternion;
                 mesh.rotationQuaternion = rotationQuaternion;
 
 
-                mesh.setPivotMatrix(oldPivot);
+                mesh.setPreTransformMatrix(oldPivot);
                 mesh.computeWorldMatrix(true);
                 mesh.computeWorldMatrix(true);
             } else if (impostor.type === PhysicsImpostor.MeshImpostor) {
             } else if (impostor.type === PhysicsImpostor.MeshImpostor) {
                 this._tmpDeltaPosition.copyFromFloats(0, 0, 0);
                 this._tmpDeltaPosition.copyFromFloats(0, 0, 0);

+ 12 - 9
src/PostProcess/babylon.postProcess.ts

@@ -179,13 +179,14 @@
         }
         }
 
 
         /**
         /**
-        * The resulting output of the post process.
+        * The input texture for this post process and the output texture of the previous post process. When added to a pipeline the previous post process will
+        * render it's output into this texture and this texture will be used as textureSampler in the fragment shader of this post process.
         */
         */
-        public get outputTexture(): InternalTexture {
+        public get inputTexture(): InternalTexture {
             return this._textures.data[this._currentRenderTextureInd];
             return this._textures.data[this._currentRenderTextureInd];
         }
         }
 
 
-        public set outputTexture(value: InternalTexture) {
+        public set inputTexture(value: InternalTexture) {
             this._forcedOutputTexture = value;
             this._forcedOutputTexture = value;
         }
         }
 
 
@@ -228,7 +229,7 @@
          * @param textureType Type of textures used when performing the post process. (default: 0)
          * @param textureType Type of textures used when performing the post process. (default: 0)
          * @param vertexUrl The url of the vertex shader to be used. (default: "postprocess")
          * @param vertexUrl The url of the vertex shader to be used. (default: "postprocess")
          * @param indexParameters The index parameters to be used for babylons include syntax "#include<kernelBlurVaryingDeclaration>[0..varyingCount]". (default: undefined) See usage in babylon.blurPostProcess.ts and kernelBlur.vertex.fx
          * @param indexParameters The index parameters to be used for babylons include syntax "#include<kernelBlurVaryingDeclaration>[0..varyingCount]". (default: undefined) See usage in babylon.blurPostProcess.ts and kernelBlur.vertex.fx
-         * @param blockCompilation If the shader should be compiled imediatly. (default: false) 
+         * @param blockCompilation If the shader should not be compiled imediatly. (default: false) 
          */
          */
         constructor(/** Name of the PostProcess. */public name: string, fragmentUrl: string, parameters: Nullable<string[]>, samplers: Nullable<string[]>, options: number | PostProcessOptions, camera: Nullable<Camera>,
         constructor(/** Name of the PostProcess. */public name: string, fragmentUrl: string, parameters: Nullable<string[]>, samplers: Nullable<string[]>, options: number | PostProcessOptions, camera: Nullable<Camera>,
             samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines: Nullable<string> = null, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, vertexUrl: string = "postprocess", indexParameters?: any, blockCompilation = false) {
             samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines: Nullable<string> = null, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, vertexUrl: string = "postprocess", indexParameters?: any, blockCompilation = false) {
@@ -333,6 +334,7 @@
 
 
         /**
         /**
          * Activates the post process by intializing the textures to be used when executed. Notifies onActivateObservable.
          * Activates the post process by intializing the textures to be used when executed. Notifies onActivateObservable.
+         * When this post process is used in a pipeline, this is call will bind the input texture of this post process to the output of the previous.
          * @param camera The camera that will be used in the post process. This camera will be used when calling onActivateObservable.
          * @param camera The camera that will be used in the post process. This camera will be used when calling onActivateObservable.
          * @param sourceTexture The source texture to be inspected to get the width and height if not specified in the post process constructor. (default: null)
          * @param sourceTexture The source texture to be inspected to get the width and height if not specified in the post process constructor. (default: null)
          * @param forceDepthStencil If true, a depth and stencil buffer will be generated. (default: false)
          * @param forceDepthStencil If true, a depth and stencil buffer will be generated. (default: false)
@@ -411,16 +413,17 @@
             var target: InternalTexture;
             var target: InternalTexture;
 
 
             if (this._shareOutputWithPostProcess) {
             if (this._shareOutputWithPostProcess) {
-                target = this._shareOutputWithPostProcess.outputTexture;
+                target = this._shareOutputWithPostProcess.inputTexture;
             } else if (this._forcedOutputTexture) {
             } else if (this._forcedOutputTexture) {
                 target = this._forcedOutputTexture;
                 target = this._forcedOutputTexture;
 
 
                 this.width = this._forcedOutputTexture.width;
                 this.width = this._forcedOutputTexture.width;
                 this.height = this._forcedOutputTexture.height;
                 this.height = this._forcedOutputTexture.height;
             } else {
             } else {
-                target = this.outputTexture;
+                target = this.inputTexture;
             }
             }
 
 
+            // Bind the input of this post process to be used as the output of the previous post process.
             if (this.enablePixelPerfectMode) {
             if (this.enablePixelPerfectMode) {
                 this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
                 this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
                 this._engine.bindFramebuffer(target, 0, requiredWidth, requiredHeight, true);
                 this._engine.bindFramebuffer(target, 0, requiredWidth, requiredHeight, true);
@@ -493,14 +496,14 @@
                 this.getEngine().setAlphaConstants(this.alphaConstants.r, this.alphaConstants.g, this.alphaConstants.b, this.alphaConstants.a);
                 this.getEngine().setAlphaConstants(this.alphaConstants.r, this.alphaConstants.g, this.alphaConstants.b, this.alphaConstants.a);
             }
             }
 
 
-            // Texture            
+            // Bind the output texture of the preivous post process as the input to this post process.            
             var source: InternalTexture;
             var source: InternalTexture;
             if (this._shareOutputWithPostProcess) {
             if (this._shareOutputWithPostProcess) {
-                source = this._shareOutputWithPostProcess.outputTexture;
+                source = this._shareOutputWithPostProcess.inputTexture;
             } else if (this._forcedOutputTexture) {
             } else if (this._forcedOutputTexture) {
                 source = this._forcedOutputTexture;
                 source = this._forcedOutputTexture;
             } else {
             } else {
-                source = this.outputTexture;
+                source = this.inputTexture;
             }
             }
             this._effect._bindTexture("textureSampler", source);
             this._effect._bindTexture("textureSampler", source);
 
 

+ 93 - 19
src/Tools/babylon.observable.ts

@@ -6,12 +6,24 @@
     export class EventState {
     export class EventState {
 
 
         /**
         /**
-        * If the callback of a given Observer set skipNextObservers to true the following observers will be ignored
-        */
+         * Create a new EventState
+         * @param mask defines the mask associated with this state
+         * @param skipNextObservers defines a flag which will instruct the observable to skip following observers when set to true
+         * @param target defines the original target of the state
+         * @param currentTarget defines the current target of the state
+         */
         constructor(mask: number, skipNextObservers = false, target?: any, currentTarget?: any) {
         constructor(mask: number, skipNextObservers = false, target?: any, currentTarget?: any) {
             this.initalize(mask, skipNextObservers, target, currentTarget);
             this.initalize(mask, skipNextObservers, target, currentTarget);
         }
         }
 
 
+        /**
+         * Initialize the current event state
+         * @param mask defines the mask associated with this state
+         * @param skipNextObservers defines a flag which will instruct the observable to skip following observers when set to true
+         * @param target defines the original target of the state
+         * @param currentTarget defines the current target of the state
+         * @returns the current event state
+         */
         public initalize(mask: number, skipNextObservers = false, target?: any, currentTarget?: any): EventState {
         public initalize(mask: number, skipNextObservers = false, target?: any, currentTarget?: any): EventState {
             this.mask = mask;
             this.mask = mask;
             this.skipNextObservers = skipNextObservers;
             this.skipNextObservers = skipNextObservers;
@@ -51,7 +63,30 @@
      * Represent an Observer registered to a given Observable object.
      * Represent an Observer registered to a given Observable object.
      */
      */
     export class Observer<T> {
     export class Observer<T> {
-        constructor(public callback: (eventData: T, eventState: EventState) => void, public mask: number, public scope: any = null) {
+        /**
+         * Gets or sets a property defining that the observer as to be unregistered after the next notification
+         */
+        public unregisterOnNextCall = false;
+
+        /**
+         * Creates a new observer
+         * @param callback defines the callback to call when the observer is notified
+         * @param mask defines the mask of the observer (used to filter notifications)
+         * @param scope defines the current scope used to restore the JS context
+         */
+        constructor(
+            /**
+             * Defines the callback to call when the observer is notified
+             */
+            public callback: (eventData: T, eventState: EventState) => void, 
+            /**
+             * Defines the mask of the observer (used to filter notifications)
+             */
+            public mask: number, 
+            /**
+             * Defines the current scope used to restore the JS context
+             */
+            public scope: any = null) {
         }
         }
     }
     }
 
 
@@ -62,6 +97,9 @@
         private _observers: Nullable<Observer<T>[]>;
         private _observers: Nullable<Observer<T>[]>;
         private _observables: Nullable<Observable<T>[]>;
         private _observables: Nullable<Observable<T>[]>;
 
 
+        /**
+         * Release associated resources
+         */
         public dispose(): void {
         public dispose(): void {
             if (this._observers && this._observables) {
             if (this._observers && this._observables) {
                 for (var index = 0; index < this._observers.length; index++) {
                 for (var index = 0; index < this._observers.length; index++) {
@@ -73,6 +111,14 @@
             this._observables = null;
             this._observables = null;
         }
         }
 
 
+        /**
+         * Raise a callback when one of the observable will notify
+         * @param observables defines a list of observables to watch
+         * @param callback defines the callback to call on notification
+         * @param mask defines the mask used to filter notifications
+         * @param scope defines the current scope used to restore the JS context
+         * @returns the new MultiObserver
+         */
         public static Watch<T>(observables: Observable<T>[], callback: (eventData: T, eventState: EventState) => void, mask: number = -1, scope: any = null): MultiObserver<T> {
         public static Watch<T>(observables: Observable<T>[], callback: (eventData: T, eventState: EventState) => void, mask: number = -1, scope: any = null): MultiObserver<T> {
             let result = new MultiObserver<T>();
             let result = new MultiObserver<T>();
 
 
@@ -98,12 +144,16 @@
      * A given observer can register itself with only Move and Stop (mask = 0x03), then it will only be notified when one of these two occurs and will never be for Turn Left/Right.
      * A given observer can register itself with only Move and Stop (mask = 0x03), then it will only be notified when one of these two occurs and will never be for Turn Left/Right.
      */
      */
     export class Observable<T> {
     export class Observable<T> {
-        _observers = new Array<Observer<T>>();
+        private _observers = new Array<Observer<T>>();
 
 
         private _eventState: EventState;
         private _eventState: EventState;
 
 
         private _onObserverAdded: Nullable<(observer: Observer<T>) => void>;
         private _onObserverAdded: Nullable<(observer: Observer<T>) => void>;
 
 
+        /**
+         * Creates a new observable
+         * @param onObserverAdded defines a callback to call when a new observer is added
+         */
         constructor(onObserverAdded?: (observer: Observer<T>) => void) {
         constructor(onObserverAdded?: (observer: Observer<T>) => void) {
             this._eventState = new EventState(0);
             this._eventState = new EventState(0);
 
 
@@ -118,13 +168,16 @@
          * @param mask the mask used to filter observers
          * @param mask the mask used to filter observers
          * @param insertFirst if true the callback will be inserted at the first position, hence executed before the others ones. If false (default behavior) the callback will be inserted at the last position, executed after all the others already present.
          * @param insertFirst if true the callback will be inserted at the first position, hence executed before the others ones. If false (default behavior) the callback will be inserted at the last position, executed after all the others already present.
          * @param scope optional scope for the callback to be called from
          * @param scope optional scope for the callback to be called from
+         * @param unregisterOnFirstCall defines if the observer as to be unregistered after the next notification
+         * @returns the new observer created for the callback
          */
          */
-        public add(callback: (eventData: T, eventState: EventState) => void, mask: number = -1, insertFirst = false, scope: any = null): Nullable<Observer<T>> {
+        public add(callback: (eventData: T, eventState: EventState) => void, mask: number = -1, insertFirst = false, scope: any = null, unregisterOnFirstCall = false): Nullable<Observer<T>> {
             if (!callback) {
             if (!callback) {
                 return null;
                 return null;
             }
             }
 
 
             var observer = new Observer(callback, mask, scope);
             var observer = new Observer(callback, mask, scope);
+            observer.unregisterOnNextCall = unregisterOnFirstCall;
 
 
             if (insertFirst) {
             if (insertFirst) {
                 this._observers.unshift(observer);
                 this._observers.unshift(observer);
@@ -141,7 +194,8 @@
 
 
         /**
         /**
          * Remove an Observer from the Observable object
          * Remove an Observer from the Observable object
-         * @param observer the instance of the Observer to remove. If it doesn't belong to this Observable, false will be returned.
+         * @param observer the instance of the Observer to remove
+         * @returns false if it doesn't belong to this Observable
          */
          */
         public remove(observer: Nullable<Observer<T>>): boolean {
         public remove(observer: Nullable<Observer<T>>): boolean {
             if (!observer) {
             if (!observer) {
@@ -162,8 +216,9 @@
 
 
         /**
         /**
          * Remove a callback from the Observable object
          * Remove a callback from the Observable object
-         * @param callback the callback to remove. If it doesn't belong to this Observable, false will be returned.
-         * @param scope optional scope. If used only the callbacks with this scope will be removed.
+         * @param callback the callback to remove
+         * @param scope optional scope. If used only the callbacks with this scope will be removed
+         * @returns false if it doesn't belong to this Observable
         */
         */
         public removeCallback(callback: (eventData: T, eventState: EventState) => void, scope?: any): boolean {
         public removeCallback(callback: (eventData: T, eventState: EventState) => void, scope?: any): boolean {
 
 
@@ -177,11 +232,20 @@
             return false;
             return false;
         }
         }
 
 
+        private _deferUnregister(observer: Observer<T>): void {
+            Tools.SetImmediate(() => {
+                this.remove(observer);
+            })
+        }
+
         /**
         /**
          * Notify all Observers by calling their respective callback with the given data
          * Notify all Observers by calling their respective callback with the given data
          * Will return true if all observers were executed, false if an observer set skipNextObservers to true, then prevent the subsequent ones to execute
          * Will return true if all observers were executed, false if an observer set skipNextObservers to true, then prevent the subsequent ones to execute
-         * @param eventData
-         * @param mask
+         * @param eventData defines the data to send to all observers
+         * @param mask defines the mask of the current notification (observers with incompatible mask (ie mask & observer.mask === 0) will not be notified)
+         * @param target defines the original target of the state
+         * @param currentTarget defines the current target of the state
+         * @returns false if the complete observer chain was not processed (because one observer set the skipNextObservers to true)
          */
          */
         public notifyObservers(eventData: T, mask: number = -1, target?: any, currentTarget?: any): boolean {
         public notifyObservers(eventData: T, mask: number = -1, target?: any, currentTarget?: any): boolean {
             if (!this._observers.length) {
             if (!this._observers.length) {
@@ -202,6 +266,10 @@
                     } else {
                     } else {
                         state.lastReturnValue = obs.callback(eventData, state);
                         state.lastReturnValue = obs.callback(eventData, state);
                     }
                     }
+
+                    if (obs.unregisterOnNextCall) {
+                        this._deferUnregister(obs);
+                    }
                 }
                 }
                 if (state.skipNextObservers) {
                 if (state.skipNextObservers) {
                     return false;
                     return false;
@@ -219,8 +287,8 @@
          * 
          * 
          * @param eventData The data to be sent to each callback
          * @param eventData The data to be sent to each callback
          * @param mask is used to filter observers defaults to -1
          * @param mask is used to filter observers defaults to -1
-         * @param target the callback target (see EventState)
-         * @param currentTarget The current object in the bubbling phase
+         * @param target defines the callback target (see EventState)
+         * @param currentTarget defines he current object in the bubbling phase
          * @returns {Promise<T>} will return a Promise than resolves when all callbacks executed successfully.
          * @returns {Promise<T>} will return a Promise than resolves when all callbacks executed successfully.
          */
          */
         public notifyObserversWithPromise(eventData: T, mask: number = -1, target?: any, currentTarget?: any): Promise<T> {
         public notifyObserversWithPromise(eventData: T, mask: number = -1, target?: any, currentTarget?: any): Promise<T> {
@@ -256,6 +324,9 @@
                             return obs.callback(eventData, state);
                             return obs.callback(eventData, state);
                         });
                         });
                     }
                     }
+                    if (obs.unregisterOnNextCall) {
+                        this._deferUnregister(obs);
+                    }                    
                 }
                 }
             });
             });
 
 
@@ -265,8 +336,9 @@
 
 
         /**
         /**
          * Notify a specific observer
          * Notify a specific observer
-         * @param eventData
-         * @param mask
+         * @param observer defines the observer to notify
+         * @param eventData defines the data to be sent to each callback
+         * @param mask is used to filter observers defaults to -1
          */
          */
         public notifyObserver(observer: Observer<T>, eventData: T, mask: number = -1): void {
         public notifyObserver(observer: Observer<T>, eventData: T, mask: number = -1): void {
             let state = this._eventState;
             let state = this._eventState;
@@ -277,7 +349,8 @@
         }
         }
 
 
         /**
         /**
-         * return true is the Observable has at least one Observer registered
+         * Gets a boolean indicating if the observable has at least one observer
+         * @returns true is the Observable has at least one Observer registered
          */
          */
         public hasObservers(): boolean {
         public hasObservers(): boolean {
             return this._observers.length > 0;
             return this._observers.length > 0;
@@ -292,8 +365,9 @@
         }
         }
 
 
         /**
         /**
-        * Clone the current observable
-        */
+         * Clone the current observable
+         * @returns a new observable
+         */
         public clone(): Observable<T> {
         public clone(): Observable<T> {
             var result = new Observable<T>();
             var result = new Observable<T>();
 
 
@@ -304,8 +378,8 @@
 
 
         /**
         /**
          * Does this observable handles observer registered with a given mask
          * Does this observable handles observer registered with a given mask
-         * @param {number} trigger - the mask to be tested
-         * @return {boolean} whether or not one observer registered with the given mask is handeled 
+         * @param mask defines the mask to be tested
+         * @return whether or not one observer registered with the given mask is handeled 
         **/
         **/
         public hasSpecificMask(mask: number = -1): boolean {
         public hasSpecificMask(mask: number = -1): boolean {
             for (var obs of this._observers) {
             for (var obs of this._observers) {

+ 10 - 11
src/babylon.assetContainer.ts

@@ -274,17 +274,16 @@ module BABYLON {
             this._moveAssets(this.scene.meshes, this.meshes, keepAssets.meshes);
             this._moveAssets(this.scene.meshes, this.meshes, keepAssets.meshes);
             this._moveAssets(this.scene.getGeometries(), this.geometries, keepAssets.geometries);
             this._moveAssets(this.scene.getGeometries(), this.geometries, keepAssets.geometries);
             this._moveAssets(this.scene.materials, this.materials, keepAssets.materials);
             this._moveAssets(this.scene.materials, this.materials, keepAssets.materials);
-    
-            Array.prototype.push.apply(this.actionManagers, this.scene._actionManagers);
-            Array.prototype.push.apply(this.animations, this.scene.animations);
-            Array.prototype.push.apply(this.lensFlareSystems, this.scene.lensFlareSystems);
-            Array.prototype.push.apply(this.lights, this.scene.lights);
-            Array.prototype.push.apply(this.morphTargetManagers, this.scene.morphTargetManagers);
-            Array.prototype.push.apply(this.multiMaterials, this.scene.multiMaterials);
-            Array.prototype.push.apply(this.skeletons, this.scene.skeletons);
-            Array.prototype.push.apply(this.particleSystems, this.scene.particleSystems);
-            Array.prototype.push.apply(this.sounds, this.scene.mainSoundTrack.soundCollection);
-            Array.prototype.push.apply(this.transformNodes, this.scene.transformNodes);
+            this._moveAssets(this.scene._actionManagers, this.actionManagers, keepAssets.actionManagers);
+            this._moveAssets(this.scene.animations, this.animations, keepAssets.animations);
+            this._moveAssets(this.scene.lensFlareSystems, this.lensFlareSystems, keepAssets.lensFlareSystems);
+            this._moveAssets(this.scene.lights, this.lights, keepAssets.lights);
+            this._moveAssets(this.scene.morphTargetManagers, this.morphTargetManagers, keepAssets.morphTargetManagers);
+            this._moveAssets(this.scene.multiMaterials, this.multiMaterials, keepAssets.multiMaterials);
+            this._moveAssets(this.scene.skeletons, this.skeletons, keepAssets.skeletons);
+            this._moveAssets(this.scene.particleSystems, this.particleSystems, keepAssets.particleSystems);
+            this._moveAssets(this.scene.mainSoundTrack.soundCollection, this.sounds, keepAssets.sounds);
+            this._moveAssets(this.scene.transformNodes, this.transformNodes, keepAssets.transformNodes);
     
     
             this.removeAllFromScene();
             this.removeAllFromScene();
         }
         }

BIN
tests/validation/ReferenceImages/LightProjectionTexture.png


BIN
tests/validation/ReferenceImages/gltfMaterialSpecularGlossiness.png


BIN
tests/validation/ReferenceImages/gltfPrimitiveAttribute.png


+ 5 - 0
tests/validation/config.json

@@ -342,6 +342,11 @@
       "functionToCall": "CreateBones2TestScene",
       "functionToCall": "CreateBones2TestScene",
       "referenceImage": "instancedBones.png",
       "referenceImage": "instancedBones.png",
       "replace": "Dude.babylon, dude.babylon"
       "replace": "Dude.babylon, dude.babylon"
+    },
+    {
+      "title": "Light Projection Texture",
+      "playgroundId": "#CQNGRK",
+      "referenceImage": "LightProjectionTexture.png"
     }
     }
   ]
   ]
 }
 }