浏览代码

Merge branch 'master' into jbousquie-patch-1

Jérôme Bousquié 7 年之前
父节点
当前提交
6052b7aec7

+ 23 - 1
Tools/Gulp/config.json

@@ -1651,7 +1651,29 @@
         ],
         "build": {
             "srcOutputDirectory": "../../Viewer/",
-            "distOutputDirectory": "/viewer/"
+            "outputs": [
+                {
+                    "destination": [
+                        {
+                            "filename": "viewer.min.js",
+                            "outputDirectory": "/../../Viewer/dist/"
+                        },
+                        {
+                            "filename": "babylon.viewer.js",
+                            "outputDirectory": "/viewer/"
+                        }
+                    ],
+                    "minified": true
+                },
+                {
+                    "destination": [
+                        {
+                            "filename": "viewer.js",
+                            "outputDirectory": "/../../Viewer/dist/"
+                        }
+                    ]
+                }
+            ]
         }
     }
 }

+ 39 - 13
Tools/Gulp/gulpfile.js

@@ -426,14 +426,40 @@ var buildExternalLibrary = function (library, settings, watch) {
         }
 
         if (library.webpack) {
-            return waitAll.on("end", function () {
-                return webpack(require(library.webpack))
-                    .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
-                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true))
-                    .pipe(uglify())
-                    .pipe(optimisejs())
-                    .pipe(gulp.dest(outputDirectory))
-            });
+            let sequence = [waitAll];
+            let wpBuild = webpack(require(library.webpack));
+            if (settings.build.outputs) {
+                let build = wpBuild
+                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true));
+
+                settings.build.outputs.forEach(out => {
+                    let outBuild = build;
+                    if (out.minified) {
+                        outBuild = build
+                            .pipe(uglify())
+                            .pipe(optimisejs())
+                    }
+
+                    out.destination.forEach(dest => {
+                        var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
+                        let destBuild = outBuild
+                            .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
+                            .pipe(gulp.dest(outputDirectory));
+                        sequence.push(destBuild);
+                    });
+                })
+            } else {
+                sequence.push(
+                    wpBuild
+                        .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
+                        .pipe(addModuleExports(library.moduleDeclaration, false, false, true))
+                        .pipe(uglify())
+                        .pipe(optimisejs())
+                        .pipe(gulp.dest(outputDirectory))
+                )
+            }
+
+            return merge2(sequence);
         }
         else {
             return waitAll;
@@ -911,14 +937,14 @@ gulp.task("tests-unit-transpile", function (done) {
 
     var tsResult = gulp.src("../../tests/unit/**/*.ts", { base: "../../" })
         .pipe(tsProject());
-    
+
     tsResult.once("error", function () {
         tsResult.once("finish", function () {
             console.log("Typescript compile failed");
             process.exit(1);
         });
     });
- 
+
     return tsResult.js.pipe(gulp.dest("../../"));
 });
 
@@ -951,7 +977,7 @@ gulp.task("tests-unit", ["tests-unit-transpile"], function (done) {
     server.start();
 });
 
-gulp.task("tests-whatsnew", function(done) {
+gulp.task("tests-whatsnew", function (done) {
     // Only checks on Travis
     if (!process.env.TRAVIS) {
         done();
@@ -980,12 +1006,12 @@ gulp.task("tests-whatsnew", function(done) {
             oldData += data;
         });
         res.on("end", () => {
-            fs.readFile("../../dist/preview release/what's new.md", "utf-8", function(err, newData) {
+            fs.readFile("../../dist/preview release/what's new.md", "utf-8", function (err, newData) {
                 if (err || oldData != newData) {
                     done();
                     return;
                 }
-                
+
                 console.error("What's new file did not change.");
                 process.exit(1);
             });

文件差异内容过多而无法显示
+ 69 - 112077
Viewer/dist/viewer.js


文件差异内容过多而无法显示
+ 69 - 1
Viewer/dist/viewer.min.js


+ 54 - 9
Viewer/src/configuration/configuration.ts

@@ -46,6 +46,24 @@ export interface ViewerConfiguration {
         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?: {
@@ -66,14 +84,15 @@ export interface ViewerConfiguration {
         [propName: string]: any;
     },
     skybox?: {
-        cubeTexture: {
+        cubeTexture?: {
             noMipMap?: boolean;
             gammaSpace?: boolean;
-            url: string | Array<string>;
+            url?: string | Array<string>;
         };
-        pbr?: boolean;
+        color?: { r: number, g: number, b: number };
+        pbr?: boolean; // deprecated
         scale?: number;
-        blur?: number;
+        blur?: number; // deprecated
         material?: {
             imageProcessingConfiguration?: IImageProcessingConfiguration;
         };
@@ -84,11 +103,23 @@ export interface ViewerConfiguration {
     ground?: boolean | {
         size?: number;
         receiveShadows?: boolean;
-        shadowOnly?: boolean;
-        mirror?: boolean;
-        material?: {
+        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;
-        }
+        };
+
     };
     lights?: {
         [name: string]: {
@@ -133,7 +164,21 @@ export interface ViewerConfiguration {
         main: ITemplateConfiguration,
         [key: string]: ITemplateConfiguration
     };
-    // nodes?
+
+    customShaders?: {
+        shaders?: {
+            [key: string]: string;
+        };
+        includes?: {
+            [key: string]: string;
+        }
+    }
+}
+
+export interface SceneOptimizerParameters {
+    priority?: number;
+    maximumSize?: number;
+    step?: number;
 }
 
 export interface IImageProcessingConfiguration {

+ 10 - 14
Viewer/src/configuration/types/default.ts

@@ -1,9 +1,7 @@
 import { ViewerConfiguration } from './../configuration';
 
 export let defaultConfiguration: ViewerConfiguration = {
-    version: "0.1",
-    //eventPrefix: 'babylonviewer-',
-    //events: true,
+    version: "3.2.0-alpha4",
     templates: {
         main: {
             html: require("../../../assets/templates/default/defaultTemplate.html")
@@ -71,12 +69,12 @@ export let defaultConfiguration: ViewerConfiguration = {
             }
         }
     },
-    /*lights: [
-        {
+    /*lights: {
+        "default": {
             type: 1,
             shadowEnabled: true,
-            direction: { x: -0.2, y: -1, z: 0 },
-            position: { x: 0.017, y: 50, z: 0 },
+            direction: { x: -0.2, y: -0.8, z: 0 },
+            position: { x: 10, y: 10, z: 0 },
             intensity: 4.5,
             shadowConfig: {
                 useBlurExponentialShadowMap: true,
@@ -85,16 +83,16 @@ export let defaultConfiguration: ViewerConfiguration = {
                 blurScale: 4
             }
         }
-    ],*/
+    },*/
     skybox: {
-        cubeTexture: {
+        /*cubeTexture: {
             url: 'https://playground.babylonjs.com/textures/environment.dds',
             gammaSpace: false
-        },
+        },*/
         pbr: true,
         blur: 0.7,
         infiniteDIstance: false,
-        material: {
+        /*material: {
             imageProcessingConfiguration: {
                 colorCurves: {
                     globalDensity: 89,
@@ -110,7 +108,7 @@ export let defaultConfiguration: ViewerConfiguration = {
                 vignetteColor: { r: 0.8, g: 0.6, b: 0.4 },
                 vignetteM: true
             }
-        }
+        }*/
     },
     ground: true,
     engine: {
@@ -122,7 +120,5 @@ export let defaultConfiguration: ViewerConfiguration = {
             contrast: 1.66,
             toneMappingEnabled: true
         }
-        //autoRotate: true,
-        //rotationSpeed: 0.1
     }
 }

+ 13 - 0
Viewer/src/templateManager.ts

@@ -154,6 +154,19 @@ export class TemplateManager {
         }
     }
 
+    public dispose() {
+        // dispose all templates
+        Object.keys(this.templates).forEach(template => {
+            this.templates[template].dispose();
+        });
+
+        this.onInit.clear();
+        this.onAllLoaded.clear();
+        this.onEventTriggered.clear();
+        this.onLoaded.clear();
+        this.onStateChange.clear();
+    }
+
 }
 
 

+ 25 - 19
Viewer/src/viewer/defaultViewer.ts

@@ -135,7 +135,7 @@ export class DefaultViewer extends AbstractViewer {
         this.setupCamera(meshes);
         this.setupLights(meshes);
 
-        return this.initEnvironment(meshes);
+        return; //this.initEnvironment(meshes);
     }
 
     private setModelMetaData() {
@@ -167,7 +167,7 @@ export class DefaultViewer extends AbstractViewer {
 
     }
 
-    public initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
+    /*protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
         if (this.configuration.skybox) {
             // Define a general environment textue
             let texture;
@@ -267,7 +267,7 @@ export class DefaultViewer extends AbstractViewer {
         }
 
         return Promise.resolve(this.scene);
-    }
+    }*/
 
     public showOverlayScreen(subScreen: string) {
         let template = this.templateManager.getTemplate('overlay');
@@ -382,7 +382,7 @@ export class DefaultViewer extends AbstractViewer {
 
                 //position. Some lights don't support shadows
                 if (light instanceof ShadowLight) {
-                    if (lightConfig.shadowEnabled) {
+                    if (lightConfig.shadowEnabled && this.maxShadows) {
                         var shadowGenerator = new ShadowGenerator(512, light);
                         this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
                         // add the focues meshes to the shadow list
@@ -395,6 +395,22 @@ export class DefaultViewer extends AbstractViewer {
                     }
                 }
             });
+        } else {
+            if (!this.configuration.lights && this.configuration.ground) {
+                let light = this.scene.lights[0];
+                if (light instanceof ShadowLight) {
+                    if (this.maxShadows) {
+                        var shadowGenerator = new ShadowGenerator(512, light);
+                        // 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]);
+                        }
+                    }
+                }
+            }
         }
     }
 
@@ -430,6 +446,11 @@ export class DefaultViewer extends AbstractViewer {
         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 | {
@@ -481,19 +502,4 @@ export class DefaultViewer extends AbstractViewer {
                 break;
         }
     }
-
-    private extendClassWithConfig(object: any, config: any) {
-        if (!config) return;
-        Object.keys(config).forEach(key => {
-            if (key in object && typeof object[key] !== 'function') {
-                if (typeof object[key] === 'function') return;
-                // if it is an object, iterate internally until reaching basic types
-                if (typeof object[key] === 'object') {
-                    this.extendClassWithConfig(object[key], config[key]);
-                } else {
-                    object[key] = config[key];
-                }
-            }
-        });
-    }
 }

+ 257 - 5
Viewer/src/viewer/viewer.ts

@@ -1,7 +1,7 @@
 import { viewerManager } from './viewerManager';
 import { TemplateManager } from './../templateManager';
 import configurationLoader from './../configuration/loader';
-import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database, SceneLoaderProgressEvent, ISceneLoaderPlugin, ISceneLoaderPluginAsync } from 'babylonjs';
+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 { PromiseObservable } from '../util/promiseObservable';
 
@@ -11,6 +11,7 @@ export abstract class AbstractViewer {
 
     public engine: Engine;
     public scene: Scene;
+    public sceneOptimizer: SceneOptimizer;
     public baseId: string;
 
     /**
@@ -22,6 +23,13 @@ export abstract class AbstractViewer {
     public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
 
     protected configuration: ViewerConfiguration;
+    protected environmentHelper: EnvironmentHelper;
+
+    protected defaultHighpTextureType: number;
+    protected shadowGeneratorBias: number;
+    protected defaultPipelineTextureType: number;
+    protected maxShadows: number;
+
 
     // observables
     public onSceneInitObservable: PromiseObservable<Scene>;
@@ -84,6 +92,8 @@ export abstract class AbstractViewer {
             });
         });
 
+        //this.onModelLoadedObservable.add(this.initEnvironment.bind(this));
+
     }
 
     public getBaseId(): string {
@@ -113,6 +123,18 @@ export abstract class AbstractViewer {
 
     public dispose() {
         window.removeEventListener('resize', this.resize);
+
+        this.sceneOptimizer.stop();
+        this.sceneOptimizer.dispose();
+
+        if (this.scene.activeCamera) {
+            this.scene.activeCamera.detachControl(this.canvas);
+        }
+
+        this.scene.dispose();
+        this.engine.dispose();
+
+        this.templateManager.dispose();
     }
 
     protected abstract prepareContainerElement();
@@ -163,6 +185,10 @@ export abstract class AbstractViewer {
      * @memberof Viewer
      */
     protected initEngine(): Promise<Engine> {
+
+        // init custom shaders
+        this.injectCustomShaders();
+
         let canvasElement = this.templateManager.getCanvas();
         if (!canvasElement) {
             return Promise.reject('Canvas element not found!');
@@ -186,6 +212,9 @@ export abstract class AbstractViewer {
             this.engine.setHardwareScalingLevel(scale);
         }
 
+        // set hardware limitations for scene initialization
+        this.handleHardwareLimitations();
+
         return Promise.resolve(this.engine);
     }
 
@@ -200,9 +229,47 @@ export abstract class AbstractViewer {
         this.scene = new Scene(this.engine);
         // make sure there is a default camera and light.
         this.scene.createDefaultCameraOrLight(true, true, true);
-        if (this.configuration.scene && this.configuration.scene.debug) {
-            this.scene.debugLayer.show();
+        if (this.configuration.scene) {
+            if (this.configuration.scene.debug) {
+                this.scene.debugLayer.show();
+            }
+
+            // Scene 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;
+            }
         }
+
+
+
         return Promise.resolve(this.scene);
     }
 
@@ -229,9 +296,194 @@ export abstract class AbstractViewer {
                 }, plugin)!;
             });
         }).then((meshes: Array<AbstractMesh>) => {
-            return this.onModelLoadedObservable.notifyWithPromise(meshes).then(() => {
-                return this.scene;
+            return this.onModelLoadedObservable.notifyWithPromise(meshes)
+                .then(() => {
+                    this.initEnvironment();
+                }).then(() => {
+                    return this.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);
+                }
+            }
+        }
+
+        return Promise.resolve(this.scene);
+    }
+
+    /**
+		 * Alters render settings to reduce features based on hardware feature limitations
+		 * @param options Viewer options to modify
+		 */
+    protected handleHardwareLimitations() {
+        //flip rendering settings switches based on hardware support
+        let maxVaryingRows = this.engine.getCaps().maxVaryingVectors;
+        let maxFragmentSamplers = this.engine.getCaps().maxTexturesImageUnits;
+
+        //shadows are disabled if there's not enough varyings for a single shadow
+        if ((maxVaryingRows < 8) || (maxFragmentSamplers < 8)) {
+            this.maxShadows = 0;
+        } else {
+            this.maxShadows = 3;
+        }
+
+        //can we render to any >= 16-bit targets (required for HDR)
+        let caps = this.engine.getCaps();
+        let linearHalfFloatTargets = caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering;
+        let linearFloatTargets = caps.textureFloatRender && caps.textureFloatLinearFiltering;
+
+        let supportsHDR: boolean = !!(linearFloatTargets || linearHalfFloatTargets);
+
+        if (linearHalfFloatTargets) {
+            this.defaultHighpTextureType = Engine.TEXTURETYPE_HALF_FLOAT;
+            this.shadowGeneratorBias = 0.002;
+        } else if (linearFloatTargets) {
+            this.defaultHighpTextureType = Engine.TEXTURETYPE_FLOAT;
+            this.shadowGeneratorBias = 0.001;
+        } else {
+            this.defaultHighpTextureType = Engine.TEXTURETYPE_UNSIGNED_INT;
+            this.shadowGeneratorBias = 0.001;
+        }
+
+        this.defaultPipelineTextureType = supportsHDR ? this.defaultHighpTextureType : Engine.TEXTURETYPE_UNSIGNED_INT;
+    }
+
+    /**
+     * Injects all the spectre shader in the babylon shader store
+     */
+    protected injectCustomShaders(): void {
+        let customShaders = this.configuration.customShaders;
+        // Inject all the spectre shader in the babylon shader store.
+        if (!customShaders) {
+            return;
+        }
+        if (customShaders.shaders) {
+            Object.keys(customShaders.shaders).forEach(key => {
+                // typescript considers a callback "unsafe", so... '!'
+                Effect.ShadersStore[key] = customShaders!.shaders![key];
             });
+        }
+        if (customShaders.includes) {
+            Object.keys(customShaders.includes).forEach(key => {
+                // typescript considers a callback "unsafe", so... '!'
+                Effect.IncludesShadersStore[key] = customShaders!.includes![key];
+            });
+        }
+    }
+
+    protected extendClassWithConfig(object: any, config: any) {
+        if (!config) return;
+        Object.keys(config).forEach(key => {
+            if (key in object && typeof object[key] !== 'function') {
+                if (typeof object[key] === 'function') return;
+                // if it is an object, iterate internally until reaching basic types
+                if (typeof object[key] === 'object') {
+                    this.extendClassWithConfig(object[key], config[key]);
+                } else {
+                    object[key] = config[key];
+                }
+            }
         });
     }
 }

文件差异内容过多而无法显示
+ 7289 - 7097
dist/preview release/babylon.d.ts


文件差异内容过多而无法显示
+ 0 - 1469
dist/preview release/typedocValidationBaseline.json


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

@@ -36,8 +36,12 @@
 - Added depth of field effect to default pipeline ([trevordev](https://github.com/trevordev))
 - The observable can now notify observers using promise-based callback chain. ([RaananW](https://github.com/RaananW))
 - Added base64 helper functions to `Tools` ([bghgary](https://github.com/bghgary))
-- Added `createDefaultCamera` and `createDefaultLight` functions to `Scene` ([bghgary](https://github.com/bghgary))  
-- SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie))  
+- Added `createDefaultCamera` and `createDefaultLight` functions to `Scene` ([bghgary](https://github.com/bghgary))
+- 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) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
+- SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
+
 
 ## Bug fixes
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))

+ 243 - 32
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -3,23 +3,76 @@
      * Interface to implement to create a shadow generator compatible with BJS.
      */
     export interface IShadowGenerator {
+        /**
+         * Gets the main RTT containing the shadow map (usually storing depth from the light point of view).
+         * @returns The render target texture if present otherwise, null
+         */
         getShadowMap(): Nullable<RenderTargetTexture>;
+        /**
+         * Gets the RTT used during rendering (can be a blurred version of the shadow map or the shadow map itself).
+         * @returns The render target texture if the shadow map is present otherwise, null
+         */
         getShadowMapForRendering(): Nullable<RenderTargetTexture>;
 
+        /**
+         * Determine wheter the shadow generator is ready or not (mainly all effects and related post processes needs to be ready).
+         * @param subMesh The submesh we want to render in the shadow map
+         * @param useInstances Defines wether will draw in the map using instances
+         * @returns true if ready otherwise, false
+         */
         isReady(subMesh: SubMesh, useInstances: boolean): boolean;
 
+        /**
+         * Prepare all the defines in a material relying on a shadow map at the specified light index.
+         * @param defines Defines of the material we want to update
+         * @param lightIndex Index of the light in the enabled light list of the material
+         */
         prepareDefines(defines: MaterialDefines, lightIndex: number): void;
+        /**
+         * Binds the shadow related information inside of an effect (information like near, far, darkness...
+         * defined in the generator but impacting the effect).
+         * It implies the unifroms available on the materials are the standard BJS ones.
+         * @param lightIndex Index of the light in the enabled light list of the material owning the effect
+         * @param effect The effect we are binfing the information for 
+         */
         bindShadowLight(lightIndex: string, effect: Effect): void;
+        /**
+         * Gets the transformation matrix used to project the meshes into the map from the light point of view.
+         * (eq to shadow prjection matrix * light transform matrix)
+         * @returns The transform matrix used to create the shadow map
+         */
         getTransformMatrix(): Matrix;
 
+        /**
+         * Recreates the shadow map dependencies like RTT and post processes. This can be used during the switch between
+         * Cube and 2D textures for instance.
+         */
         recreateShadowMap(): void;
 
+        /**
+         * Forces all the attached effect to compile to enable rendering only once ready vs. lazyly compiling effects.
+         * @param onCompiled Callback triggered at the and of the effects compilation
+         * @param options Sets of optional options forcing the compilation with different modes 
+         */
         forceCompilation(onCompiled?: (generator: ShadowGenerator) => void, options?: Partial<{ useInstances: boolean }>): void;
 
+        /**
+         * Serializes the shadow generator setup to a json object.
+         * @returns The serialized JSON object 
+         */
         serialize(): any;
+
+        /**
+         * Disposes the Shadow map and related Textures and effects.
+         */
         dispose(): void;
     }
 
+    /**
+     * Default implementation of @see IShadowGenerator.
+     * This is the main object responsible of generating shadows in the framework.
+     * Documentation: https://doc.babylonjs.com/babylon101/shadows
+     */
     export class ShadowGenerator implements IShadowGenerator {
         private static _FILTER_NONE = 0;
         private static _FILTER_EXPONENTIALSHADOWMAP = 1;
@@ -28,44 +81,81 @@
         private static _FILTER_CLOSEEXPONENTIALSHADOWMAP = 4;
         private static _FILTER_BLURCLOSEEXPONENTIALSHADOWMAP = 5;
 
-        // Static
+        /**
+         * Shadow generator mode None: no filtering applied.
+         */
         public static get FILTER_NONE(): number {
             return ShadowGenerator._FILTER_NONE;
         }
 
+        /**
+         * Shadow generator mode Poisson Sampling: Percentage Closer Filtering.
+         * (Multiple Tap around evenly distributed around the pixel are used to evaluate the shadow strength)
+         */
         public static get FILTER_POISSONSAMPLING(): number {
             return ShadowGenerator._FILTER_POISSONSAMPLING;
         }
 
+        /**
+         * Shadow generator mode ESM: Exponential Shadow Mapping.
+         * (http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf)
+         */
         public static get FILTER_EXPONENTIALSHADOWMAP(): number {
             return ShadowGenerator._FILTER_EXPONENTIALSHADOWMAP;
         }
 
+        /**
+         * Shadow generator mode ESM: Blurred Exponential Shadow Mapping.
+         * (http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf)
+         */
         public static get FILTER_BLUREXPONENTIALSHADOWMAP(): number {
             return ShadowGenerator._FILTER_BLUREXPONENTIALSHADOWMAP;
         }
 
+        /**
+         * Shadow generator mode ESM: Exponential Shadow Mapping using the inverse of the exponential preventing 
+         * edge artifacts on steep falloff.
+         * (http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf)
+         */
         public static get FILTER_CLOSEEXPONENTIALSHADOWMAP(): number {
             return ShadowGenerator._FILTER_CLOSEEXPONENTIALSHADOWMAP;
         }
 
+        /**
+         * Shadow generator mode ESM: Blurred Exponential Shadow Mapping using the inverse of the exponential preventing 
+         * edge artifacts on steep falloff.
+         * (http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf)
+         */
         public static get FILTER_BLURCLOSEEXPONENTIALSHADOWMAP(): number {
             return ShadowGenerator._FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
         }
 
-        // Members
         private _bias = 0.00005;
+        /**
+         * Gets the bias: offset applied on the depth preventing acnea.
+         */
         public get bias(): number {
             return this._bias;
         }
+        /**
+         * Sets the bias: offset applied on the depth preventing acnea.
+         */
         public set bias(bias: number) {
             this._bias = bias;
         }
 
         private _blurBoxOffset = 1;
+        /**
+         * Gets the blur box offset: offset applied during the blur pass.
+         * Only usefull if useKernelBlur = false
+         */
         public get blurBoxOffset(): number {
             return this._blurBoxOffset;
         }
+        /**
+         * Sets the blur box offset: offset applied during the blur pass.
+         * Only usefull if useKernelBlur = false
+         */
         public set blurBoxOffset(value: number) {
             if (this._blurBoxOffset === value) {
                 return;
@@ -76,9 +166,17 @@
         }
 
         private _blurScale = 2;
+        /**
+         * Gets the blur scale: scale of the blurred texture compared to the main shadow map.
+         * 2 means half of the size.
+         */
         public get blurScale(): number {
             return this._blurScale;
         }
+        /**
+         * Sets the blur scale: scale of the blurred texture compared to the main shadow map.
+         * 2 means half of the size.
+         */
         public set blurScale(value: number) {
             if (this._blurScale === value) {
                 return;
@@ -89,9 +187,17 @@
         }
 
         private _blurKernel = 1;
+        /**
+         * Gets the blur kernel: kernel size of the blur pass.
+         * Only usefull if useKernelBlur = true
+         */
         public get blurKernel(): number {
             return this._blurKernel;
         }
+        /**
+         * Sets the blur kernel: kernel size of the blur pass.
+         * Only usefull if useKernelBlur = true
+         */
         public set blurKernel(value: number) {
             if (this._blurKernel === value) {
                 return;
@@ -102,9 +208,17 @@
         }
 
         private _useKernelBlur = false;
+        /**
+         * Gets whether the blur pass is a kernel blur (if true) or box blur.
+         * Only usefull in filtered mode (useBlurExponentialShadowMap...)
+         */
         public get useKernelBlur(): boolean {
             return this._useKernelBlur;
         }
+        /**
+         * Sets whether the blur pass is a kernel blur (if true) or box blur.
+         * Only usefull in filtered mode (useBlurExponentialShadowMap...)
+         */
         public set useKernelBlur(value: boolean) {
             if (this._useKernelBlur === value) {
                 return;
@@ -115,17 +229,32 @@
         }
 
         private _depthScale: number;
+        /**
+         * Gets the depth scale used in ESM mode.
+         */
         public get depthScale(): number {
             return this._depthScale !== undefined ? this._depthScale : this._light.getDepthScale();
         }
+        /**
+         * Sets the depth scale used in ESM mode.
+         * This can override the scale stored on the light.
+         */
         public set depthScale(value: number) {
             this._depthScale = value;
         }
 
         private _filter = ShadowGenerator.FILTER_NONE;
+        /**
+         * Gets the current mode of the shadow generator (normal, PCF, ESM...).
+         * The returned value is a number equal to one of the available mode defined in ShadowMap.FILTER_x like _FILTER_NONE
+         */
         public get filter(): number {
             return this._filter;
         }
+        /**
+         * Sets the current mode of the shadow generator (normal, PCF, ESM...).
+         * The returned value is a number equal to one of the available mode defined in ShadowMap.FILTER_x like _FILTER_NONE
+         */
         public set filter(value: number) {
             // Blurring the cubemap is going to be too expensive. Reverting to unblurred version
             if (this._light.needCube()) {
@@ -149,10 +278,15 @@
             this._light._markMeshesAsLightDirty();
         }
 
+        /**
+         * Gets if the current filter is set to Poisson Sampling aka PCF.
+         */
         public get usePoissonSampling(): boolean {
             return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING;
         }
-
+        /**
+         * Sets the current filter to Poisson Sampling aka PCF.
+         */
         public set usePoissonSampling(value: boolean) {
             if (!value && this.filter !== ShadowGenerator.FILTER_POISSONSAMPLING) {
                 return;
@@ -161,27 +295,49 @@
             this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
         }
 
+        /**
+         * Gets if the current filter is set to VSM.
+         * DEPRECATED. Should use useExponentialShadowMap instead.
+         */
         public get useVarianceShadowMap(): boolean {
             Tools.Warn("VSM are now replaced by ESM. Please use useExponentialShadowMap instead.");
             return this.useExponentialShadowMap;
         }
+        /**
+         * Sets the current filter is to VSM.
+         * DEPRECATED. Should use useExponentialShadowMap instead.
+         */
         public set useVarianceShadowMap(value: boolean) {
             Tools.Warn("VSM are now replaced by ESM. Please use useExponentialShadowMap instead.");
             this.useExponentialShadowMap = value;
         }
 
+        /**
+         * Gets if the current filter is set to blurred VSM.
+         * DEPRECATED. Should use useBlurExponentialShadowMap instead.
+         */
         public get useBlurVarianceShadowMap(): boolean {
             Tools.Warn("VSM are now replaced by ESM. Please use useBlurExponentialShadowMap instead.");
             return this.useBlurExponentialShadowMap;
         }
+        /**
+         * Sets the current filter is to blurred VSM.
+         * DEPRECATED. Should use useBlurExponentialShadowMap instead.
+         */
         public set useBlurVarianceShadowMap(value: boolean) {
             Tools.Warn("VSM are now replaced by ESM. Please use useBlurExponentialShadowMap instead.");
             this.useBlurExponentialShadowMap = value;
         }
 
+        /**
+         * Gets if the current filter is set to ESM.
+         */
         public get useExponentialShadowMap(): boolean {
             return this.filter === ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP;
         }
+        /**
+         * Sets the current filter is to ESM.
+         */
         public set useExponentialShadowMap(value: boolean) {
             if (!value && this.filter !== ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP) {
                 return;
@@ -189,9 +345,15 @@
             this.filter = (value ? ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 
+        /**
+         * Gets if the current filter is set to filtered ESM.
+         */
         public get useBlurExponentialShadowMap(): boolean {
             return this.filter === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP;
         }
+        /**
+         * Gets if the current filter is set to filtered  ESM.
+         */
         public set useBlurExponentialShadowMap(value: boolean) {
             if (!value && this.filter !== ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
                 return;
@@ -199,9 +361,17 @@
             this.filter = (value ? ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 
+        /**
+         * Gets if the current filter is set to "close ESM" (using the inverse of the 
+         * exponential to prevent steep falloff artifacts).
+         */
         public get useCloseExponentialShadowMap(): boolean {
             return this.filter === ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP;
         }
+        /**
+         * Sets the current filter to "close ESM" (using the inverse of the 
+         * exponential to prevent steep falloff artifacts).
+         */
         public set useCloseExponentialShadowMap(value: boolean) {
             if (!value && this.filter !== ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP) {
                 return;
@@ -209,9 +379,17 @@
             this.filter = (value ? ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 
+        /**
+         * Gets if the current filter is set to filtered "close ESM" (using the inverse of the 
+         * exponential to prevent steep falloff artifacts).
+         */
         public get useBlurCloseExponentialShadowMap(): boolean {
             return this.filter === ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
         }
+        /**
+         * Sets the current filter to fileterd "close ESM" (using the inverse of the 
+         * exponential to prevent steep falloff artifacts).
+         */
         public set useBlurCloseExponentialShadowMap(value: boolean) {
             if (!value && this.filter !== ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP) {
                 return;
@@ -221,14 +399,17 @@
 
         private _darkness = 0;
         /**
-         * Returns the darkness value (float).  
+         * Returns the darkness value (float). This can only decrease the actual darkness of a shadow.
+         * 0 means strongest and 1 would means no shadow.
+         * @returns the darkness.
          */
         public getDarkness(): number {
             return this._darkness;
         }
         /**
-         * Sets the ShadowGenerator darkness value (float <= 1.0).  
-         * Returns the ShadowGenerator.  
+         * Sets the darkness value (float). This can only decrease the actual darkness of a shadow.
+         * @param darkness The darkness value 0 means strongest and 1 would means no shadow.
+         * @returns the shadow generator allowing fluent coding.
          */
         public setDarkness(darkness: number): ShadowGenerator {
             if (darkness >= 1.0)
@@ -242,24 +423,27 @@
 
         private _transparencyShadow = false;
         /**
-         * Sets the ability to have transparent shadow (boolean).  
-         * Returns the ShadowGenerator.  
+         * Sets the ability to have transparent shadow (boolean).
+         * @param transparent True if transparent else False
+         * @returns the shadow generator allowing fluent coding
          */
-        public setTransparencyShadow(hasShadow: boolean): ShadowGenerator {
-            this._transparencyShadow = hasShadow;
+        public setTransparencyShadow(transparent: boolean): ShadowGenerator {
+            this._transparencyShadow = transparent;
             return this;
         }
 
         private _shadowMap: Nullable<RenderTargetTexture>;
         private _shadowMap2: Nullable<RenderTargetTexture>;
         /**
-         * Returns a RenderTargetTexture object : the shadow map texture.  
+         * Gets the main RTT containing the shadow map (usually storing depth from the light point of view).
+         * @returns The render target texture if present otherwise, null
          */
         public getShadowMap(): Nullable<RenderTargetTexture> {
             return this._shadowMap;
         }
         /**
-         * Returns the most ready computed shadow map as a RenderTargetTexture object.  
+         * Gets the RTT used during rendering (can be a blurred version of the shadow map or the shadow map itself).
+         * @returns The render target texture if the shadow map is present otherwise, null
          */
         public getShadowMapForRendering(): Nullable<RenderTargetTexture> {
             if (this._shadowMap2) {
@@ -270,9 +454,10 @@
         }
 
         /**
-         * Helper function to add a mesh and its descendants to the list of shadow casters
+         * Helper function to add a mesh and its descendants to the list of shadow casters.
          * @param mesh Mesh to add
          * @param includeDescendants boolean indicating if the descendants should be added. Default to true
+         * @returns the Shadow Generator itself
          */
         public addShadowCaster(mesh: AbstractMesh, includeDescendants = true): ShadowGenerator {
             if (!this._shadowMap) {
@@ -296,6 +481,7 @@
          * Helper function to remove a mesh and its descendants from the list of shadow casters
          * @param mesh Mesh to remove
          * @param includeDescendants boolean indicating if the descendants should be removed. Default to true
+         * @returns the Shadow Generator itself
          */
         public removeShadowCaster(mesh: AbstractMesh, includeDescendants = true): ShadowGenerator {
             if (!this._shadowMap || !this._shadowMap.renderList) {
@@ -318,19 +504,25 @@
         }
 
         /**
-		 * Controls the extent to which the shadows fade out at the edge of the frustum
+         * Controls the extent to which the shadows fade out at the edge of the frustum
          * Used only by directionals and spots
-		 */
+         */
         public frustumEdgeFalloff = 0;
 
         private _light: IShadowLight;
         /**
-         * Returns the associated light object.  
+         * Returns the associated light object.
+         * @returns the light generating the shadow
          */
         public getLight(): IShadowLight {
             return this._light;
         }
 
+        /**
+         * If true the shadow map is generated by rendering the back face of the mesh instead of the front face.
+         * This can help with self-shadowing as the geometry making up the back of objects is slightly offset.
+         * It might on the other hand introduce peter panning.
+         */
         public forceBackFacesOnly = false;
 
         private _scene: Scene;
@@ -356,14 +548,13 @@
         private _defaultTextureMatrix = Matrix.Identity();
 
         /**
-         * Creates a ShadowGenerator object.  
-         * A ShadowGenerator is the required tool to use the shadows.  
-         * Each light casting shadows needs to use its own ShadowGenerator.  
-         * Required parameters : 
-         * - `mapSize` (integer): the size of the texture what stores the shadows. Example : 1024.    
-         * - `light`: the light object generating the shadows.  
-         * - `useFullFloatFirst`: by default the generator will try to use half float textures but if you need precision (for self shadowing for instance), you can use this option to enforce full float texture.
+         * Creates a ShadowGenerator object.
+         * A ShadowGenerator is the required tool to use the shadows.
+         * Each light casting shadows needs to use its own ShadowGenerator.
          * Documentation : http://doc.babylonjs.com/tutorials/shadows  
+         * @param mapSize The size of the texture what stores the shadows. Example : 1024.
+         * @param light The light object generating the shadows.  
+         * @param useFullFloatFirst By default the generator will try to use half float textures but if you need precision (for self shadowing for instance), you can use this option to enforce full float texture.
          */
         constructor(mapSize: number, light: IShadowLight, useFullFloatFirst?: boolean) {
             this._mapSize = mapSize;
@@ -595,7 +786,9 @@
         }
 
         /**
-         * Force shader compilation including textures ready check
+         * Forces all the attached effect to compile to enable rendering only once ready vs. lazyly compiling effects.
+         * @param onCompiled Callback triggered at the and of the effects compilation
+         * @param options Sets of optional options forcing the compilation with different modes 
          */
         public forceCompilation(onCompiled?: (generator: ShadowGenerator) => void, options?: Partial<{ useInstances: boolean }>): void {
             let localOptions = {
@@ -653,7 +846,10 @@
         }
 
         /**
-         * Boolean : true when the ShadowGenerator is finally computed.  
+         * Determine wheter the shadow generator is ready or not (mainly all effects and related post processes needs to be ready).
+         * @param subMesh The submesh we want to render in the shadow map
+         * @param useInstances Defines wether will draw in the map using instances
+         * @returns true if ready otherwise, false
          */
         public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
             var defines = [];
@@ -746,7 +942,9 @@
         }
 
         /**
-         * This creates the defines related to the standard BJS materials.
+         * Prepare all the defines in a material relying on a shadow map at the specified light index.
+         * @param defines Defines of the material we want to update
+         * @param lightIndex Index of the light in the enabled light list of the material
          */
         public prepareDefines(defines: any, lightIndex: number): void {
             var scene = this._scene;
@@ -774,8 +972,10 @@
         }
 
         /**
-         * This binds shadow lights related to the standard BJS materials.
-         * It implies the unifroms available on the materials are the standard BJS ones.
+         * Binds the shadow related information inside of an effect (information like near, far, darkness...
+         * defined in the generator but impacting the effect).
+         * @param lightIndex Index of the light in the enabled light list of the material owning the effect
+         * @param effect The effect we are binfing the information for 
          */
         public bindShadowLight(lightIndex: string, effect: Effect): void {
             var light = this._light;
@@ -804,9 +1004,10 @@
             light._uniformBuffer.updateFloat2("depthValues", this.getLight().getDepthMinZ(camera), this.getLight().getDepthMinZ(camera) + this.getLight().getDepthMaxZ(camera), lightIndex);
         }
 
-        // Methods
         /**
-         * Returns a Matrix object : the updated transformation matrix.  
+         * Gets the transformation matrix used to project the meshes into the map from the light point of view.
+         * (eq to shadow prjection matrix * light transform matrix)
+         * @returns The transform matrix used to create the shadow map
          */
         public getTransformMatrix(): Matrix {
             var scene = this._scene;
@@ -850,6 +1051,10 @@
             return this._transformMatrix;
         }
 
+        /**
+         * Recreates the shadow map dependencies like RTT and post processes. This can be used during the switch between
+         * Cube and 2D textures for instance.
+         */
         public recreateShadowMap(): void {
             let shadowMap = this._shadowMap;
             if (!shadowMap) {
@@ -915,8 +1120,10 @@
                 this._light._markMeshesAsLightDirty();
             }
         }
+
         /**
-         * Serializes the ShadowGenerator and returns a serializationObject.  
+         * Serializes the shadow generator setup to a json object.
+         * @returns The serialized JSON object 
          */
         public serialize(): any {
             var serializationObject: any = {};
@@ -953,8 +1160,12 @@
 
             return serializationObject;
         }
+
         /**
-         * Parses a serialized ShadowGenerator and returns a new ShadowGenerator.  
+         * Parses a serialized ShadowGenerator and returns a new ShadowGenerator.
+         * @param parsedShadowGenerator The JSON object to parse
+         * @param scene The scene to create the shadow map for
+         * @returns The parsed shadow generator
          */
         public static Parse(parsedShadowGenerator: any, scene: Scene): ShadowGenerator {
             //casting to point light, as light is missing the position attr and typescript complains.

+ 35 - 6
src/Lights/babylon.directionalLight.ts

@@ -1,4 +1,10 @@
 module BABYLON {
+    /**
+     * A directional light is defined by a direction (what a surprise!). 
+     * The light is emitted from everywhere in the specified direction, and has an infinite range. 
+     * An example of a directional light is when a distance planet is lit by the apparently parallel lines of light from its sun. Light in a downward direction will light the top of an object.
+     * Documentation: https://doc.babylonjs.com/babylon101/lights
+     */
     export class DirectionalLight extends ShadowLight {
 
         private _shadowFrustumSize = 0;
@@ -18,15 +24,29 @@
         }
 
         private _shadowOrthoScale = 0.5;
+        /**
+         * Gets the shadow projection scale against the optimal computed one.
+         * 0.1 by default which means that the projection window is increase by 10% from the optimal size.
+         * This does not impact in fixed frustum size (shadowFrustumSize being set)
+         */
         @serialize()
         public get shadowOrthoScale(): number {
             return this._shadowOrthoScale
         }
+        /**
+         * Sets the shadow projection scale against the optimal computed one.
+         * 0.1 by default which means that the projection window is increase by 10% from the optimal size.
+         * This does not impact in fixed frustum size (shadowFrustumSize being set)
+         */
         public set shadowOrthoScale(value: number) {
             this._shadowOrthoScale = value;
             this.forceProjectionMatrixCompute();
         }
 
+        /**
+         * Automatically compute the projection matrix to best fit (including all the casters)
+         * on each frame.
+         */
         @serialize()
         public autoUpdateExtends = true;
 
@@ -39,8 +59,11 @@
         /**
          * Creates a DirectionalLight object in the scene, oriented towards the passed direction (Vector3).  
          * The directional light is emitted from everywhere in the given direction.  
-         * It can cast shawdows.  
-         * Documentation : http://doc.babylonjs.com/tutorials/lights  
+         * It can cast shawdows.
+         * Documentation : http://doc.babylonjs.com/tutorials/lights
+         * @param name The friendly name of the light
+         * @param direction The direction of the light
+         * @param scene The scene the light belongs to
          */
         constructor(name: string, direction: Vector3, scene: Scene) {
             super(name, scene);
@@ -49,7 +72,8 @@
         }
 
         /**
-         * Returns the string "DirectionalLight".  
+         * Returns the string "DirectionalLight".
+         * @return The class name
          */
         public getClassName(): string {
             return "DirectionalLight";
@@ -57,6 +81,7 @@
 
         /**
          * Returns the integer 1.
+         * @return The light Type id as a constant defines in Light.LIGHTTYPEID_x
          */
         public getTypeID(): number {
             return Light.LIGHTTYPEID_DIRECTIONALLIGHT;
@@ -155,7 +180,9 @@
 
         /**
          * Sets the passed Effect object with the DirectionalLight transformed position (or position if not parented) and the passed name.  
-         * Returns the DirectionalLight.  
+         * @param effect The effect to update
+         * @param lightIndex The index of the light in the effect to update
+         * @returns The directional light
          */
         public transferToEffect(effect: Effect, lightIndex: string): DirectionalLight {
             if (this.computeTransformedInformation()) {
@@ -171,7 +198,8 @@
          * 
          * Values are fixed on directional lights as it relies on an ortho projection hence the need to convert being
          * -1 and 1 to 0 and 1 doing (depth + min) / (min + max) -> (depth + 1) / (1 + 1) -> (depth * 0.5) + 0.5.
-         * @param activeCamera 
+         * @param activeCamera The camera we are returning the min for
+         * @returns the depth min z
          */
         public getDepthMinZ(activeCamera: Camera): number {
             return 1;
@@ -182,7 +210,8 @@
          * 
          * Values are fixed on directional lights as it relies on an ortho projection hence the need to convert being
          * -1 and 1 to 0 and 1 doing (depth + min) / (min + max) -> (depth + 1) / (1 + 1) -> (depth * 0.5) + 0.5.
-         * @param activeCamera 
+         * @param activeCamera The camera we are returning the max for
+         * @returns the depth max z
          */
         public getDepthMaxZ(activeCamera: Camera): number {
             return 1;

+ 35 - 6
src/Lights/babylon.hemisphericLight.ts

@@ -1,8 +1,19 @@
 module BABYLON {
+    /**
+     * The HemisphericLight simulates the ambient environment light,
+     * so the passed direction is the light reflection direction, not the incoming direction.
+     */
     export class HemisphericLight extends Light {
+        /**
+         * The groundColor is the light in the opposite direction to the one specified during creation.
+         * You can think of the diffuse and specular light as coming from the centre of the object in the given direction and the groundColor light in the opposite direction.
+         */
         @serializeAsColor3()
         public groundColor = new Color3(0.0, 0.0, 0.0);
 
+        /**
+         * The light reflection direction, not the incoming direction.
+         */
         @serializeAsVector3()
         public direction: Vector3
 
@@ -12,7 +23,10 @@
          * Creates a HemisphericLight object in the scene according to the passed direction (Vector3).  
          * The HemisphericLight simulates the ambient environment light, so the passed direction is the light reflection direction, not the incoming direction.  
          * The HemisphericLight can't cast shadows.  
-         * Documentation : http://doc.babylonjs.com/tutorials/lights  
+         * Documentation : http://doc.babylonjs.com/tutorials/lights
+         * @param name The friendly name of the light
+         * @param direction The direction of the light reflection
+         * @param scene The scene the light belongs to
          */
         constructor(name: string, direction: Vector3, scene: Scene) {
             super(name, scene);
@@ -30,27 +44,37 @@
         }
 
         /**
-         * Returns the string "HemisphericLight".  
+         * Returns the string "HemisphericLight".
+         * @return The class name
          */
         public getClassName(): string {
             return "HemisphericLight";
-        }          
+        }
+
         /**
          * Sets the HemisphericLight direction towards the passed target (Vector3).  
-         * Returns the updated direction.  
+         * Returns the updated direction.
+         * @param target The target the direction should point to
+         * @return The computed direction
          */
         public setDirectionToTarget(target: Vector3): Vector3 {
             this.direction = Vector3.Normalize(target.subtract(Vector3.Zero()));
             return this.direction;
         }
 
+        /**
+         * Returns the shadow generator associated to the light.
+         * @returns Always null for hemispheric lights because it does not support shadows.
+         */
         public getShadowGenerator(): Nullable<ShadowGenerator> {
             return null;
         }
 
         /**
          * Sets the passed Effect object with the HemisphericLight normalized direction and color and the passed name (string).  
-         * Returns the HemisphericLight.  
+         * @param effect The effect to update
+         * @param lightIndex The index of the light in the effect to update
+         * @returns The hemispheric light
          */
         public transferToEffect(effect: Effect, lightIndex: string): HemisphericLight {
             var normalizeDirection = Vector3.Normalize(this.direction);
@@ -64,14 +88,19 @@
             return this;
         }
 
+        /**
+         * @ignore internal use only.
+         */
         public _getWorldMatrix(): Matrix {
             if (!this._worldMatrix) {
                 this._worldMatrix = Matrix.Identity();
             }
             return this._worldMatrix;
         }
+
         /**
-         * Returns the integer 3.  
+         * Returns the integer 3.
+         * @return The light Type id as a constant defines in Light.LIGHTTYPEID_x
          */
         public getTypeID(): number {
             return Light.LIGHTTYPEID_HEMISPHERICLIGHT;

+ 135 - 90
src/Lights/babylon.light.ts

@@ -1,5 +1,10 @@
 module BABYLON {
-    export class Light extends Node {
+    /**
+     * Base class of all the lights in Babylon. It groups all the generic information about lights.
+     * Lights are used, as you would expect, to affect how meshes are seen, in terms of both illumination and colour. 
+     * All meshes allow light to pass through them unless shadow generation is activated. The default number of lights allowed is four but this can be increased.
+     */
+    export abstract class Light extends Node {
 
         //lightmapMode Consts
         private static _LIGHTMAP_DEFAULT = 0;
@@ -112,15 +117,31 @@ module BABYLON {
             return Light._LIGHTTYPEID_HEMISPHERICLIGHT;
         }
 
+        /**
+         * Diffuse gives the basic color to an object.
+         */
         @serializeAsColor3()
         public diffuse = new Color3(1.0, 1.0, 1.0);
 
+        /**
+         * Specular produces a highlight color on an object.
+         * Note: This is note affecting PBR materials.
+         */
         @serializeAsColor3()
         public specular = new Color3(1.0, 1.0, 1.0);
 
+        /**
+         * Strength of the light.
+         * Note: By default it is define in the framework own unit.
+         * Note: In PBR materials the intensityMode can be use to chose what unit the intensity is defined in.
+         */
         @serialize()
         public intensity = 1.0;
 
+        /**
+         * Defines how far from the source the light is impacting in scene units.
+         * Note: Unused in PBR material as the distance light falloff is defined following the inverse squared falloff.
+         */
         @serialize()
         public range = Number.MAX_VALUE;
 
@@ -164,12 +185,13 @@ module BABYLON {
             this._computePhotometricScale();
         };
 
+        
+        @serialize()
+        private _renderPriority: number;
         /**
          * Defines the rendering priority of the lights. It can help in case of fallback or number of lights
          * exceeding the number allowed of the materials.
          */
-        @serialize()
-        private _renderPriority: number;
         @expandToProperty("_reorderLightsInScene")
         public renderPriority: number = 0;
 
@@ -181,19 +203,30 @@ module BABYLON {
         public shadowEnabled: boolean = true;
 
         private _includedOnlyMeshes: AbstractMesh[];
+        /**
+         * Gets the only meshes impacted by this light.
+         */
         public get includedOnlyMeshes(): AbstractMesh[] {
             return this._includedOnlyMeshes;
         }
-
+        /**
+         * Sets the only meshes impacted by this light.
+         */
         public set includedOnlyMeshes(value: AbstractMesh[]) {
             this._includedOnlyMeshes = value;
             this._hookArrayForIncludedOnly(value);
         }
 
         private _excludedMeshes: AbstractMesh[];
+        /**
+         * Gets the meshes not impacted by this light.
+         */
         public get excludedMeshes(): AbstractMesh[] {
             return this._excludedMeshes;
         }
+        /**
+         * Sets the meshes not impacted by this light.
+         */
         public set excludedMeshes(value: AbstractMesh[]) {
             this._excludedMeshes = value;
             this._hookArrayForExcluded(value);
@@ -201,10 +234,17 @@ module BABYLON {
 
         @serialize("excludeWithLayerMask")
         private _excludeWithLayerMask = 0;
+        /**
+         * Gets the layer id use to find what meshes are not impacted by the light.
+         * Inactive if 0
+         */
         public get excludeWithLayerMask(): number {
             return this._excludeWithLayerMask;
         }
-
+        /**
+         * Sets the layer id use to find what meshes are not impacted by the light.
+         * Inactive if 0
+         */
         public set excludeWithLayerMask(value: number) {
             this._excludeWithLayerMask = value;
             this._resyncMeshes();
@@ -212,10 +252,17 @@ module BABYLON {
 
         @serialize("includeOnlyWithLayerMask")
         private _includeOnlyWithLayerMask = 0;
+        /**
+         * Gets the layer id use to find what meshes are impacted by the light.
+         * Inactive if 0
+         */
         public get includeOnlyWithLayerMask(): number {
             return this._includeOnlyWithLayerMask;
         }
-
+        /**
+         * Sets the layer id use to find what meshes are impacted by the light.
+         * Inactive if 0
+         */
         public set includeOnlyWithLayerMask(value: number) {
             this._includeOnlyWithLayerMask = value;
             this._resyncMeshes();
@@ -223,10 +270,15 @@ module BABYLON {
 
         @serialize("lightmapMode")
         private _lightmapMode = 0;
+        /**
+         * Gets the lightmap mode of this light (should be one of the constants defined by Light.LIGHTMAP_x)
+         */
         public get lightmapMode(): number {
             return this._lightmapMode;
         }
-
+        /**
+         * Sets the lightmap mode of this light (should be one of the constants defined by Light.LIGHTMAP_x)
+         */
         public set lightmapMode(value: number) {
             if (this._lightmapMode === value) {
                 return;
@@ -237,16 +289,34 @@ module BABYLON {
         }
 
         private _parentedWorldMatrix: Matrix;
+
+        /**
+         * Shadow generator associted to the light.
+         * Internal use only.
+         */
         public _shadowGenerator: Nullable<IShadowGenerator>;
+
+        /**
+         * @ignore Internal use only.
+         */
         public _excludedMeshesIds = new Array<string>();
+
+        /**
+         * @ignore Internal use only.
+         */
         public _includedOnlyMeshesIds = new Array<string>();
 
-        // Light uniform buffer
+        /**
+         * The current light unifom buffer.
+         * @ignore Internal use only.
+         */
         public _uniformBuffer: UniformBuffer;
 
         /**
          * Creates a Light object in the scene.  
          * Documentation : http://doc.babylonjs.com/tutorials/lights  
+         * @param name The firendly name of the light
+         * @param scene The scene the light belongs too 
          */
         constructor(name: string, scene: Scene) {
             super(name, scene);
@@ -260,19 +330,33 @@ module BABYLON {
             this._resyncMeshes();
         }
 
-        protected _buildUniformLayout(): void {
-            // Overridden
-        }
+        protected abstract _buildUniformLayout(): void;
+
+        /**
+         * Sets the passed Effect "effect" with the Light information.
+         * @param effect The effect to update
+         * @param lightIndex The index of the light in the effect to update
+         * @returns The light
+         */
+        public abstract transferToEffect(effect: Effect, lightIndex: string): Light;
 
         /**
-         * Returns the string "Light".  
+         * @ignore internal use only.
+         */
+        public abstract _getWorldMatrix(): Matrix;
+
+        /**
+         * Returns the string "Light".
+         * @returns the class name
          */
         public getClassName(): string {
             return "Light";
         }
 
         /**
-         * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
+         * Converts the light information to a readable string for debug purpose.
+         * @param fullDetails Supports for multiple levels of logging within scene loading
+         * @returns the human readable light info
          */
         public toString(fullDetails?: boolean): string {
             var ret = "Name: " + this.name;
@@ -287,10 +371,9 @@ module BABYLON {
             return ret;
         }
 
-
         /**
          * Set the enabled state of this node.
-         * @param {boolean} value - the new enabled state
+         * @param value - the new enabled state
          * @see isEnabled
          */
         public setEnabled(value: boolean): void {
@@ -300,7 +383,8 @@ module BABYLON {
         }
 
         /**
-         * Returns the Light associated shadow generator.  
+         * Returns the Light associated shadow generator if any.
+         * @return the associated shadow generator.
          */
         public getShadowGenerator(): Nullable<IShadowGenerator> {
             return this._shadowGenerator;
@@ -308,20 +392,16 @@ module BABYLON {
 
         /**
          * Returns a Vector3, the absolute light position in the World.  
+         * @returns the world space position of the light
          */
         public getAbsolutePosition(): Vector3 {
             return Vector3.Zero();
         }
 
-        public transferToEffect(effect: Effect, lightIndex: string): void {
-        }
-
-        public _getWorldMatrix(): Matrix {
-            return Matrix.Identity();
-        }
-
         /**
-         * Boolean : True if the light will affect the passed mesh.  
+         * Specifies if the light will affect the passed mesh.
+         * @param mesh The mesh to test against the light
+         * @return true the mesh is affected otherwise, false.
          */
         public canAffectMesh(mesh: AbstractMesh): boolean {
             if (!mesh) {
@@ -348,7 +428,8 @@ module BABYLON {
         }
 
         /**
-         * Returns the light World matrix.  
+         * Computes and Returns the light World matrix.
+         * @returns the world matrix 
          */
         public getWorldMatrix(): Matrix {
             this._currentRenderId = this.getScene().getRenderId();
@@ -376,7 +457,7 @@ module BABYLON {
 		 * @param b Second Light object to compare first.
 		 * @return -1 to reduce's a's index relative to be, 0 for no change, 1 to increase a's index relative to b.
 		 */
-        public static compareLightsPriority(a: Light, b: Light): number {
+        public static CompareLightsPriority(a: Light, b: Light): number {
             //shadow-casting lights have priority over non-shadow-casting lights
             //the renderPrioirty is a secondary sort criterion
             if (a.shadowEnabled !== b.shadowEnabled) {
@@ -384,59 +465,7 @@ module BABYLON {
             }
             return b.renderPriority - a.renderPriority;
         }
-        // Projection texture, if needed
-        protected _computeTextureMatrix(): void{
-            //Leave out for different light type
-        }
-        protected _light_far  :number;
-        @serialize()
-        /**
-         * Allows reading the far clip of the Spotlight for texture projection.
-         */
-        public get light_far(): number {
-            return this._light_far;
-        }
-        /**
-         * Allows setting the far clip of the Spotlight for texture projection.
-         */
-        public set light_far(value: number) {
-            this._light_far = value;
-            this._computeTextureMatrix();
-        }
 
-        protected _light_near :number;
-        @serialize()
-        /**
-         * Allows reading the near clip of the Spotlight for texture projection.
-         */
-        public get light_near(): number {
-            return this._light_near;
-        }
-        /**
-         * Allows setting the near clip of the Spotlight for texture projection.
-         */
-        public set light_near(value: number) {
-            this._light_near = value;
-            this._computeTextureMatrix();
-        }
-
-        @serializeAsTexture("projectedLightTexture")
-        private _projectedLightTexture: Nullable<BaseTexture>;;
-        /** 
-         * Allows reading the projection texture of the light.
-        */
-        public get projectedLightTexture(): Nullable<BaseTexture> {
-            return this._projectedLightTexture;
-        }
-        /**
-        * Allows setting the projection texture of the light.
-        */
-        public set projectedLightTexture(value: Nullable<BaseTexture>) {
-            this._projectedLightTexture = value;
-            this._light_far = 1000.0;
-            this._light_near = 1e-6;
-            this._computeTextureMatrix();
-        }
         /**
          * Disposes the light.  
          */
@@ -455,16 +484,15 @@ module BABYLON {
             }
 
             this._uniformBuffer.dispose();
-            if (this._projectedLightTexture){
-                this._projectedLightTexture.dispose();
-            }
+
             // Remove from scene
             this.getScene().removeLight(this);
             super.dispose();
         }
 
         /**
-         * Returns the light type ID (integer).  
+         * Returns the light type ID (integer).
+         * @returns The light Type id as a constant defines in Light.LIGHTTYPEID_x
          */
         public getTypeID(): number {
             return 0;
@@ -472,13 +500,16 @@ module BABYLON {
 
         /**
          * Returns the intensity scaled by the Photometric Scale according to the light type and intensity mode.
+         * @returns the scaled intensity in intensity mode unit
          */
         public getScaledIntensity() {
             return this._photometricScale * this.intensity;
         }
 
         /**
-         * Returns a new Light object, named "name", from the current one.  
+         * Returns a new Light object, named "name", from the current one.
+         * @param name The name of the cloned light
+         * @returns the new created light
          */
         public clone(name: string): Nullable<Light> {
             let constructor = Light.GetConstructorFromName(this.getTypeID(), name, this.getScene());
@@ -488,9 +519,10 @@ module BABYLON {
             }
             return SerializationHelper.Clone(constructor, this);
         }
+
         /**
          * Serializes the current light into a Serialization object.  
-         * Returns the serialized object.  
+         * @returns the serialized object.
          */
         public serialize(): any {
             var serializationObject = SerializationHelper.Serialize(this);
@@ -527,9 +559,13 @@ module BABYLON {
 
         /**
          * Creates a new typed light from the passed type (integer) : point light = 0, directional light = 1, spot light = 2, hemispheric light = 3.  
-         * This new light is named "name" and added to the passed scene.  
+         * This new light is named "name" and added to the passed scene.
+         * @param type Type according to the types available in Light.LIGHTTYPEID_x
+         * @param name The friendly name of the light
+         * @param scene The scene the new light will belong to
+         * @returns the constructor function
          */
-        static GetConstructorFromName(type: number, name: string, scene: Scene): Nullable<() => Light> {
+        public static GetConstructorFromName(type: number, name: string, scene: Scene): Nullable<() => Light> {
             switch (type) {
                 case 0:
                     return () => new PointLight(name, Vector3.Zero(), scene);
@@ -545,7 +581,10 @@ module BABYLON {
         }
 
         /**
-         * Parses the passed "parsedLight" and returns a new instanced Light from this parsing.  
+         * Parses the passed "parsedLight" and returns a new instanced Light from this parsing.
+         * @param parsedLight The JSON representation of the light
+         * @param scene The scene to create the parsed light in
+         * @returns the created light after parsing
          */
         public static Parse(parsedLight: any, scene: Scene): Nullable<Light> {
             let constructor = Light.GetConstructorFromName(parsedLight.type, parsedLight.name, scene);
@@ -643,6 +682,10 @@ module BABYLON {
             }
         }
 
+        /**
+         * Forces the meshes to update their light related information in their rendering used effects
+         * @ignore Internal Use Only
+         */
         public _markMeshesAsLightDirty() {
             for (var mesh of this.getScene().meshes) {
                 if (mesh._lightSources.indexOf(this) !== -1) {
@@ -717,6 +760,11 @@ module BABYLON {
             }
             return photometricScale;
         }
+
+        /**
+         * Reorder the light in the scene according to their defined priority.
+         * @ignore Internal Use Only
+         */
         public _reorderLightsInScene(): void {
             var scene = this.getScene();
             if (this._renderPriority != 0) {
@@ -724,8 +772,5 @@ module BABYLON {
             }
             this.getScene().sortLightsByPriority();
         }
-
-
-
     }
 }

+ 23 - 3
src/Lights/babylon.pointLight.ts

@@ -1,4 +1,10 @@
 module BABYLON {
+    /**
+     * A point light is a light defined by an unique point in world space. 
+     * The light is emitted in every direction from this point.
+     * A good example of a point light is a standard light bulb.
+     * Documentation: https://doc.babylonjs.com/babylon101/lights
+     */
     export class PointLight extends ShadowLight {
 
         private _shadowAngle = Math.PI / 2;
@@ -23,6 +29,10 @@
             this.forceProjectionMatrixCompute();
         }
 
+        /**
+         * Gets the direction if it has been set.
+         * In case of direction provided, the shadow will not use a cube texture but simulate a spot shadow as a fallback
+         */
         public get direction(): Vector3 {
             return this._direction;
         }
@@ -47,6 +57,9 @@
          * var pointLight = new BABYLON.PointLight("pl", camera.position, scene);
          * ```
          * Documentation : http://doc.babylonjs.com/tutorials/lights  
+         * @param name The light friendly name
+         * @param position The position of the point light in the scene
+         * @param scene The scene the lights belongs to
          */
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, scene);
@@ -55,13 +68,15 @@
 
         /**
          * Returns the string "PointLight"
+         * @returns the class name
          */
         public getClassName(): string {
             return "PointLight";
         }
         
         /**
-         * Returns the integer 0.  
+         * Returns the integer 0.
+         * @returns The light Type id as a constant defines in Light.LIGHTTYPEID_x
          */
         public getTypeID(): number {
             return Light.LIGHTTYPEID_POINTLIGHT;
@@ -69,13 +84,16 @@
 
         /**
          * Specifies wether or not the shadowmap should be a cube texture.
+         * @returns true if the shadowmap needs to be a cube texture.
          */
         public needCube(): boolean {
             return !this.direction;
         }
 
         /**
-         * Returns a new Vector3 aligned with the PointLight cube system according to the passed cube face index (integer).  
+         * Returns a new Vector3 aligned with the PointLight cube system according to the passed cube face index (integer).
+         * @param faceIndex The index of the face we are computed the direction to generate shadow
+         * @returns The set direction in 2d mode otherwise the direction to the cubemap face if needCube() is true
          */
         public getShadowDirection(faceIndex?: number): Vector3 {
             if (this.direction) {
@@ -130,7 +148,9 @@
 
         /**
          * Sets the passed Effect "effect" with the PointLight transformed position (or position, if none) and passed name (string).  
-         * Returns the PointLight.  
+         * @param effect The effect to update
+         * @param lightIndex The index of the light in the effect to update
+         * @returns The point light
          */
         public transferToEffect(effect: Effect, lightIndex: string): PointLight {
             if (this.computeTransformedInformation()) {

+ 139 - 14
src/Lights/babylon.shadowLight.ts

@@ -1,87 +1,198 @@
 module BABYLON {
+    /**
+     * Interface describing all the common properties and methods a shadow light needs to implement.
+     * This helps both the shadow generator and materials to genrate the corresponding shadow maps
+     * as well as binding the different shadow properties to the effects.
+     */
     export interface IShadowLight extends Light {
+        /**
+         * The light id in the scene (used in scene.findLighById for instance)
+         */
         id: string;
+        /**
+         * The position the shdow will be casted from.
+         */
         position: Vector3;
+        /**
+         * In 2d mode (needCube being false), the direction used to cast the shadow.
+         */
         direction: Vector3;
+        /**
+         * The transformed position. Position of the light in world space taking parenting in account.
+         */
         transformedPosition: Vector3;
+        /**
+         * The transformed direction. Direction of the light in world space taking parenting in account.
+         */
         transformedDirection: Vector3;
+        /**
+         * The friendly name of the light in the scene.
+         */
         name: string;
+        /**
+         * Defines the shadow projection clipping minimum z value.
+         */
         shadowMinZ: number;
+        /**
+         * Defines the shadow projection clipping maximum z value.
+         */
         shadowMaxZ: number;
 
+        /**
+         * Computes the transformed information (transformedPosition and transformedDirection in World space) of the current light
+         * @returns true if the information has been computed, false if it does not need to (no parenting)
+         */
         computeTransformedInformation(): boolean;
+
+        /**
+         * Gets the scene the light belongs to.
+         * @returns The scene
+         */
         getScene(): Scene;
 
+        /**
+         * Callback defining a custom Projection Matrix Builder.
+         * This can be used to override the default projection matrix computation.
+         */
         customProjectionMatrixBuilder: (viewMatrix: Matrix, renderList: Array<AbstractMesh>, result: Matrix) => void;
+
+        /**
+         * Sets the shadow projection matrix in parameter to the generated projection matrix.
+         * @param matrix The materix to updated with the projection information
+         * @param viewMatrix The transform matrix of the light
+         * @param renderList The list of mesh to render in the map
+         * @returns The current light
+         */
         setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): IShadowLight;
+
+        /**
+         * Gets the current depth scale used in ESM.
+         * @returns The scale
+         */
         getDepthScale(): number;
 
+        /**
+         * Returns whether or not the shadow generation require a cube texture or a 2d texture.
+         * @returns true if a cube texture needs to be use
+         */
         needCube(): boolean;
+
+        /**
+         * Detects if the projection matrix requires to be recomputed this frame.
+         * @returns true if it requires to be recomputed otherwise, false.
+         */
         needProjectionMatrixCompute(): boolean;
+
+        /**
+         * Forces the shadow generator to recompute the projection matrix even if position and direction did not changed.
+         */
         forceProjectionMatrixCompute(): void;
 
+        /**
+         * Get the direction to use to render the shadow map. In case of cube texture, the face index can be passed.
+         * @param faceIndex The index of the face we are computed the direction to generate shadow
+         * @returns The set direction in 2d mode otherwise the direction to the cubemap face if needCube() is true
+         */
         getShadowDirection(faceIndex?: number): Vector3;
 
         /**
          * Gets the minZ used for shadow according to both the scene and the light.
-         * @param activeCamera 
+         * @param activeCamera The camera we are returning the min for
+         * @returns the depth min z
          */
         getDepthMinZ(activeCamera: Camera): number;
 
         /**
-         * Gets the minZ used for shadow according to both the scene and the light.
-         * @param activeCamera 
+         * Gets the maxZ used for shadow according to both the scene and the light.
+         * @param activeCamera The camera we are returning the max for
+         * @returns the depth max z
          */
         getDepthMaxZ(activeCamera: Camera): number;
     }
 
+    /**
+     * Base implementation of @see IShadowLight
+     * It groups all the common behaviour in order to reduce dupplication and better follow the DRY pattern.
+     */
     export abstract class ShadowLight extends Light implements IShadowLight {
 
         protected abstract _setDefaultShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void;
 
+        /**
+         * The position the shdow will be casted from.
+         */
         @serializeAsVector3()
         public position: Vector3;
 
         protected _direction: Vector3;
         @serializeAsVector3()
+        /**
+         * In 2d mode (needCube being false), gets the direction used to cast the shadow.
+         */
         public get direction(): Vector3 {
             return this._direction;
         }
+        /**
+         * In 2d mode (needCube being false), sets the direction used to cast the shadow.
+         */
         public set direction(value: Vector3) {
             this._direction = value;
         }
 
         private _shadowMinZ: number;
+        /**
+         * Gets the shadow projection clipping minimum z value.
+         */
         @serialize()
         public get shadowMinZ(): number {
             return this._shadowMinZ
         }
+        /**
+         * Sets the shadow projection clipping minimum z value.
+         */
         public set shadowMinZ(value: number) {
             this._shadowMinZ = value;
             this.forceProjectionMatrixCompute();
         }
 
         private _shadowMaxZ: number;
+        /**
+         * Sets the shadow projection clipping maximum z value.
+         */
         @serialize()
         public get shadowMaxZ(): number {
             return this._shadowMaxZ
         }
+        /**
+         * Gets the shadow projection clipping maximum z value.
+         */
         public set shadowMaxZ(value: number) {
             this._shadowMaxZ = value;
             this.forceProjectionMatrixCompute();
         }
 
+        /**
+         * Callback defining a custom Projection Matrix Builder.
+         * This can be used to override the default projection matrix computation.
+         */
         public customProjectionMatrixBuilder: (viewMatrix: Matrix, renderList: Array<AbstractMesh>, result: Matrix) => void;
 
+        /**
+         * The transformed position. Position of the light in world space taking parenting in account.
+         */
         public transformedPosition: Vector3;
 
+        /**
+         * The transformed direction. Direction of the light in world space taking parenting in account.
+         */
         public transformedDirection: Vector3;
 
         private _worldMatrix: Matrix;
         private _needProjectionMatrixCompute: boolean = true;
 
         /**
-         * Computes the light transformed position/direction in case the light is parented. Returns true if parented, else false.
+         * Computes the transformed information (transformedPosition and transformedDirection in World space) of the current light
+         * @returns true if the information has been computed, false if it does not need to (no parenting)
          */
         public computeTransformedInformation(): boolean {
             if (this.parent && this.parent.getWorldMatrix) {
@@ -104,13 +215,16 @@
 
         /**
          * Return the depth scale used for the shadow map.
+         * @returns the depth scale.
          */
         public getDepthScale(): number {
             return 50.0;
         }
 
         /**
-         * Returns the light direction (Vector3) for any passed face index.
+         * Get the direction to use to render the shadow map. In case of cube texture, the face index can be passed.
+         * @param faceIndex The index of the face we are computed the direction to generate shadow
+         * @returns The set direction in 2d mode otherwise the direction to the cubemap face if needCube() is true
          */
         public getShadowDirection(faceIndex?: number): Vector3 {
             return this.transformedDirection ? this.transformedDirection : this.direction;
@@ -118,14 +232,16 @@
 
         /**
          * Returns the ShadowLight absolute position in the World.
+         * @returns the position vector in world space
          */
         public getAbsolutePosition(): Vector3 {
             return this.transformedPosition ? this.transformedPosition : this.position;
         }
 
         /**
-         * Sets the ShadowLight direction toward the passed target (Vector3).
-         * Returns the updated ShadowLight direction (Vector3).
+         * Sets the ShadowLight direction toward the passed target.
+         * @param target The point tot target in local space
+         * @returns the updated ShadowLight direction
          */
         public setDirectionToTarget(target: Vector3): Vector3 {
             this.direction = Vector3.Normalize(target.subtract(this.position));
@@ -133,7 +249,8 @@
         }
 
         /**
-         * Returns the light rotation (Vector3).
+         * Returns the light rotation in euler definition.
+         * @returns the x y z rotation in local space.
          */
         public getRotation(): Vector3 {
             this.direction.normalize();
@@ -143,14 +260,16 @@
         }
 
         /**
-         * Boolean : false by default.
+         * Returns whether or not the shadow generation require a cube texture or a 2d texture.
+         * @returns true if a cube texture needs to be use
          */
         public needCube(): boolean {
             return false;
         }
 
         /**
-         * Specifies wether or not the projection matrix should be recomputed this frame.
+         * Detects if the projection matrix requires to be recomputed this frame.
+         * @returns true if it requires to be recomputed otherwise, false.
          */
         public needProjectionMatrixCompute(): boolean {
             return this._needProjectionMatrixCompute;
@@ -165,6 +284,7 @@
 
         /**
          * Get the world matrix of the sahdow lights.
+         * @ignore Internal Use Only
          */
         public _getWorldMatrix(): Matrix {
             if (!this._worldMatrix) {
@@ -178,7 +298,8 @@
 
         /**
          * Gets the minZ used for shadow according to both the scene and the light.
-         * @param activeCamera 
+         * @param activeCamera The camera we are returning the min for
+         * @returns the depth min z
          */
         public getDepthMinZ(activeCamera: Camera): number {
             return this.shadowMinZ !== undefined ? this.shadowMinZ : activeCamera.minZ;
@@ -186,15 +307,19 @@
 
         /**
          * Gets the maxZ used for shadow according to both the scene and the light.
-         * @param activeCamera 
+         * @param activeCamera The camera we are returning the max for
+         * @returns the depth max z
          */
         public getDepthMaxZ(activeCamera: Camera): number {
             return this.shadowMaxZ !== undefined ? this.shadowMaxZ : activeCamera.maxZ;
         }
 
         /**
-         * Sets the projection matrix according to the type of light and custom projection matrix definition.
-         * Returns the light.
+         * Sets the shadow projection matrix in parameter to the generated projection matrix.
+         * @param matrix The materix to updated with the projection information
+         * @param viewMatrix The transform matrix of the light
+         * @param renderList The list of mesh to render in the map
+         * @returns The current light
          */
         public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): IShadowLight {
             if (this.customProjectionMatrixBuilder) {

+ 124 - 42
src/Lights/babylon.spotLight.ts

@@ -1,6 +1,13 @@
 module BABYLON {
+    /**
+     * A spot light is defined by a position, a direction, an angle, and an exponent. 
+     * These values define a cone of light starting from the position, emitting toward the direction.
+     * The angle, in radians, defines the size (field of illumination) of the spotlight's conical beam, 
+     * and the exponent defines the speed of the decay of the light with distance (reach).
+     * Documentation: https://doc.babylonjs.com/babylon101/lights
+     */
     export class SpotLight extends ShadowLight {
-        /**
+        /*
             upVector , rightVector and direction will form the coordinate system for this spot light. 
             These three vectors will be used as projection matrix when doing texture projection.
             
@@ -17,44 +24,18 @@
             projection matrix. Need to call computeTextureMatrix() to recompute manually. Add inheritance
             to the setting function of the 2 attributes will solve the problem.
         */
-        /**
-         * Main function for light texture projection matrix computing.
-         */
-        protected _computeTextureMatrix(): void{    
-
-            var viewLightMatrix = Matrix.Zero();
-            Matrix.LookAtLHToRef(this.position, this.position.add(this.direction), Vector3.Up(), viewLightMatrix);
-
-            var light_far = this.light_far;
-            var light_near = this.light_near;
-
-            var P = light_far / (light_far - light_near);
-            var Q = - P * light_near;
-            var S = 1.0 / Math.tan(this._angle / 2.0);
-            var A = 1.0;
-            
-            var projectionLightMatrix = Matrix.Zero();
-            Matrix.FromValuesToRef(S/A, 0.0, 0.0, 0.0,
-                0.0, S, 0.0, 0.0,
-                0.0, 0.0, P, 1.0,
-                0.0, 0.0, Q, 0.0, projectionLightMatrix);
-
-            var scaleMatrix = Matrix.Zero();
-            Matrix.FromValuesToRef(0.5, 0.0, 0.0, 0.0,
-                0.0, 0.5, 0.0, 0.0,
-                0.0, 0.0, 0.5, 0.0,
-                0.5, 0.5, 0.5, 1.0, scaleMatrix);
-                
-            this._textureProjectionMatrix.copyFrom(viewLightMatrix);
-            this._textureProjectionMatrix.multiplyToRef(projectionLightMatrix, this._textureProjectionMatrix);
-            this._textureProjectionMatrix.multiplyToRef(scaleMatrix, this._textureProjectionMatrix);
-        }
 
         private _angle: number;
         @serialize()
+        /**
+         * Gets the cone angle of the spot light in Radians.
+         */
         public get angle(): number {
             return this._angle
         }
+        /**
+         * Sets the cone angle of the spot light in Radians.
+         */
         public set angle(value: number) {
             this._angle = value;
             this.forceProjectionMatrixCompute();
@@ -75,6 +56,10 @@
             this._shadowAngleScale = value;
             this.forceProjectionMatrixCompute();
         }
+
+        /**
+         * The light decay speed with the distance from the emission spot.
+         */
         @serialize()
         public exponent: number;
 
@@ -93,15 +78,65 @@
             this._textureProjectionMatrix = value;
         }
 
+        protected _light_near :number;
+        @serialize()
+        /**
+         * Gets the near clip of the Spotlight for texture projection.
+         */
+        public get light_near(): number {
+            return this._light_near;
+        }
+        /**
+         * Sets the near clip of the Spotlight for texture projection.
+         */
+        public set light_near(value: number) {
+            this._light_near = value;
+            this._computeTextureMatrix();
+        }
+
+        protected _light_far  :number;
+        /**
+         * Gets the far clip of the Spotlight for texture projection.
+         */
+        @serialize()
+        public get light_far(): number {
+            return this._light_far;
+        }
+        /**
+         * Sets the far clip of the Spotlight for texture projection.
+         */
+        public set light_far(value: number) {
+            this._light_far = value;
+        }
+
+        @serializeAsTexture("projectedLightTexture")
+        private _projectedLightTexture: Nullable<BaseTexture>;;
+        /** 
+         * Gets the projection texture of the light.
+        */
+        public get projectedLightTexture(): Nullable<BaseTexture> {
+            return this._projectedLightTexture;
+        }
+        /**
+        * Sets the projection texture of the light.
+        */
+        public set projectedLightTexture(value: Nullable<BaseTexture>) {
+            this._projectedLightTexture = value;
+            this._light_far = 1000.0;
+            this._light_near = 1e-6;
+            this._computeTextureMatrix();
+        }
+
         /**
-         * Creates a SpotLight object in the scene with the passed parameters :   
-         * - `position` (Vector3) is the initial SpotLight position,  
-         * - `direction` (Vector3) is the initial SpotLight direction,  
-         * - `angle` (float, in radians) is the spot light cone angle,
-         * - `exponent` (float) is the light decay speed with the distance from the emission spot.  
-         * A spot light is a simply light oriented cone.   
-         * It can cast shadows.  
-         * Documentation : http://doc.babylonjs.com/tutorials/lights  
+         * Creates a SpotLight object in the scene. A spot light is a simply light oriented cone.
+         * It can cast shadows.
+         * Documentation : http://doc.babylonjs.com/tutorials/lights
+         * @param name The light friendly name
+         * @param position The position of the spot light in the scene
+         * @param direction The direction of the light in the scene
+         * @param angle The cone angle of the light in Radians
+         * @param exponent The light decay speed with the distance from the emission spot
+         * @param scene The scene the lights belongs to
          */
         constructor(name: string, position: Vector3, direction: Vector3, angle: number, exponent: number, scene: Scene) {
             super(name, scene);
@@ -114,6 +149,7 @@
 
         /**
          * Returns the string "SpotLight".
+         * @returns the class name
          */
         public getClassName(): string {
             return "SpotLight";
@@ -121,6 +157,7 @@
 
         /**
          * Returns the integer 2.
+         * @returns The light Type id as a constant defines in Light.LIGHTTYPEID_x
          */
         public getTypeID(): number {
             return Light.LIGHTTYPEID_SPOTLIGHT;
@@ -144,6 +181,39 @@
             this.getDepthMinZ(activeCamera), this.getDepthMaxZ(activeCamera), matrix);
         }
 
+        /**
+         * Main function for light texture projection matrix computing.
+         */
+        protected _computeTextureMatrix(): void {
+
+            var viewLightMatrix = Matrix.Zero();
+            Matrix.LookAtLHToRef(this.position, this.position.add(this.direction), Vector3.Up(), viewLightMatrix);
+
+            var light_far = this.light_far;
+            var light_near = this.light_near;
+
+            var P = light_far / (light_far - light_near);
+            var Q = - P * light_near;
+            var S = 1.0 / Math.tan(this._angle / 2.0);
+            var A = 1.0;
+            
+            var projectionLightMatrix = Matrix.Zero();
+            Matrix.FromValuesToRef(S/A, 0.0, 0.0, 0.0,
+                0.0, S, 0.0, 0.0,
+                0.0, 0.0, P, 1.0,
+                0.0, 0.0, Q, 0.0, projectionLightMatrix);
+
+            var scaleMatrix = Matrix.Zero();
+            Matrix.FromValuesToRef(0.5, 0.0, 0.0, 0.0,
+                0.0, 0.5, 0.0, 0.0,
+                0.0, 0.0, 0.5, 0.0,
+                0.5, 0.5, 0.5, 1.0, scaleMatrix);
+                
+            this._textureProjectionMatrix.copyFrom(viewLightMatrix);
+            this._textureProjectionMatrix.multiplyToRef(projectionLightMatrix, this._textureProjectionMatrix);
+            this._textureProjectionMatrix.multiplyToRef(scaleMatrix, this._textureProjectionMatrix);
+        }
+
         protected _buildUniformLayout(): void {
             this._uniformBuffer.addUniform("vLightData", 4);
             this._uniformBuffer.addUniform("vLightDiffuse", 4);
@@ -156,7 +226,9 @@
 
         /**
          * Sets the passed Effect object with the SpotLight transfomed position (or position if not parented) and normalized direction.  
-         * Return the SpotLight.   
+         * @param effect The effect to update
+         * @param lightIndex The index of the light in the effect to update
+         * @returns The spot light
          */
         public transferToEffect(effect: Effect, lightIndex: string): SpotLight {
             var normalizeDirection;
@@ -194,5 +266,15 @@
             }
             return this;
         }
+
+        /**
+         * Disposes the light and the associated resources.
+         */
+        public dispose() : void {
+            super.dispose();
+            if (this._projectedLightTexture){
+                this._projectedLightTexture.dispose();
+            }
+        }
     }
 }

+ 59 - 58
src/Materials/Background/babylon.backgroundMaterial.ts

@@ -1,6 +1,7 @@
 module BABYLON {
     /**
      * Background material defines definition.
+     * @ignore Mainly internal Use
      */
     class BackgroundMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         /**
@@ -126,172 +127,172 @@
         /**
          * Standard reflectance value at parallel view angle.
          */
-        public static standardReflectance0 = 0.05;
+        public static StandardReflectance0 = 0.05;
 
         /**
          * Standard reflectance value at grazing angle.
          */
-        public static standardReflectance90 = 0.5;
+        public static StandardReflectance90 = 0.5;
 
+        @serializeAsColor3()
+        protected _primaryColor: Color3;
         /**
          * Key light Color (multiply against the R channel of the environement texture)
          */
-        @serializeAsColor3()
-        protected _primaryColor: Color3;
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         public primaryColor = Color3.White();
 
+        @serialize()
+        protected _primaryLevel: float;
         /**
          * Key light Level (allowing HDR output of the background)
          */
-        @serialize()
-        protected _primaryLevel: float;
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         public primaryLevel: float = 1;
+        @serializeAsColor3()
+        protected _secondaryColor: Color3;
         /**
          * Secondary light Color (multiply against the G channel of the environement texture)
          */
-        @serializeAsColor3()
-        protected _secondaryColor: Color3;
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         public secondaryColor = Color3.Gray();
 
+        @serialize()
+        protected _secondaryLevel: float;
         /**
          * Secondary light Level (allowing HDR output of the background)
          */
-        @serialize()
-        protected _secondaryLevel: float;
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         public secondaryLevel: float = 1;
 
+        @serializeAsColor3()
+        protected _tertiaryColor: Color3;
         /**
          * Tertiary light Color (multiply against the B channel of the environement texture)
          */
-        @serializeAsColor3()
-        protected _tertiaryColor: Color3;
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         public tertiaryColor = Color3.Black();
 
+        @serialize()
+        protected _tertiaryLevel: float;
         /**
          * Tertiary light Level (allowing HDR output of the background)
          */
-        @serialize()
-        protected _tertiaryLevel: float;
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         public tertiaryLevel: float = 1;
 
+        @serializeAsTexture()
+        protected _reflectionTexture: Nullable<BaseTexture>;
         /**
          * Reflection Texture used in the material.
          * Should be author in a specific way for the best result (refer to the documentation).
          */
-        @serializeAsTexture()
-        protected _reflectionTexture: Nullable<BaseTexture>;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionTexture: Nullable<BaseTexture> = null;
 
+        @serialize()
+        protected _reflectionBlur: float;
         /**
          * Reflection Texture level of blur.
          * 
          * Can be use to reuse an existing HDR Texture and target a specific LOD to prevent authoring the 
          * texture twice.
          */
-        @serialize()
-        protected _reflectionBlur: float;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionBlur: float = 0;
 
+        @serializeAsTexture()
+        protected _diffuseTexture: Nullable<BaseTexture>;
         /**
          * Diffuse Texture used in the material.
          * Should be author in a specific way for the best result (refer to the documentation).
          */
-        @serializeAsTexture()
-        protected _diffuseTexture: Nullable<BaseTexture>;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public diffuseTexture: Nullable<BaseTexture> = null;
 
+        protected _shadowLights: Nullable<IShadowLight[]> = null;
         /**
          * Specify the list of lights casting shadow on the material.
          * All scene shadow lights will be included if null.
          */
-        protected _shadowLights: Nullable<IShadowLight[]> = null;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public shadowLights: Nullable<IShadowLight[]> = null;
 
+        @serialize()
+        protected _shadowBlurScale: int;
         /**
          * For the lights having a blurred shadow generator, this can add a second blur pass in order to reach
          * soft lighting on the background.
          */
-        @serialize()
-        protected _shadowBlurScale: int;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public shadowBlurScale: int = 1;
 
+        @serialize()
+        protected _shadowLevel: float;
         /**
          * Helps adjusting the shadow to a softer level if required.
          * 0 means black shadows and 1 means no shadows.
          */
-        @serialize()
-        protected _shadowLevel: float;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public shadowLevel: float = 0;
 
+        @serializeAsVector3()
+        protected _sceneCenter: Vector3;
         /**
          * In case of opacity Fresnel or reflection falloff, this is use as a scene center.
          * It is usually zero but might be interesting to modify according to your setup.
          */
-        @serializeAsVector3()
-        protected _sceneCenter: Vector3;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public sceneCenter: Vector3 = Vector3.Zero();
 
+        @serialize()
+        protected _opacityFresnel: boolean;
         /**
          * This helps specifying that the material is falling off to the sky box at grazing angle.
          * This helps ensuring a nice transition when the camera goes under the ground.
          */
-        @serialize()
-        protected _opacityFresnel: boolean;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public opacityFresnel: boolean = true;
 
+        @serialize()
+        protected _reflectionFresnel: boolean;
         /**
          * This helps specifying that the material is falling off from diffuse to the reflection texture at grazing angle. 
          * This helps adding a mirror texture on the ground.
          */
-        @serialize()
-        protected _reflectionFresnel: boolean;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionFresnel: boolean = false;
 
+        @serialize()
+        protected _reflectionFalloffDistance: number;
         /**
          * This helps specifying the falloff radius off the reflection texture from the sceneCenter.
          * This helps adding a nice falloff effect to the reflection if used as a mirror for instance.
          */
-        @serialize()
-        protected _reflectionFalloffDistance: number;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionFalloffDistance: number = 0.0;
 
+        @serialize()
+        protected _reflectionAmount: number;
         /**
          * This specifies the weight of the reflection against the background in case of reflection Fresnel.
          */
-        @serialize()
-        protected _reflectionAmount: number;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionAmount: number = 1.0;
 
+        @serialize()
+        protected _reflectionReflectance0: number;
         /**
          * This specifies the weight of the reflection at grazing angle.
          */
-        @serialize()
-        protected _reflectionReflectance0: number;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionReflectance0: number = 0.05;
 
+        @serialize()
+        protected _reflectionReflectance90: number;
         /**
          * This specifies the weight of the reflection at a perpendicular point of view.
          */
-        @serialize()
-        protected _reflectionReflectance90: number;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public reflectionReflectance90: number = 0.5;
 
@@ -304,37 +305,36 @@
 
             if (reflectionWeight < 0.5) {
                 reflectionWeight = reflectionWeight * 2.0;
-                this.reflectionReflectance0 = BackgroundMaterial.standardReflectance0 * reflectionWeight;
-                this.reflectionReflectance90 = BackgroundMaterial.standardReflectance90 * reflectionWeight;
+                this.reflectionReflectance0 = BackgroundMaterial.StandardReflectance0 * reflectionWeight;
+                this.reflectionReflectance90 = BackgroundMaterial.StandardReflectance90 * reflectionWeight;
             } else {
                 reflectionWeight = reflectionWeight * 2.0 - 1.0;
-                this.reflectionReflectance0 = BackgroundMaterial.standardReflectance0 + (1.0 - BackgroundMaterial.standardReflectance0) * reflectionWeight;
-                this.reflectionReflectance90 = BackgroundMaterial.standardReflectance90 + (1.0 - BackgroundMaterial.standardReflectance90) * reflectionWeight;
+                this.reflectionReflectance0 = BackgroundMaterial.StandardReflectance0 + (1.0 - BackgroundMaterial.StandardReflectance0) * reflectionWeight;
+                this.reflectionReflectance90 = BackgroundMaterial.StandardReflectance90 + (1.0 - BackgroundMaterial.StandardReflectance90) * reflectionWeight;
             }
         }
 
+        @serialize()
+        protected _useRGBColor: boolean;
         /**
          * Helps to directly use the maps channels instead of their level.
          */
-        @serialize()
-        protected _useRGBColor: boolean;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public useRGBColor: boolean = true;
 
+        @serialize()
+        protected _enableNoise: boolean;
         /**
          * This helps reducing the banding effect that could occur on the background.
          */
-        @serialize()
-        protected _enableNoise: boolean;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public enableNoise: boolean = false;
 
-
+        @serialize()
+        private _maxSimultaneousLights: int = 4;
         /**
          * Number of Simultaneous lights allowed on the material.
          */
-        @serialize()
-        private _maxSimultaneousLights: int = 4;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public maxSimultaneousLights: int = 4;
 
@@ -503,8 +503,8 @@
         private _reflectionControls = Vector4.Zero();
 
         /**
-         * constructor
-         * @param name The name of the material
+         * Instantiates a Background Material in the given scene
+         * @param name The friendly name of the material
          * @param scene The scene to add the material to
          */
         constructor(name: string, scene: Scene) {
@@ -549,6 +549,7 @@
          * @param mesh The mesh to render
          * @param subMesh The submesh to check against
          * @param useInstances Specify wether or not the material is used with instances
+         * @returns true if all the dependencies are ready (Textures, Effects...)
          */
         public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances: boolean = false): boolean {
             if (subMesh.effect && this.isFrozen) {
@@ -978,8 +979,8 @@
 
         /**
          * Dispose the material.
-         * @forceDisposeEffect Force disposal of the associated effect.
-         * @forceDisposeTextures Force disposal of the associated textures.
+         * @param forceDisposeEffect Force disposal of the associated effect.
+         * @param forceDisposeTextures Force disposal of the associated textures.
          */
         public dispose(forceDisposeEffect: boolean = false, forceDisposeTextures: boolean = false): void {
             if (forceDisposeTextures) {
@@ -1002,7 +1003,7 @@
 
         /**
          * Clones the material.
-         * @name The cloned name.
+         * @param name The cloned name.
          * @returns The cloned material.
          */
         public clone(name: string): BackgroundMaterial {
@@ -1029,9 +1030,9 @@
 
         /**
          * Parse a JSON input to create back a background material.
-         * @param source 
-         * @param scene 
-         * @param rootUrl 
+         * @param source The JSON data to parse
+         * @param scene The scene to create the parsed material in 
+         * @param rootUrl The root url of the assets the material depends upon
          * @returns the instantiated BackgroundMaterial.
          */
         public static Parse(source: any, scene: Scene, rootUrl: string): BackgroundMaterial {

+ 132 - 9
src/Materials/babylon.materialHelper.ts

@@ -1,6 +1,19 @@
 module BABYLON {
+    /**
+     * "Static Class" containing the most commonly used helper while dealing with material for 
+     * rendering purpose.
+     * 
+     * It contains the basic tools to help defining defines, binding uniform for the common part of the materials.
+     * 
+     * This works by convention in BabylonJS but is meant to be use only with shader following the in place naming rules and conventions.
+     */
     export class MaterialHelper {
 
+        /**
+         * Bind the current view position to an effect.
+         * @param effect The effect to be bound
+         * @param scene The scene the eyes position is used from
+         */
         public static BindEyePosition(effect: Effect, scene: Scene): void {
             if (scene._forcedViewPosition) {
                 effect.setVector3("vEyePosition", scene._forcedViewPosition);
@@ -9,6 +22,13 @@ module BABYLON {
             effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera!.globalPosition);
         }
 
+        /**
+         * Helps preparing the defines values about the UVs in used in the effect.
+         * UVs are shared as much as we can accross chanels in the shaders.
+         * @param texture The texture we are preparing the UVs for
+         * @param defines The defines to update
+         * @param key The chanel key "diffuse", "specular"... used in the shader
+         */
         public static PrepareDefinesForMergedUV(texture: BaseTexture, defines: any, key: string): void {
             defines._needUVs = true;
             defines[key] = true;
@@ -24,6 +44,12 @@ module BABYLON {
             }
         }
 
+        /**
+         * Binds a texture matrix value to its corrsponding uniform
+         * @param texture The texture to bind the matrix for 
+         * @param uniformBuffer The uniform buffer receivin the data
+         * @param key The chanel key "diffuse", "specular"... used in the shader
+         */
         public static BindTextureMatrix(texture: BaseTexture, uniformBuffer: UniformBuffer, key: string): void {
             var matrix = texture.getTextureMatrix();
 
@@ -58,7 +84,6 @@ module BABYLON {
          * @param engine defines the current engine
          * @param defines specifies the list of active defines
          * @param useInstances defines if instances have to be turned on
-         * @param alphaTest defines if alpha testing has to be turned on
          */
         public static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean): void {
             var changed = false;
@@ -83,6 +108,16 @@ module BABYLON {
             }
         }
 
+        /**
+         * Prepares the defines used in the shader depending on the attributes data available in the mesh
+         * @param mesh The mesh containing the geometry data we will draw
+         * @param defines The defines to update
+         * @param useVertexColor Precise whether vertex colors should be used or not (override mesh info)
+         * @param useBones Precise whether bones should be used or not (override mesh info)
+         * @param useMorphTargets Precise whether morph targets should be used or not (override mesh info)
+         * @param useVertexAlpha Precise whether vertex alpha should be used or not (override mesh info)
+         * @returns false if defines are considered not dirty and have not been checked
+         */
         public static PrepareDefinesForAttributes(mesh: AbstractMesh, defines: any, useVertexColor: boolean, useBones: boolean, useMorphTargets = false, useVertexAlpha = true): boolean {
             if (!defines._areAttributesDirty && defines._needNormals === defines._normals && defines._needUVs === defines._uvs) {
                 return false;
@@ -139,6 +174,16 @@ module BABYLON {
             return true;
         }
 
+        /**
+         * Prepares the defines related to the light information passed in parameter
+         * @param scene The scene we are intending to draw
+         * @param mesh The mesh the effect is compiling for
+         * @param defines The defines to update
+         * @param specularSupported Specifies whether specular is supported or not (override lights data)
+         * @param maxSimultaneousLights Specfies how manuy lights can be added to the effect at max
+         * @param disableLighting Specifies whether the lighting is disabled (override scene and light)
+         * @returns true if normals will be required for the rest of the effect
+         */
         public static PrepareDefinesForLights(scene: Scene, mesh: AbstractMesh, defines: any, specularSupported: boolean, maxSimultaneousLights = 4, disableLighting = false): boolean {
             if (!defines._areLightsDirty) {
                 return defines._needNormals;
@@ -169,6 +214,7 @@ module BABYLON {
                     var type;
                     if (light.getTypeID() === Light.LIGHTTYPEID_SPOTLIGHT) {
                         type = "SPOTLIGHT" + lightIndex;
+                        defines["PROJECTEDLIGHTTEXTURE" + lightIndex] = (light as SpotLight).projectedLightTexture ? true : false;
                     } else if (light.getTypeID() === Light.LIGHTTYPEID_HEMISPHERICLIGHT) {
                         type = "HEMILIGHT" + lightIndex;
                     } else if (light.getTypeID() === Light.LIGHTTYPEID_POINTLIGHT) {
@@ -207,12 +253,6 @@ module BABYLON {
                         defines["LIGHTMAPNOSPECULAR" + lightIndex] = false;
                     }
 
-                    //Projection texture
-                    if (light.projectedLightTexture){
-                        defines["PROJECTEDLIGHTTEXTURE" + lightIndex] = true;
-                    }else{
-                        defines["PROJECTEDLIGHTTEXTURE" + lightIndex] = false;                        
-                    }
                     lightIndex++;
                     if (lightIndex === maxSimultaneousLights)
                         break;
@@ -252,6 +292,14 @@ module BABYLON {
             return needNormals;
         }
 
+        /**
+         * Prepares the uniforms and samplers list to be used in the effect. This can automatically remove from the list uniforms 
+         * that won t be acctive due to defines being turned off.
+         * @param uniformsListOrOptions The uniform names to prepare or an EffectCreationOptions containing the liist and extra information
+         * @param samplersList The samplers list
+         * @param defines The defines helping in the list generation
+         * @param maxSimultaneousLights The maximum number of simultanous light allowed in the effect
+         */
         public static PrepareUniformsAndSamplersList(uniformsListOrOptions: string[] | EffectCreationOptions, samplersList?: string[], defines?: any, maxSimultaneousLights = 4): void {
             let uniformsList: string[];
             let uniformBuffersList: Nullable<string[]> = null;
@@ -304,6 +352,14 @@ module BABYLON {
             }
         }
 
+        /**
+         * This helps decreasing rank by rank the shadow quality (0 being the highest rank and quality)
+         * @param defines The defines to update while falling back
+         * @param fallbacks The authorized effect fallbacks
+         * @param maxSimultaneousLights The maximum number of lights allowed
+         * @param rank the current rank of the Effect
+         * @returns The newly affected rank
+         */
         public static HandleFallbacksForShadows(defines: any, fallbacks: EffectFallbacks, maxSimultaneousLights = 4, rank = 0): number {
             let lightFallbackRank = 0;
             for (var lightIndex = 0; lightIndex < maxSimultaneousLights; lightIndex++) {
@@ -333,6 +389,12 @@ module BABYLON {
             return lightFallbackRank++;
         }
 
+        /**
+         * Prepares the list of attributes required for morph targets according to the effect defines.
+         * @param attribs The current list of supported attribs
+         * @param mesh The mesh to prepare the morph targets attributes for
+         * @param defines The current Defines of the effect
+         */
         public static PrepareAttributesForMorphTargets(attribs: string[], mesh: AbstractMesh, defines: any): void {
             var influencers = defines["NUM_MORPH_INFLUENCERS"];
 
@@ -359,6 +421,13 @@ module BABYLON {
             }
         }
 
+        /**
+         * Prepares the list of attributes required for bones according to the effect defines.
+         * @param attribs The current list of supported attribs
+         * @param mesh The mesh to prepare the bones attributes for
+         * @param defines The current Defines of the effect
+         * @param fallbacks The current efffect fallback strategy
+         */
         public static PrepareAttributesForBones(attribs: string[], mesh: AbstractMesh, defines: any, fallbacks: EffectFallbacks): void {
             if (defines["NUM_BONE_INFLUENCERS"] > 0) {
                 fallbacks.addCPUSkinningFallback(0, mesh);
@@ -372,6 +441,11 @@ module BABYLON {
             }
         }
 
+        /**
+         * Prepares the list of attributes required for instances according to the effect defines.
+         * @param attribs The current list of supported attribs
+         * @param defines The current Defines of the effect
+         */
         public static PrepareAttributesForInstances(attribs: string[], defines: any): void {
             if (defines["INSTANCES"]) {
                 attribs.push("world0");
@@ -381,7 +455,14 @@ module BABYLON {
             }
         }
 
-        // Bindings
+        /**
+         * Binds the light shadow information to the effect for the given mesh.
+         * @param light The light containing the generator
+         * @param scene The scene the lights belongs to
+         * @param mesh The mesh we are binding the information to render 
+         * @param lightIndex The light index in the effect used to render the mesh
+         * @param effect The effect we are binding the data to
+         */
         public static BindLightShadow(light: Light, scene: Scene, mesh: AbstractMesh, lightIndex: string, effect: Effect): void {
             if (light.shadowEnabled && mesh.receiveShadows) {
                 var shadowGenerator = light.getShadowGenerator();
@@ -391,11 +472,26 @@ module BABYLON {
             }
         }
 
+        /**
+         * Binds the light information to the effect.
+         * @param light The light containing the generator
+         * @param effect The effect we are binding the data to
+         * @param lightIndex The light index in the effect used to render
+         */
         public static BindLightProperties(light: Light, effect: Effect, lightIndex: number): void {
             light.transferToEffect(effect, lightIndex + "");
         }
 
-        public static BindLights(scene: Scene, mesh: AbstractMesh, effect: Effect, defines: any, maxSimultaneousLights = 4, usePhysicalLightFalloff = false) {
+        /**
+         * Binds the lights information from the scene to the effect for the given mesh.
+         * @param scene The scene the lights belongs to
+         * @param mesh The mesh we are binding the information to render 
+         * @param effect The effect we are binding the data to
+         * @param defines The generated defines for the effect
+         * @param maxSimultaneousLights The maximum number of light that can be bound to the effect
+         * @param usePhysicalLightFalloff Specifies whether the light falloff is defined physically or not
+         */
+        public static BindLights(scene: Scene, mesh: AbstractMesh, effect: Effect, defines: any, maxSimultaneousLights = 4, usePhysicalLightFalloff = false): void {
             let len = Math.min(mesh._lightSources.length, maxSimultaneousLights);
 
             for (var i = 0; i < len; i++) {
@@ -423,6 +519,12 @@ module BABYLON {
             }
         }
 
+        /**
+         * Binds the fog information from the scene to the effect for the given mesh.
+         * @param scene The scene the lights belongs to
+         * @param mesh The mesh we are binding the information to render 
+         * @param effect The effect we are binding the data to
+         */
         public static BindFogParameters(scene: Scene, mesh: AbstractMesh, effect: Effect): void {
             if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
                 effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
@@ -430,6 +532,11 @@ module BABYLON {
             }
         }
 
+        /**
+         * Binds the bones information from the mesh to the effect.
+         * @param mesh The mesh we are binding the information to render 
+         * @param effect The effect we are binding the data to
+         */
         public static BindBonesParameters(mesh?: AbstractMesh, effect?: Effect): void {
             if (mesh && mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
                 var matrices = mesh.skeleton.getTransformMatrices(mesh);
@@ -440,6 +547,11 @@ module BABYLON {
             }
         }
 
+        /**
+         * Binds the morph targets information from the mesh to the effect.
+         * @param abstractMesh The mesh we are binding the information to render 
+         * @param effect The effect we are binding the data to
+         */
         public static BindMorphTargetParameters(abstractMesh: AbstractMesh, effect: Effect): void {
             let manager = (<Mesh>abstractMesh).morphTargetManager;
             if (!abstractMesh || !manager) {
@@ -449,12 +561,23 @@ module BABYLON {
             effect.setFloatArray("morphTargetInfluences", manager.influences);
         }
 
+        /**
+         * Binds the logarithmic depth information from the scene to the effect for the given defines.
+         * @param defines The generated defines used in the effect
+         * @param effect The effect we are binding the data to
+         * @param scene The scene we are willing to render with logarithmic scale for
+         */
         public static BindLogDepth(defines: any, effect: Effect, scene: Scene): void {
             if (defines["LOGARITHMICDEPTH"]) {
                 effect.setFloat("logarithmicDepthConstant", 2.0 / (Math.log((<Camera>scene.activeCamera).maxZ + 1.0) / Math.LN2));
             }
         }
 
+        /**
+         * Binds the clip plane information from the scene to the effect.
+         * @param scene The scene the clip plane information are extracted from
+         * @param effect The effect we are binding the data to
+         */
         public static BindClipPlane(effect: Effect, scene: Scene): void {
             if (scene.clipPlane) {
                 var clipPlane = scene.clipPlane;

+ 1 - 1
src/babylon.scene.ts

@@ -2431,7 +2431,7 @@
 
         public sortLightsByPriority(): void {
             if (this.requireLightSorting) {
-                this.lights.sort(Light.compareLightsPriority);
+                this.lights.sort(Light.CompareLightsPriority);
             }
         }