瀏覽代碼

Merge pull request #948 from sebavan/pbrupdate

PBR: Add HDR File support for environment lighting.
David Catuhe 9 年之前
父節點
當前提交
4cad464534
共有 33 個文件被更改,包括 23719 次插入20351 次删除
  1. 27 18
      dist/preview release/babylon.core.js
  2. 1179 1177
      dist/preview release/babylon.d.ts
  3. 35 25
      dist/preview release/babylon.js
  4. 8332 8255
      dist/preview release/babylon.max.js
  5. 34 24
      dist/preview release/babylon.noworker.js
  6. 9 2
      materialsLibrary/config.json
  7. 2 2
      materialsLibrary/dist/babylon.fireMaterial.js
  8. 1 1
      materialsLibrary/dist/babylon.fireMaterial.min.js
  9. 1 1
      materialsLibrary/dist/babylon.normalMaterial.js
  10. 1 1
      materialsLibrary/dist/babylon.normalMaterial.min.js
  11. 632 5
      materialsLibrary/dist/babylon.pbrMaterial.js
  12. 2 2
      materialsLibrary/dist/babylon.pbrMaterial.min.js
  13. 1 1
      materialsLibrary/dist/babylon.simpleMaterial.js
  14. 1 1
      materialsLibrary/dist/babylon.simpleMaterial.min.js
  15. 1 1
      materialsLibrary/dist/babylon.terrainMaterial.js
  16. 1 1
      materialsLibrary/dist/babylon.terrainMaterial.min.js
  17. 104 0
      materialsLibrary/dist/dts/babylon.pbrMaterial.d.ts
  18. 15 4
      materialsLibrary/gulpfile.js
  19. 139 0
      materialsLibrary/materials/pbr/babylon.hdrcubetexture.ts
  20. 43 4
      materialsLibrary/materials/pbr/babylon.pbrMaterial.ts
  21. 48 0
      materialsLibrary/materials/pbr/babylon.sphericalharmonics.ts
  22. 43 0
      materialsLibrary/materials/pbr/babylon.sphericalpolynomial.ts
  23. 136 0
      materialsLibrary/materials/pbr/babylon.tools.cubemaptosphericalpolynomial.ts
  24. 217 0
      materialsLibrary/materials/pbr/babylon.tools.hdr.ts
  25. 148 0
      materialsLibrary/materials/pbr/babylon.tools.panoramatocubemap.ts
  26. 238 135
      materialsLibrary/materials/pbr/pbr.fragment.fx
  27. 6 0
      materialsLibrary/materials/pbr/tsconfig.json
  28. 45 22
      materialsLibrary/test/add/addpbr.js
  29. 12097 10665
      materialsLibrary/test/refs/babylon.max.js
  30. 二進制
      materialsLibrary/test/textures/hdr/environment.hdr
  31. 77 0
      src/babylon.engine.js
  32. 98 4
      src/babylon.engine.ts
  33. 6 0
      src/tsconfig.json

文件差異過大導致無法顯示
+ 27 - 18
dist/preview release/babylon.core.js


文件差異過大導致無法顯示
+ 1179 - 1177
dist/preview release/babylon.d.ts


文件差異過大導致無法顯示
+ 35 - 25
dist/preview release/babylon.js


文件差異過大導致無法顯示
+ 8332 - 8255
dist/preview release/babylon.max.js


文件差異過大導致無法顯示
+ 34 - 24
dist/preview release/babylon.noworker.js


+ 9 - 2
materialsLibrary/config.json

@@ -10,14 +10,21 @@
       "output": "babylon.gradientMaterial.js"
     },
     {
-      "file": "materials/pbr/babylon.pbrMaterial.ts",
+      "file": ["materials/pbr/babylon.pbrMaterial.ts",
+        "materials/pbr/babylon.sphericalharmonics.ts",
+        "materials/pbr/babylon.sphericalpolynomial.ts", 
+        "materials/pbr/babylon.tools.panoramatocubemap.ts",
+        "materials/pbr/babylon.tools.cubemaptosphericalpolynomial.ts",
+        "materials/pbr/babylon.tools.hdr.ts",
+        "materials/pbr/babylon.hdrcubetexture.ts"],
       "shaderFiles": [
         "materials/pbr/pbr.vertex.fx",
         "materials/pbr/pbr.fragment.fx",
         "materials/pbr/legacypbr.vertex.fx",
         "materials/pbr/legacypbr.fragment.fx"
       ],
-      "output": "babylon.pbrMaterial.js"
+      "output": "babylon.pbrMaterial.js",
+      "declarationFilename": "babylon.pbrMaterial.d.ts"
     },
     {
       "file": "materials/normal/babylon.normalMaterial.ts",

文件差異過大導致無法顯示
+ 2 - 2
materialsLibrary/dist/babylon.fireMaterial.js


文件差異過大導致無法顯示
+ 1 - 1
materialsLibrary/dist/babylon.fireMaterial.min.js


文件差異過大導致無法顯示
+ 1 - 1
materialsLibrary/dist/babylon.normalMaterial.js


文件差異過大導致無法顯示
+ 1 - 1
materialsLibrary/dist/babylon.normalMaterial.min.js


文件差異過大導致無法顯示
+ 632 - 5
materialsLibrary/dist/babylon.pbrMaterial.js


文件差異過大導致無法顯示
+ 2 - 2
materialsLibrary/dist/babylon.pbrMaterial.min.js


文件差異過大導致無法顯示
+ 1 - 1
materialsLibrary/dist/babylon.simpleMaterial.js


文件差異過大導致無法顯示
+ 1 - 1
materialsLibrary/dist/babylon.simpleMaterial.min.js


文件差異過大導致無法顯示
+ 1 - 1
materialsLibrary/dist/babylon.terrainMaterial.js


文件差異過大導致無法顯示
+ 1 - 1
materialsLibrary/dist/babylon.terrainMaterial.min.js


+ 104 - 0
materialsLibrary/dist/dts/babylon.pbrMaterial.d.ts

@@ -84,3 +84,107 @@ declare module BABYLON {
         static Parse(source: any, scene: Scene, rootUrl: string): PBRMaterial;
     }
 }
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class SphericalHarmonics {
+        L00: Vector3;
+        L1_1: Vector3;
+        L10: Vector3;
+        L11: Vector3;
+        L2_2: Vector3;
+        L2_1: Vector3;
+        L20: Vector3;
+        L21: Vector3;
+        L22: Vector3;
+        addLight(direction: Vector3, color: Color3, deltaSolidAngle: number): void;
+        scale(scale: number): void;
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class SphericalPolynomial {
+        x: Vector3;
+        y: Vector3;
+        z: Vector3;
+        xx: Vector3;
+        yy: Vector3;
+        zz: Vector3;
+        xy: Vector3;
+        yz: Vector3;
+        zx: Vector3;
+        addAmbient(color: Color3): void;
+        static getSphericalPolynomialFromHarmonics(harmonics: SphericalHarmonics): SphericalPolynomial;
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON.Internals {
+    interface CubeMapInfo {
+        front: Float32Array;
+        back: Float32Array;
+        left: Float32Array;
+        right: Float32Array;
+        up: Float32Array;
+        down: Float32Array;
+        size: number;
+    }
+    class PanoramaToCubeMapTools {
+        private static FACE_FRONT;
+        private static FACE_BACK;
+        private static FACE_LEFT;
+        private static FACE_RIGHT;
+        private static FACE_UP;
+        private static FACE_DOWN;
+        static ConvertPanoramaToCubemap(float32Array: Float32Array, inputWidth: number, inputHeight: number, size: number): CubeMapInfo;
+        private static CreateCubemapTexture(texSize, faceData, float32Array, inputWidth, inputHeight);
+        private static CalcProjectionSpherical(vDir, float32Array, inputWidth, inputHeight);
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON.Internals {
+    class CubeMapToSphericalPolynomialTools {
+        private static FileFaces;
+        static ConvertCubeMapToSphericalPolynomial(cubeInfo: CubeMapInfo): SphericalPolynomial;
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON.Internals {
+    interface HDRInfo {
+        height: number;
+        width: number;
+        dataPosition: number;
+    }
+    class HDRTools {
+        private static Ldexp(mantissa, exponent);
+        private static Rgbe2float(float32array, red, green, blue, exponent, index);
+        private static readStringLine(uint8array, startIndex);
+        static RGBE_ReadHeader(uint8array: Uint8Array): HDRInfo;
+        static GetCubeMapTextureData(buffer: ArrayBuffer, size: number): CubeMapInfo;
+        static RGBE_ReadPixels(uint8array: Uint8Array, hdrInfo: HDRInfo): Float32Array;
+        private static RGBE_ReadPixels_RLE(uint8array, hdrInfo);
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class HDRCubeTexture extends BaseTexture {
+        url: string;
+        coordinatesMode: number;
+        private _noMipmap;
+        private _extensions;
+        private _textureMatrix;
+        private _size;
+        sphericalPolynomial: SphericalPolynomial;
+        constructor(url: string, scene: Scene, size: number, noMipmap?: boolean);
+        private loadTexture();
+        clone(): HDRCubeTexture;
+        delayLoad(): void;
+        getReflectionTextureMatrix(): Matrix;
+        static Parse(parsedTexture: any, scene: Scene, rootUrl: string): HDRCubeTexture;
+        serialize(): any;
+    }
+}

+ 15 - 4
materialsLibrary/gulpfile.js

@@ -20,7 +20,7 @@ function shadersName(filename) {
 }
 
 gulp.task('copyReference', function () {
-    return gulp.src("../dist/preview release/babylon.max.js").pipe(gulp.dest("test"));
+    return gulp.src("../dist/preview release/babylon.max.js").pipe(gulp.dest("test/refs"));
 });
 
 /*
@@ -37,9 +37,20 @@ gulp.task('default', ["copyReference"], function () {
             }));
 
         var js = compilOutput.js;
-        // Build definitions file
-        var dts = compilOutput.dts.pipe(gulp.dest(config.build.dtsOutputDirectory));
-
+        
+        var dts = [];
+        if (material.declarationFilename) {
+            // Build definitions file
+            dts = compilOutput.dts
+                .pipe(concat(material.declarationFilename))
+                .pipe(gulp.dest(config.build.dtsOutputDirectory));
+        }
+        else {
+            // Build definitions file
+            dts = compilOutput.dts
+                .pipe(gulp.dest(config.build.dtsOutputDirectory));
+        }
+        
         var shader = gulp.src(material.shaderFiles).pipe(srcToVariable("BABYLON.Effect.ShadersStore", true, shadersName));
 
         return merge2(js, shader)

+ 139 - 0
materialsLibrary/materials/pbr/babylon.hdrcubetexture.ts

@@ -0,0 +1,139 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+    export class HDRCubeTexture extends BaseTexture {
+        public url: string;
+        public coordinatesMode = Texture.CUBIC_MODE;
+
+        private _noMipmap: boolean;
+        private _extensions: string[];
+        private _textureMatrix: Matrix;
+        private _size: number;
+
+        public sphericalPolynomial: SphericalPolynomial = null;
+
+        constructor(url: string, scene: Scene, size:number, noMipmap?: boolean) {
+            super(scene);
+
+            this.name = url;
+            this.url = url;
+            this._noMipmap = noMipmap;
+            this.hasAlpha = false;
+            this._size = size;
+
+            if (!url) {
+                return;
+            }
+
+            this._texture = this._getFromCache(url, noMipmap);
+
+            if (!this._texture) {
+                if (!scene.useDelayedTextureLoading) {
+                    this.loadTexture();
+                } else {
+                    this.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;
+                }
+            }
+
+            this.isCube = true;
+
+            this._textureMatrix = Matrix.Identity();
+        }
+        
+        private loadTexture() {
+            var callback = (buffer: ArrayBuffer) => {
+                var data = BABYLON.Internals.HDRTools.GetCubeMapTextureData(buffer, this._size);
+                this.sphericalPolynomial = BABYLON.Internals.CubeMapToSphericalPolynomialTools.ConvertCubeMapToSphericalPolynomial(data);
+
+                var mapping = [
+                    "left",
+                    "down",
+                    "front",
+                    "right",
+                    "up",
+                    "back"
+                ];
+
+                var results = [];
+                for (var j = 0; j < 6; j++) {
+                    var dataFace = <Float32Array>data[mapping[j]];
+// TODO. Support Int Textures...
+//                     // 3 channels of 1 bytes per pixel in bytes.
+//                     var byteBuffer = new ArrayBuffer(this._size * this._size * 3);
+//                     var byteArray = new Uint8Array(byteBuffer);
+// 
+//                     /* now convert data from buffer into bytes */
+//                     for(var i = 0; i < this._size * this._size; i++) {
+//                         byteArray[(i * 3) + 0] = dataFace[(i * 3) + 0] * 255;
+//                         byteArray[(i * 3) + 1] = dataFace[(i * 3) + 1] * 255;
+//                         byteArray[(i * 3) + 2] = dataFace[(i * 3) + 2] * 255;
+//                     }
+
+                    results.push(dataFace);
+                }
+                return results;
+            }
+
+            this._texture = (<any>this.getScene().getEngine()).createRawCubeTexture(this.url, this.getScene(), this._size, Engine.TEXTUREFORMAT_RGB, Engine.TEXTURETYPE_FLOAT, this._noMipmap, callback);
+        }
+
+        public clone(): HDRCubeTexture {
+            var newTexture = new HDRCubeTexture(this.url, this.getScene(), this._size, this._noMipmap);
+
+            // Base texture
+            newTexture.level = this.level;
+            newTexture.wrapU = this.wrapU;
+            newTexture.wrapV = this.wrapV;
+            newTexture.coordinatesIndex = this.coordinatesIndex;
+            newTexture.coordinatesMode = this.coordinatesMode;
+
+            return newTexture;
+        }
+
+        // Methods
+        public delayLoad(): void {
+            if (this.delayLoadState !== Engine.DELAYLOADSTATE_NOTLOADED) {
+                return;
+            }
+
+            this.delayLoadState = Engine.DELAYLOADSTATE_LOADED;
+            this._texture = this._getFromCache(this.url, this._noMipmap);
+
+            if (!this._texture) {
+                this.loadTexture();
+            }
+        }
+
+        public getReflectionTextureMatrix(): Matrix {
+            return this._textureMatrix;
+        }
+        
+        public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): HDRCubeTexture {
+            var texture = null;
+            if (parsedTexture.name && !parsedTexture.isRenderTarget) {
+                texture = new BABYLON.HDRCubeTexture(rootUrl + parsedTexture.name, scene, parsedTexture.size);
+                texture.name = parsedTexture.name;
+                texture.hasAlpha = parsedTexture.hasAlpha;
+                texture.level = parsedTexture.level;
+                texture.coordinatesMode = parsedTexture.coordinatesMode;
+            }
+            return texture;
+        }
+
+        public serialize(): any {
+            if (!this.name) {
+                return null;
+            }
+
+            var serializationObject: any = {};
+            serializationObject.name = this.name;
+            serializationObject.hasAlpha = this.hasAlpha;
+            serializationObject.isCube = true;
+            serializationObject.level = this.level;
+            serializationObject.size = this._size;
+            serializationObject.coordinatesMode = this.coordinatesMode;
+
+            return serializationObject;
+        }
+    }
+} 

+ 43 - 4
materialsLibrary/materials/pbr/babylon.pbrMaterial.ts

@@ -82,6 +82,7 @@ module BABYLON {
         public CAMERACONTRAST = false;
         public OVERLOADEDVALUES = false;
         public OVERLOADEDSHADOWVALUES = false;
+        public USESPHERICALFROMREFLECTIONMAP = false;
 
         constructor() {
             super();
@@ -470,10 +471,15 @@ module BABYLON {
                                 this._defines.REFLECTIONMAP_EQUIRECTANGULAR = true;
                                 break;
                         }
+
+                        if (this.reflectionTexture instanceof HDRCubeTexture) {
+                            this._defines.USESPHERICALFROMREFLECTIONMAP = true;
+                            needNormals = true;
+                        }
                     }
                 }
 
-                if (this.lightmapTexture && StandardMaterial.LightmapEnabled) {
+                if (this.lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
                     if (!this.lightmapTexture.isReady()) {
                         return false;
                     } else {
@@ -570,7 +576,7 @@ module BABYLON {
             }
 
             if (scene.lightsEnabled && !this.disableLighting) {
-                needNormals = PBRMaterial.PrepareDefinesForLights(scene, mesh, this._defines);
+                needNormals = PBRMaterial.PrepareDefinesForLights(scene, mesh, this._defines) || needNormals;
             }
 
             if (StandardMaterial.FresnelEnabled) {
@@ -759,7 +765,10 @@ module BABYLON {
                         "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3", "depthValues",
                         "opacityParts", "emissiveLeftColor", "emissiveRightColor",
                         "vLightingIntensity", "vOverloadedShadowIntensity", "vOverloadedIntensity", "vCameraInfos", "vOverloadedAlbedo", "vOverloadedReflection", "vOverloadedReflectivity", "vOverloadedEmissive", "vOverloadedMicroSurface",
-                        "logarithmicDepthConstant"
+                        "logarithmicDepthConstant",
+                        "vSphericalX", "vSphericalY", "vSphericalZ",
+                        "vSphericalXX", "vSphericalYY", "vSphericalZZ",
+                        "vSphericalXY", "vSphericalYZ", "vSphericalZX"
                     ],
                     ["albedoSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "reflectivitySampler", "bumpSampler", "lightmapSampler",
                         "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3"
@@ -856,6 +865,36 @@ module BABYLON {
 
                     this._effect.setMatrix("reflectionMatrix", this.reflectionTexture.getReflectionTextureMatrix());
                     this._effect.setFloat2("vReflectionInfos", this.reflectionTexture.level, 0);
+
+                    if (this._defines.USESPHERICALFROMREFLECTIONMAP) {
+                        this._effect.setFloat3("vSphericalX", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.x.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.x.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.x.z);
+                        this._effect.setFloat3("vSphericalY", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.y.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.y.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.y.z);
+                        this._effect.setFloat3("vSphericalZ", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.z.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.z.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.z.z);
+                        this._effect.setFloat3("vSphericalXX", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.xx.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.xx.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.xx.z);
+                        this._effect.setFloat3("vSphericalYY", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.yy.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.yy.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.yy.z);
+                        this._effect.setFloat3("vSphericalZZ", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.zz.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.zz.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.zz.z);
+                        this._effect.setFloat3("vSphericalXY", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.xy.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.xy.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.xy.z);
+                        this._effect.setFloat3("vSphericalYZ", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.yz.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.yz.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.yz.z);
+                        this._effect.setFloat3("vSphericalZX", (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.zx.x,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.zx.y,
+                            (<HDRCubeTexture>this.reflectionTexture).sphericalPolynomial.zx.z);
+                    }
                 }
 
                 if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
@@ -865,7 +904,7 @@ module BABYLON {
                     this._effect.setMatrix("emissiveMatrix", this.emissiveTexture.getTextureMatrix());
                 }
 
-                if (this.lightmapTexture && StandardMaterial.LightmapEnabled) {
+                if (this.lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
                     this._effect.setTexture("lightmapSampler", this.lightmapTexture);
 
                     this._effect.setFloat2("vLightmapInfos", this.lightmapTexture.coordinatesIndex, this.lightmapTexture.level);

+ 48 - 0
materialsLibrary/materials/pbr/babylon.sphericalharmonics.ts

@@ -0,0 +1,48 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+
+    export class SphericalHarmonics {
+        public L00: Vector3 = Vector3.Zero();
+        public L1_1: Vector3 = Vector3.Zero();
+        public L10: Vector3 = Vector3.Zero();
+        public L11: Vector3 = Vector3.Zero();
+        public L2_2: Vector3 = Vector3.Zero();
+        public L2_1: Vector3 = Vector3.Zero();
+        public L20: Vector3 = Vector3.Zero();
+        public L21: Vector3 = Vector3.Zero();
+        public L22: Vector3 = Vector3.Zero();
+
+        public addLight(direction: Vector3, color: Color3, deltaSolidAngle: number) : void
+        {
+            var colorVector = new Vector3(color.r, color.g, color.b);
+            var c = colorVector.scale(deltaSolidAngle);
+
+            this.L00 = this.L00.add(c.scale(0.282095));
+
+            this.L1_1 = this.L1_1.add(c.scale(0.488603 * direction.y));
+            this.L10 = this.L10.add(c.scale(0.488603 * direction.z));
+            this.L11 = this.L11.add(c.scale(0.488603 * direction.x));
+
+            this.L2_2 = this.L2_2.add(c.scale(1.092548  * direction.x * direction.y));
+            this.L2_1 = this.L2_1.add(c.scale(1.092548 * direction.y * direction.z));
+            this.L21 = this.L21.add(c.scale(1.092548 * direction.x * direction.z));
+
+            this.L20 = this.L20.add(c.scale(0.315392 * (3.0 * direction.z * direction.z - 1.0)));
+            this.L22 = this.L22.add(c.scale(0.546274 * (direction.x * direction.x - direction.y * direction.y)));
+        }
+
+        public scale(scale: number): void
+        {
+            this.L00 = this.L00.scale(scale);
+            this.L1_1 = this.L1_1.scale(scale);
+            this.L10 = this.L10.scale(scale);
+            this.L11 = this.L11.scale(scale);
+            this.L2_2 = this.L2_2.scale(scale);
+            this.L2_1 = this.L2_1.scale(scale);
+            this.L20 = this.L20.scale(scale);
+            this.L21 = this.L21.scale(scale);
+            this.L22 = this.L22.scale(scale);
+        }
+    }
+}

+ 43 - 0
materialsLibrary/materials/pbr/babylon.sphericalpolynomial.ts

@@ -0,0 +1,43 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+
+    export class SphericalPolynomial {
+        public x: Vector3 = Vector3.Zero();
+        public y: Vector3 = Vector3.Zero();
+        public z: Vector3 = Vector3.Zero();
+        public xx: Vector3 = Vector3.Zero();
+        public yy: Vector3 = Vector3.Zero();
+        public zz: Vector3 = Vector3.Zero();
+        public xy: Vector3 = Vector3.Zero();
+        public yz: Vector3 = Vector3.Zero();
+        public zx: Vector3 = Vector3.Zero();
+
+        public addAmbient(color: Color3): void
+        {
+            var colorVector = new Vector3(color.r, color.g, color.b);
+            this.xx = this.xx.add(colorVector);
+            this.yy = this.yy.add(colorVector);
+            this.zz = this.zz.add(colorVector);
+        }
+
+        public static getSphericalPolynomialFromHarmonics(harmonics: SphericalHarmonics): SphericalPolynomial 
+        {
+            var result = new SphericalPolynomial();
+
+            result.x = harmonics.L11.scale(1.02333);
+            result.y = harmonics.L1_1.scale(1.02333);
+            result.z = harmonics.L10.scale(1.02333);
+
+            result.xx = harmonics.L00.scale(0.886277).subtract(harmonics.L20.scale(0.247708)).add(harmonics.L22.scale(0.429043));
+            result.yy = harmonics.L00.scale(0.886277).subtract(harmonics.L20.scale(0.247708)).subtract(harmonics.L22.scale(0.429043));
+            result.zz = harmonics.L00.scale(0.886277).add(harmonics.L20.scale(0.495417));
+
+            result.yz = harmonics.L2_1.scale(0.858086);
+            result.zx = harmonics.L21.scale(0.858086);
+            result.xy = harmonics.L2_2.scale(0.858086);
+
+            return result;
+        }
+    }
+}

+ 136 - 0
materialsLibrary/materials/pbr/babylon.tools.cubemaptosphericalpolynomial.ts

@@ -0,0 +1,136 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.Internals {
+
+    class FileFaceOrientation
+    {
+        public name: string;
+        public worldAxisForNormal: Vector3; // the world axis corresponding to the normal to the face
+        public worldAxisForFileX: Vector3; // the world axis corresponding to texture right x-axis in file
+        public worldAxisForFileY: Vector3; // the world axis corresponding to texture down y-axis in file
+
+        public constructor(name: string, worldAxisForNormal: Vector3, worldAxisForFileX: Vector3, worldAxisForFileY: Vector3) {
+            this.name = name;
+            this.worldAxisForNormal = worldAxisForNormal;
+            this.worldAxisForFileX = worldAxisForFileX;
+            this.worldAxisForFileY = worldAxisForFileY;
+        }
+    };
+
+    export class CubeMapToSphericalPolynomialTools {        
+
+        private static FileFaces: FileFaceOrientation[] = [
+            new FileFaceOrientation("left", new Vector3(1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, -1, 0)), // +X east
+            new FileFaceOrientation("right", new Vector3(-1, 0, 0), new Vector3(0, 0, 1), new Vector3(0, -1, 0)), // -X west
+            new FileFaceOrientation("down", new Vector3(0, 1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, 1)), // +Y north
+            new FileFaceOrientation("up", new Vector3(0, -1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, -1)), // -Y south
+            new FileFaceOrientation("front", new Vector3(0, 0, 1), new Vector3(1, 0, 0), new Vector3(0, -1, 0)), // +Z top
+            new FileFaceOrientation("back", new Vector3(0, 0, -1), new Vector3(-1, 0, 0), new Vector3(0, -1, 0))// -Z bottom
+        ];
+        
+        public static ConvertCubeMapToSphericalPolynomial(cubeInfo: CubeMapInfo): SphericalPolynomial {
+            var sphericalHarmonics = new SphericalHarmonics();
+            var totalSolidAngle = 0.0;
+
+            // The (u,v) range is [-1,+1], so the distance between each texel is 2/Size.
+            var du = 2.0 / cubeInfo.size;
+            var dv = du;
+
+            // The (u,v) of the first texel is half a texel from the corner (-1,-1).
+            var minUV = du * 0.5 - 1.0;
+
+            for (var faceIndex = 0; faceIndex < 6; faceIndex++)
+            {
+                var fileFace = this.FileFaces[faceIndex];
+                var dataArray = cubeInfo[fileFace.name];
+                var v = minUV;
+
+                // TODO: we could perform the summation directly into a SphericalPolynomial (SP), which is more efficient than SphericalHarmonic (SH).
+                // This is possible because during the summation we do not need the SH-specific properties, e.g. orthogonality.
+                // Because SP is still linear, so summation is fine in that basis.
+
+                for (var y = 0; y < cubeInfo.size; y++)
+                {
+                    var u = minUV;
+
+                    for (var x = 0; x < cubeInfo.size; x++)
+                    {
+                        // World direction (not normalised)
+                        var worldDirection =
+                            fileFace.worldAxisForFileX.scale(u).add(
+                            fileFace.worldAxisForFileY.scale(v)).add(
+                            fileFace.worldAxisForNormal);
+                        worldDirection.normalize();
+
+                        var deltaSolidAngle = Math.pow(1.0 + u * u + v * v, -3.0 / 2.0);
+
+                        if (1) {
+                            var r = dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0];
+                            var g = dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1];
+                            var b = dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2];
+
+                            var color = new Color3(r, g, b);
+
+                            sphericalHarmonics.addLight(worldDirection, color, deltaSolidAngle);    
+                        }
+                        else {
+
+                            if (faceIndex == 0) {
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 1;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 0;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 0;                                
+                            }
+                            else if (faceIndex == 1) {
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 0;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 1;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 0;
+                            }
+                            else if (faceIndex == 2) {
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 0;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 0;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 1;
+                            }
+                            else if (faceIndex == 3) {
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 1;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 1;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 0;
+                            }
+                            else if (faceIndex == 4) {
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 1;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 0;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 1;
+                            }
+                            else if (faceIndex == 5) {
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 0;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 1;
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 1;
+                            }
+
+                            var color = new Color3(dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0], 
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1], 
+                                dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2]);
+
+                            sphericalHarmonics.addLight(worldDirection, color, deltaSolidAngle);
+                        }
+
+                        totalSolidAngle += deltaSolidAngle;
+
+                        u += du;
+                    }
+
+                    v += dv;
+                }
+            }
+
+            var correctSolidAngle = 4.0 * Math.PI; // Solid angle for entire sphere is 4*pi
+            var correction = correctSolidAngle / totalSolidAngle;
+
+            sphericalHarmonics.scale(correction);
+
+            // Additionally scale by pi -- audit needed
+            sphericalHarmonics.scale(1.0 / Math.PI);
+
+            return SphericalPolynomial.getSphericalPolynomialFromHarmonics(sphericalHarmonics);
+        }
+    }
+} 

+ 217 - 0
materialsLibrary/materials/pbr/babylon.tools.hdr.ts

@@ -0,0 +1,217 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.Internals {
+    export interface HDRInfo {
+        height: number;
+        width: number;
+        dataPosition: number;
+    };
+
+    export class HDRTools {
+
+        private static Ldexp(mantissa: number, exponent: number): number {
+            if (exponent > 1023) {
+                return mantissa * Math.pow(2, 1023) * Math.pow(2, exponent - 1023);
+            }
+
+            if (exponent < -1074) {
+                return mantissa * Math.pow(2, -1074) * Math.pow(2, exponent + 1074);
+            }
+
+            return mantissa * Math.pow(2, exponent);
+        }
+
+        private static Rgbe2float(float32array: Float32Array, 
+            red: number, green: number, blue: number, exponent: number,
+            index: number)
+        {
+            if (exponent > 0) {   /*nonzero pixel*/
+                exponent = this.Ldexp(1.0, exponent - (128 + 8));
+
+                float32array[index + 0] = red * exponent;
+                float32array[index + 1] = green * exponent;
+                float32array[index + 2] = blue * exponent;
+            }
+            else {
+                float32array[index + 0] = 0;
+                float32array[index + 1] = 0;
+                float32array[index + 2] = 0;
+            }
+        }
+
+        private static readStringLine(uint8array: Uint8Array, startIndex: number): string {
+            var line = "";
+            var character = "";
+
+            for(var i = startIndex; i < uint8array.length - startIndex; i++) {
+                character = String.fromCharCode(uint8array[i]);
+
+                if (character == "\n") {
+                    break;
+                }
+
+                line += character;
+            }
+
+            return line;
+        }
+
+        /* minimal header reading.  modify if you want to parse more information */
+        public static RGBE_ReadHeader(uint8array: Uint8Array) : HDRInfo {
+            var height: number = 0;
+            var width: number = 0;
+            
+            var line = this.readStringLine(uint8array, 0);
+            if (line[0] != '#' || line[1] != '?') {
+                throw "Bad HDR Format.";
+            }
+
+            var endOfHeader = false;
+            var findFormat = false;
+            var lineIndex:number = 0;
+
+            do {
+                lineIndex += (line.length + 1);
+                line = this.readStringLine(uint8array, lineIndex);
+
+                if (line == "FORMAT=32-bit_rle_rgbe") {
+                    findFormat = true;
+                }
+                else if (line.length == 0) {
+                    endOfHeader = true;
+                }
+            } while (!endOfHeader);
+
+            if (!findFormat) {
+                throw "HDR Bad header format, unsupported FORMAT"; 
+            }
+
+            lineIndex += (line.length + 1);
+            line = this.readStringLine(uint8array, lineIndex);
+            
+            var sizeRegexp = /^\-Y (.*) \+X (.*)$/g;
+            var match = sizeRegexp.exec(line);
+
+            // TODO. Support +Y and -X if needed.
+            if (match.length < 3) {
+                throw "HDR Bad header format, no size"; 
+            }
+            width = parseInt(match[2]);
+            height = parseInt(match[1]);
+
+            if (width < 8 || width > 0x7fff) {
+                throw "HDR Bad header format, unsupported size"; 
+            }
+
+            lineIndex += (line.length + 1);
+
+            return {
+                height: height,
+                width: width,
+                dataPosition: lineIndex
+            };
+        }
+
+        public static GetCubeMapTextureData(buffer: ArrayBuffer, size: number) : CubeMapInfo {
+            var uint8array = new Uint8Array(buffer);
+            var hdrInfo = this.RGBE_ReadHeader(uint8array);
+            var data = this.RGBE_ReadPixels_RLE(uint8array, hdrInfo);
+
+            var cubeMapData = PanoramaToCubeMapTools.ConvertPanoramaToCubemap(data, hdrInfo.width, hdrInfo.height, size);
+
+            return cubeMapData;
+        }
+
+        public static RGBE_ReadPixels(uint8array:Uint8Array, hdrInfo:HDRInfo): Float32Array {
+            // Keep for multi format supports.
+            return this.RGBE_ReadPixels_RLE(uint8array, hdrInfo);
+        }
+
+        private static RGBE_ReadPixels_RLE(uint8array:Uint8Array, hdrInfo:HDRInfo): Float32Array {
+            var num_scanlines = hdrInfo.height;
+            var scanline_width = hdrInfo.width;
+
+            var a: number, b: number, c: number, d: number, count: number;
+            var dataIndex = hdrInfo.dataPosition;
+            var index = 0, endIndex = 0, i = 0;
+
+            var scanLineArrayBuffer = new ArrayBuffer(scanline_width * 4); // four channel R G B E
+            var scanLineArray = new Uint8Array(scanLineArrayBuffer);
+
+            // 3 channels of 4 bytes per pixel in float.
+            var resultBuffer = new ArrayBuffer(hdrInfo.width * hdrInfo.height * 4 * 3); 
+            var resultArray = new Float32Array(resultBuffer);
+
+            // read in each successive scanline
+            while(num_scanlines > 0) {
+                a = uint8array[dataIndex++];
+                b = uint8array[dataIndex++];
+                c = uint8array[dataIndex++];
+                d = uint8array[dataIndex++];
+
+                if (a != 2 || b != 2 || (c & 0x80)) {
+                  // this file is not run length encoded
+                  throw "HDR Bad header format, not RLE"; 
+                }
+
+                if (((c<<8) | d) != scanline_width) {
+                  throw "HDR Bad header format, wrong scan line width"; 
+                }
+
+                index = 0;
+
+                // read each of the four channels for the scanline into the buffer
+                for(i = 0; i < 4; i++) {
+                    endIndex = (i + 1) * scanline_width;
+
+                    while(index < endIndex) {
+                        a = uint8array[dataIndex++];
+                        b = uint8array[dataIndex++];
+
+                        if (a > 128) {
+                            // a run of the same value
+                            count = a - 128;
+                            if ((count == 0) || (count > endIndex - index)) {
+                                throw "HDR Bad Format, bad scanline data (run)";
+                            }
+
+                            while(count-- > 0) {
+                                scanLineArray[index++] = b;
+                            }
+                        }
+                        else {
+                            // a non-run
+                            count = a;
+                            if ((count == 0) || (count > endIndex - index)) {
+                                throw "HDR Bad Format, bad scanline data (non-run)";
+                            }
+
+                            scanLineArray[index++] = b;
+                            if (--count > 0) {
+                                for (var j = 0; j < count; j++) {
+                                    scanLineArray[index++] = uint8array[dataIndex++];
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // now convert data from buffer into floats
+                for(i = 0; i < scanline_width; i++) {
+                    a = scanLineArray[i];
+                    b = scanLineArray[i + scanline_width];
+                    c = scanLineArray[i + 2 * scanline_width];
+                    d = scanLineArray[i + 3 * scanline_width];
+
+                    this.Rgbe2float(resultArray,
+                        a, b, c, d,
+                        (hdrInfo.height - num_scanlines) * scanline_width * 3 + i * 3);
+                }
+
+                num_scanlines--;
+            }
+
+            return resultArray;
+        }
+    }
+} 

+ 148 - 0
materialsLibrary/materials/pbr/babylon.tools.panoramatocubemap.ts

@@ -0,0 +1,148 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.Internals {
+    export interface CubeMapInfo {
+        front: Float32Array;
+        back: Float32Array;
+        left: Float32Array;
+        right: Float32Array;
+        up: Float32Array;
+        down: Float32Array;
+        size: number;
+    }
+
+    export class PanoramaToCubeMapTools {
+
+        private static FACE_FRONT = [
+            new Vector3(-1.0, -1.0, -1.0),
+            new Vector3(1.0, -1.0, -1.0),
+            new Vector3(-1.0, 1.0, -1.0),
+            new Vector3(1.0, 1.0, -1.0)
+        ];
+        private static FACE_BACK = [
+            new Vector3(1.0, -1.0, 1.0),
+            new Vector3(-1.0, -1.0, 1.0),
+            new Vector3(1.0, 1.0, 1.0),
+            new Vector3(-1.0, 1.0, 1.0)
+        ];
+        private static FACE_LEFT = [
+            new Vector3(1.0, -1.0, -1.0),
+            new Vector3(1.0, -1.0, 1.0),
+            new Vector3(1.0, 1.0, -1.0),
+            new Vector3(1.0, 1.0, 1.0)
+        ];
+        private static FACE_RIGHT = [
+            new Vector3(-1.0, -1.0, 1.0),
+            new Vector3(-1.0, -1.0, -1.0),
+            new Vector3(-1.0, 1.0, 1.0),
+            new Vector3(-1.0, 1.0, -1.0)
+        ];
+        private static FACE_UP = [
+            new Vector3(-1.0, 1.0, -1.0),
+            new Vector3(1.0, 1.0, -1.0),
+            new Vector3(-1.0, 1.0, 1.0),
+            new Vector3(1.0, 1.0, 1.0)
+        ];
+        private static FACE_DOWN = [
+            new Vector3(-1.0, -1.0, 1.0),
+            new Vector3(1.0, -1.0, 1.0),
+            new Vector3(-1.0, -1.0, -1.0),
+            new Vector3(1.0, -1.0, -1.0)
+        ];
+
+        public static ConvertPanoramaToCubemap(float32Array: Float32Array, inputWidth: number, inputHeight: number, size: number): CubeMapInfo {
+            if (!float32Array) {
+                throw "ConvertPanoramaToCubemap: input cannot be null";
+            }
+
+            if (float32Array.length != inputWidth * inputHeight * 3) {
+                throw "ConvertPanoramaToCubemap: input size is wrong";
+            }
+
+            var textureFront  = this.CreateCubemapTexture(size, this.FACE_FRONT, float32Array, inputWidth, inputHeight);
+            var textureBack   = this.CreateCubemapTexture(size, this.FACE_BACK, float32Array, inputWidth, inputHeight);
+            var textureLeft   = this.CreateCubemapTexture(size, this.FACE_LEFT, float32Array, inputWidth, inputHeight);
+            var textureRight  = this.CreateCubemapTexture(size, this.FACE_RIGHT, float32Array, inputWidth, inputHeight);
+            var textureUp     = this.CreateCubemapTexture(size, this.FACE_UP, float32Array, inputWidth, inputHeight);
+            var textureDown   = this.CreateCubemapTexture(size, this.FACE_DOWN, float32Array, inputWidth, inputHeight);
+
+            return {
+                front: textureFront,
+                back: textureBack,
+                left: textureLeft,
+                right: textureRight,
+                up: textureUp,
+                down: textureDown,
+                size: size
+            };
+        }
+
+        private static CreateCubemapTexture(texSize: number, faceData: Vector3[], float32Array: Float32Array, inputWidth: number, inputHeight: number) {
+            var buffer = new ArrayBuffer(texSize * texSize * 4 * 3);
+            var textureArray = new Float32Array(buffer);
+
+            var rotDX1 = faceData[1].subtract(faceData[0]).scale(1 / texSize);
+            var rotDX2 = faceData[3].subtract(faceData[2]).scale(1 / texSize);
+
+            var dy = 1 / texSize;
+            var fy = 0;
+
+            for (var y = 0; y < texSize; y++) {
+                var xv1 = faceData[0];
+                var xv2 = faceData[2];
+
+                for (var x = 0; x < texSize; x++) {
+                    var v = xv2.subtract(xv1).scale(fy).add(xv1);
+                    v.normalize();
+
+                    var color = this.CalcProjectionSpherical(v, float32Array, inputWidth, inputHeight);
+
+                    // 3 channels per pixels
+                    textureArray[y * texSize * 3 + (x * 3) + 0] = color.r;
+                    textureArray[y * texSize * 3 + (x * 3) + 1] = color.g;
+                    textureArray[y * texSize * 3 + (x * 3) + 2] = color.b;
+
+                    xv1 = xv1.add(rotDX1);
+                    xv2 = xv2.add(rotDX2);
+                }
+
+                fy += dy;
+            }
+
+            return textureArray;
+        }
+
+        private static CalcProjectionSpherical(vDir: Vector3, float32Array: Float32Array, inputWidth: number, inputHeight: number): any {
+            var theta = Math.atan2(vDir.z, vDir.x);
+            var phi   = Math.acos(vDir.y);
+            
+            while (theta < -Math.PI) theta += 2 * Math.PI;
+            while (theta > Math.PI) theta -= 2 * Math.PI;
+
+            var dx = theta / Math.PI;
+            var dy = phi / Math.PI;
+            
+            // recenter.
+            dx = dx * 0.5 + 0.5;
+
+            var px = Math.round(dx * inputWidth);
+            if (px < 0) px = 0;
+            else if (px >= inputWidth) px = inputWidth - 1;
+
+            var py = Math.round(dy * inputHeight);
+            if (py < 0) py = 0;
+            else if (py >= inputHeight) py = inputHeight - 1;
+
+            var inputY = (inputHeight - py - 1);
+            var r = float32Array[inputY * inputWidth * 3 + (px * 3) + 0];
+            var g = float32Array[inputY * inputWidth * 3 + (px * 3) + 1];
+            var b = float32Array[inputY * inputWidth * 3 + (px * 3) + 2];
+
+            return {
+                r: r,
+                g: g,
+                b: b
+            };
+        }
+    }
+} 

+ 238 - 135
materialsLibrary/materials/pbr/pbr.fragment.fx

@@ -35,9 +35,97 @@ uniform vec4 vCameraInfos;
     uniform vec4 vOverloadedShadowIntensity;
 #endif
 
+#ifdef USESPHERICALFROMREFLECTIONMAP
+    uniform vec3 vSphericalX;
+    uniform vec3 vSphericalY;
+    uniform vec3 vSphericalZ;
+    uniform vec3 vSphericalXX;
+    uniform vec3 vSphericalYY;
+    uniform vec3 vSphericalZZ;
+    uniform vec3 vSphericalXY;
+    uniform vec3 vSphericalYZ;
+    uniform vec3 vSphericalZX;
+
+    vec3 EnvironmentIrradiance(vec3 normal)
+    {
+        // Note: 'normal' is assumed to be normalised (or near normalised)
+        // This isn't as critical as it is with other calculations (e.g. specular highlight), but the result will be incorrect nonetheless.
+
+        // TODO: switch to optimal implementation
+        vec3 result =
+            vSphericalX * normal.x +
+            vSphericalY * normal.y +
+            vSphericalZ * normal.z +
+            vSphericalXX * normal.x * normal.x +
+            vSphericalYY * normal.y * normal.y +
+            vSphericalZZ * normal.z * normal.z +
+            vSphericalYZ * normal.y * normal.z +
+            vSphericalZX * normal.z * normal.x +
+            vSphericalXY * normal.x * normal.y;
+
+        return result.rgb;
+    }
+#endif
+
 // PBR CUSTOM CONSTANTS
 const float kPi = 3.1415926535897932384626433832795;
 
+#ifdef PoissonSamplingEnvironment
+    const int poissonSphereSamplersCount = 32;
+    vec3 poissonSphereSamplers[poissonSphereSamplersCount];
+
+    void initSamplers()
+    {
+        poissonSphereSamplers[0] = vec3( -0.552198926093, 0.801049753814, -0.0322487480415 );
+        poissonSphereSamplers[1] = vec3( 0.344874796559, -0.650989584719, 0.283038477033 ); 
+        poissonSphereSamplers[2] = vec3( -0.0710183703467, 0.163770497767, -0.95022416734 ); 
+        poissonSphereSamplers[3] = vec3( 0.422221832073, 0.576613638193, 0.519157625948 ); 
+        poissonSphereSamplers[4] = vec3( -0.561872200916, -0.665581249881, -0.131630473211 ); 
+        poissonSphereSamplers[5] = vec3( -0.409905973809, 0.0250731510778, 0.674676954809 ); 
+        poissonSphereSamplers[6] = vec3( 0.206829570551, -0.190199352704, 0.919073906156 ); 
+        poissonSphereSamplers[7] = vec3( -0.857514664463, 0.0274425010091, -0.475068738967 ); 
+        poissonSphereSamplers[8] = vec3( -0.816275009951, -0.0432916479141, 0.40394579291 ); 
+        poissonSphereSamplers[9] = vec3( 0.397976181928, -0.633227519667, -0.617794410447 ); 
+        poissonSphereSamplers[10] = vec3( -0.181484199014, 0.0155418272003, -0.34675720703 ); 
+        poissonSphereSamplers[11] = vec3( 0.591734926919, 0.489930882201, -0.51675303188 ); 
+        poissonSphereSamplers[12] = vec3( -0.264514973057, 0.834248662136, 0.464624235985 ); 
+        poissonSphereSamplers[13] = vec3( -0.125845223505, 0.812029586099, -0.46213797731 ); 
+        poissonSphereSamplers[14] = vec3( 0.0345715424639, 0.349983742938, 0.855109899027 ); 
+        poissonSphereSamplers[15] = vec3( 0.694340492749, -0.281052190209, -0.379600605543 ); 
+        poissonSphereSamplers[16] = vec3( -0.241055518078, -0.580199280578, 0.435381168431 );
+        poissonSphereSamplers[17] = vec3( 0.126313722289, 0.715113642744, 0.124385788055 ); 
+        poissonSphereSamplers[18] = vec3( 0.752862552387, 0.277075021888, 0.275059597549 );
+        poissonSphereSamplers[19] = vec3( -0.400896300918, -0.309374534321, -0.74285782627 ); 
+        poissonSphereSamplers[20] = vec3( 0.121843331941, -0.00381197918195, 0.322441835258 ); 
+        poissonSphereSamplers[21] = vec3( 0.741656771351, -0.472083016745, 0.14589173819 ); 
+        poissonSphereSamplers[22] = vec3( -0.120347565985, -0.397252703556, -0.00153836114051 ); 
+        poissonSphereSamplers[23] = vec3( -0.846258835203, -0.433763808754, 0.168732209784 ); 
+        poissonSphereSamplers[24] = vec3( 0.257765618362, -0.546470581239, -0.242234375624 ); 
+        poissonSphereSamplers[25] = vec3( -0.640343473361, 0.51920903395, 0.549310644325 ); 
+        poissonSphereSamplers[26] = vec3( -0.894309984621, 0.297394061018, 0.0884583225292 ); 
+        poissonSphereSamplers[27] = vec3( -0.126241933628, -0.535151016335, -0.440093659672 ); 
+        poissonSphereSamplers[28] = vec3( -0.158176440297, -0.393125021578, 0.890727226039 ); 
+        poissonSphereSamplers[29] = vec3( 0.896024272938, 0.203068725821, -0.11198597748 ); 
+        poissonSphereSamplers[30] = vec3( 0.568671758933, -0.314144243629, 0.509070768816 ); 
+        poissonSphereSamplers[31] = vec3( 0.289665332178, 0.104356977462, -0.348379247171 );
+    }
+
+    vec3 environmentSampler(samplerCube cubeMapSampler, vec3 centralDirection, float microsurfaceAverageSlope)
+    {
+        vec3 result = vec3(0., 0., 0.);
+        for(int i = 0; i < poissonSphereSamplersCount; i++)
+        {
+            vec3 offset = poissonSphereSamplers[i];
+            vec3 direction = centralDirection + microsurfaceAverageSlope * offset;
+            result += textureCube(cubeMapSampler, direction, 0.).rgb;
+        }
+
+        result /= 32.0;
+        return result;
+    }
+
+#endif
+
 // PBR HELPER METHODS
 float Square(float value)
 {
@@ -791,89 +879,92 @@ lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4
 }
 
 void main(void) {
+    #ifdef PoissonSamplingEnvironment
+        initSamplers();
+    #endif
+
     // Clip plane
-#ifdef CLIPPLANE
-    if (fClipDistance > 0.0)
-        discard;
-#endif
+    #ifdef CLIPPLANE
+        if (fClipDistance > 0.0)
+            discard;
+    #endif
 
     vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
 
-    // Base color
-    vec4 baseColor = vec4(1., 1., 1., 1.);
-    vec3 albedoColor = vAlbedoColor.rgb;
+    // Albedo
+    vec4 surfaceAlbedo = vec4(1., 1., 1., 1.);
+    vec3 surfaceAlbedoContribution = vAlbedoColor.rgb;
     
     // Alpha
     float alpha = vAlbedoColor.a;
 
-#ifdef ALBEDO
-    baseColor = texture2D(albedoSampler, vAlbedoUV);
-    baseColor = vec4(toLinearSpace(baseColor.rgb), baseColor.a);
+    #ifdef ALBEDO
+        surfaceAlbedo = texture2D(albedoSampler, vAlbedoUV);
+        surfaceAlbedo = vec4(toLinearSpace(surfaceAlbedo.rgb), surfaceAlbedo.a);
 
-#ifdef ALPHATEST
-    if (baseColor.a < 0.4)
-        discard;
-#endif
+    #ifdef ALPHATEST
+        if (surfaceAlbedo.a < 0.4)
+            discard;
+    #endif
 
-#ifdef ALPHAFROMALBEDO
-    alpha *= baseColor.a;
-#endif
+    #ifdef ALPHAFROMALBEDO
+        alpha *= surfaceAlbedo.a;
+    #endif
 
-    baseColor.rgb *= vAlbedoInfos.y;
-#endif
+        surfaceAlbedo.rgb *= vAlbedoInfos.y;
+    #endif
 
-#ifdef VERTEXCOLOR
-    baseColor.rgb *= vColor.rgb;
-#endif
+    #ifdef VERTEXCOLOR
+        surfaceAlbedo.rgb *= vColor.rgb;
+    #endif
 
-#ifdef OVERLOADEDVALUES
-    baseColor.rgb = mix(baseColor.rgb, vOverloadedAlbedo, vOverloadedIntensity.y);
-    albedoColor.rgb = mix(albedoColor.rgb, vOverloadedAlbedo, vOverloadedIntensity.y);
-#endif
+    #ifdef OVERLOADEDVALUES
+        surfaceAlbedo.rgb = mix(surfaceAlbedo.rgb, vOverloadedAlbedo, vOverloadedIntensity.y);
+    #endif
 
     // Bump
-#ifdef NORMAL
-    vec3 normalW = normalize(vNormalW);
-#else
-    vec3 normalW = vec3(1.0, 1.0, 1.0);
-#endif
+    #ifdef NORMAL
+        vec3 normalW = normalize(vNormalW);
+    #else
+        vec3 normalW = vec3(1.0, 1.0, 1.0);
+    #endif
 
 
-#ifdef BUMP
-    normalW = perturbNormal(viewDirectionW);
-#endif
+    #ifdef BUMP
+        normalW = perturbNormal(viewDirectionW);
+    #endif
 
     // Ambient color
-    vec3 baseAmbientColor = vec3(1., 1., 1.);
+    vec3 ambientColor = vec3(1., 1., 1.);
 
-#ifdef AMBIENT
-    baseAmbientColor = texture2D(ambientSampler, vAmbientUV).rgb * vAmbientInfos.y;
-    
-    #ifdef OVERLOADEDVALUES
-        baseAmbientColor.rgb = mix(baseAmbientColor.rgb, vOverloadedAmbient, vOverloadedIntensity.x);
+    #ifdef AMBIENT
+        ambientColor = texture2D(ambientSampler, vAmbientUV).rgb * vAmbientInfos.y;
+        
+        #ifdef OVERLOADEDVALUES
+            ambientColor.rgb = mix(ambientColor.rgb, vOverloadedAmbient, vOverloadedIntensity.x);
+        #endif
     #endif
-#endif
 
     // Specular map
     float microSurface = vReflectivityColor.a;
-    vec3 reflectivityColor = vReflectivityColor.rgb;
+    vec3 surfaceReflectivityColor = vReflectivityColor.rgb;
     
     #ifdef OVERLOADEDVALUES
-        reflectivityColor.rgb = mix(reflectivityColor.rgb, vOverloadedReflectivity, vOverloadedIntensity.z);
+        surfaceReflectivityColor.rgb = mix(surfaceReflectivityColor.rgb, vOverloadedReflectivity, vOverloadedIntensity.z);
     #endif
 
     #ifdef REFLECTIVITY
-        vec4 reflectivityMapColor = texture2D(reflectivitySampler, vReflectivityUV);
-        reflectivityColor = toLinearSpace(reflectivityMapColor.rgb);
+        surfaceReflectivityColor = texture2D(reflectivitySampler, vReflectivityUV).rgb;
+        surfaceReflectivityColor = toLinearSpace(surfaceReflectivityColor);
 
         #ifdef OVERLOADEDVALUES
-                reflectivityColor.rgb = mix(reflectivityColor.rgb, vOverloadedReflectivity, vOverloadedIntensity.z);
+                surfaceReflectivityColor = mix(surfaceReflectivityColor, vOverloadedReflectivity, vOverloadedIntensity.z);
         #endif
 
         #ifdef MICROSURFACEFROMREFLECTIVITYMAP
             microSurface = reflectivityMapColor.a;
         #else
-            microSurface = computeDefaultMicroSurface(microSurface, reflectivityColor);
+            microSurface = computeDefaultMicroSurface(microSurface, surfaceReflectivityColor);
         #endif
     #endif
 
@@ -882,8 +973,8 @@ void main(void) {
     #endif
 
     // Apply Energy Conservation taking in account the environment level only if the environment is present.
-    float reflectance = max(max(reflectivityColor.r, reflectivityColor.g), reflectivityColor.b);
-    baseColor.rgb = (1. - reflectance) * baseColor.rgb;
+    float reflectance = max(max(surfaceReflectivityColor.r, surfaceReflectivityColor.g), surfaceReflectivityColor.b);
+    surfaceAlbedo.rgb = (1. - reflectance) * surfaceAlbedo.rgb;
 
     // Compute Specular Fresnel + Reflectance.
     float NdotV = max(0.00000000001, dot(normalW, viewDirectionW));
@@ -895,16 +986,16 @@ void main(void) {
     float rough = clamp(1. - microSurface, 0.000001, 1.0);
 
     // Lighting
-    vec3 diffuseBase = vec3(0., 0., 0.);
+    vec3 lightDiffuseContribution = vec3(0., 0., 0.);
     
 #ifdef OVERLOADEDSHADOWVALUES
-    vec3 shadowedOnlyDiffuseBase = vec3(1., 1., 1.);
+    vec3 shadowedOnlyLightDiffuseContribution = vec3(1., 1., 1.);
 #endif
 
 #ifdef SPECULARTERM
-    vec3 specularBase = vec3(0., 0., 0.);
+    vec3 lightSpecularContribution= vec3(0., 0., 0.);
 #endif
-    float shadow = 1.;
+    float notShadowLevel = 1.; // 1 - shadowLevel
 
 #ifdef LIGHT0
 #ifndef SPECULARTERM
@@ -921,32 +1012,32 @@ void main(void) {
 #endif
 #ifdef SHADOW0
 #ifdef SHADOWVSM0
-    shadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x);
+    notShadowLevel = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x);
 #else
 #ifdef SHADOWPCF0
 #if defined(POINTLIGHT0)
-    shadow = computeShadowWithPCFCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);
+    notShadowLevel = computeShadowWithPCFCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);
 #else
-    shadow = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);
+    notShadowLevel = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);
 #endif
 #else
 #if defined(POINTLIGHT0)
-    shadow = computeShadowCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
+    notShadowLevel = computeShadowCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
 #else
-    shadow = computeShadow(vPositionFromLight0, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
+    notShadowLevel = computeShadow(vPositionFromLight0, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
 #endif
 #endif
 #endif
 #else
-    shadow = 1.;
+    notShadowLevel = 1.;
 #endif
-    diffuseBase += info.diffuse * shadow;
+    lightDiffuseContribution += info.diffuse * notShadowLevel;
 #ifdef OVERLOADEDSHADOWVALUES
-    shadowedOnlyDiffuseBase *= shadow;
+    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
 #endif
 
 #ifdef SPECULARTERM
-    specularBase += info.specular * shadow;
+    lightSpecularContribution += info.specular * notShadowLevel;
 #endif
 #endif
 
@@ -965,33 +1056,33 @@ void main(void) {
 #endif
 #ifdef SHADOW1
 #ifdef SHADOWVSM1
-    shadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x);
+    notShadowLevel = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x);
 #else
 #ifdef SHADOWPCF1
 #if defined(POINTLIGHT1)
-    shadow = computeShadowWithPCFCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);
+    notShadowLevel = computeShadowWithPCFCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);
 #else
-    shadow = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);
+    notShadowLevel = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);
 #endif
 #else
 #if defined(POINTLIGHT1)
-    shadow = computeShadowCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
+    notShadowLevel = computeShadowCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
 #else
-    shadow = computeShadow(vPositionFromLight1, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
+    notShadowLevel = computeShadow(vPositionFromLight1, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
 #endif
 #endif
 #endif
 #else
-    shadow = 1.;
+    notShadowLevel = 1.;
 #endif
 
-    diffuseBase += info.diffuse * shadow;
+    lightDiffuseContribution += info.diffuse * notShadowLevel;
 #ifdef OVERLOADEDSHADOWVALUES
-    shadowedOnlyDiffuseBase *= shadow;
+    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
 #endif
 
 #ifdef SPECULARTERM
-    specularBase += info.specular * shadow;
+    lightSpecularContribution += info.specular * notShadowLevel;
 #endif
 #endif
 
@@ -1010,33 +1101,33 @@ void main(void) {
 #endif
 #ifdef SHADOW2
 #ifdef SHADOWVSM2
-    shadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x);
+    notShadowLevel = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x);
 #else
 #ifdef SHADOWPCF2
 #if defined(POINTLIGHT2)
-    shadow = computeShadowWithPCFCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);
+    notShadowLevel = computeShadowWithPCFCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);
 #else
-    shadow = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);
+    notShadowLevel = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);
 #endif
 #else
 #if defined(POINTLIGHT2)
-    shadow = computeShadowCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
+    notShadowLevel = computeShadowCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
 #else
-    shadow = computeShadow(vPositionFromLight2, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
+    notShadowLevel = computeShadow(vPositionFromLight2, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
 #endif
 #endif	
 #endif	
 #else
-    shadow = 1.;
+    notShadowLevel = 1.;
 #endif
 
-    diffuseBase += info.diffuse * shadow;
+    lightDiffuseContribution += info.diffuse * notShadowLevel;
 #ifdef OVERLOADEDSHADOWVALUES
-    shadowedOnlyDiffuseBase *= shadow;
+    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
 #endif
 
 #ifdef SPECULARTERM
-    specularBase += info.specular * shadow;
+    lightSpecularContribution += info.specular * notShadowLevel;
 #endif
 #endif
 
@@ -1055,39 +1146,43 @@ void main(void) {
 #endif
 #ifdef SHADOW3
 #ifdef SHADOWVSM3
-    shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);
+    notShadowLevel = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);
 #else
 #ifdef SHADOWPCF3
 #if defined(POINTLIGHT3)
-    shadow = computeShadowWithPCFCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
+    notShadowLevel = computeShadowWithPCFCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
 #else
-    shadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
+    notShadowLevel = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
 #endif
 #else
 #if defined(POINTLIGHT3)
-    shadow = computeShadowCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
+    notShadowLevel = computeShadowCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
 #else
-    shadow = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
+    notShadowLevel = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
 #endif
 #endif	
 #endif	
 #else
-    shadow = 1.;
+    notShadowLevel = 1.;
 #endif
 
-    diffuseBase += info.diffuse * shadow;
+    lightDiffuseContribution += info.diffuse * notShadowLevel;
 #ifdef OVERLOADEDSHADOWVALUES
-    shadowedOnlyDiffuseBase *= shadow;
+    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
 #endif
 
 #ifdef SPECULARTERM
-    specularBase += info.specular * shadow;
+    lightSpecularContribution += info.specular * notShadowLevel;
+#endif
 #endif
+
+#ifdef SPECULARTERM
+    lightSpecularContribution *= vLightingIntensity.w;
 #endif
 
 // Reflection
-vec3 reflectionColor = vReflectionColor.rgb;
-vec3 ambientReflectionColor = vReflectionColor.rgb;
+vec3 environmentRadiance = vReflectionColor.rgb;
+vec3 environmentIrradiance = vReflectionColor.rgb;
 
 #ifdef REFLECTION
     vec3 vReflectionUVW = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
@@ -1096,11 +1191,23 @@ vec3 ambientReflectionColor = vReflectionColor.rgb;
         // Go mat -> blurry reflexion according to microSurface
         float bias = 20. * (1.0 - microSurface);
 
-        reflectionColor = textureCube(reflectionCubeSampler, vReflectionUVW, bias).rgb * vReflectionInfos.x;
-        reflectionColor = toLinearSpace(reflectionColor.rgb);
+        environmentRadiance = textureCube(reflectionCubeSampler, vReflectionUVW, bias).rgb * vReflectionInfos.x;
+        
+        #ifdef PoissonSamplingEnvironment
+            float alphaG = convertRoughnessToAverageSlope(rough);
+            environmentRadiance = environmentSampler(reflectionCubeSampler, vReflectionUVW, alphaG) * vReflectionInfos.x;
+        #endif
 
-        ambientReflectionColor = textureCube(reflectionCubeSampler, normalW, 20.).rgb * vReflectionInfos.x;
-        ambientReflectionColor = toLinearSpace(ambientReflectionColor.rgb);
+        #ifdef USESPHERICALFROMREFLECTIONMAP
+            vec3 normalEnvironmentSpace = (reflectionMatrix * vec4(normalW, 1)).xyz;
+            environmentIrradiance = EnvironmentIrradiance(normalEnvironmentSpace);
+        #else
+            environmentRadiance = toLinearSpace(environmentRadiance.rgb);
+            
+            environmentIrradiance = textureCube(reflectionCubeSampler, normalW, 20.).rgb * vReflectionInfos.x;
+            environmentIrradiance = toLinearSpace(environmentIrradiance.rgb);
+            environmentIrradiance *= 0.2; // Hack in case of no hdr cube map use for environment.
+        #endif
     #else
         vec2 coords = vReflectionUVW.xy;
 
@@ -1110,27 +1217,27 @@ vec3 ambientReflectionColor = vReflectionColor.rgb;
 
         coords.y = 1.0 - coords.y;
 
-        reflectionColor = texture2D(reflection2DSampler, coords).rgb * vReflectionInfos.x;
-        reflectionColor = toLinearSpace(reflectionColor.rgb);
+        environmentRadiance = texture2D(reflection2DSampler, coords).rgb * vReflectionInfos.x;
+        environmentRadiance = toLinearSpace(environmentRadiance.rgb);
 
-        ambientReflectionColor = texture2D(reflection2DSampler, coords, 20.).rgb * vReflectionInfos.x;
-        ambientReflectionColor = toLinearSpace(ambientReflectionColor.rgb);
+        environmentIrradiance = texture2D(reflection2DSampler, coords, 20.).rgb * vReflectionInfos.x;
+        environmentIrradiance = toLinearSpace(environmentIrradiance.rgb);
     #endif
 #endif
 
 #ifdef OVERLOADEDVALUES
-    ambientReflectionColor = mix(ambientReflectionColor, vOverloadedReflection, vOverloadedMicroSurface.z);
-    reflectionColor = mix(reflectionColor, vOverloadedReflection, vOverloadedMicroSurface.z);
+    environmentIrradiance = mix(environmentIrradiance, vOverloadedReflection, vOverloadedMicroSurface.z);
+    environmentRadiance = mix(environmentRadiance, vOverloadedReflection, vOverloadedMicroSurface.z);
 #endif
 
-reflectionColor *= vLightingIntensity.z;
-ambientReflectionColor *= vLightingIntensity.z;
+environmentRadiance *= vLightingIntensity.z;
+environmentIrradiance *= vLightingIntensity.z;
 
 // Compute reflection specular fresnel
-vec3 specularEnvironmentR0 = reflectivityColor.rgb;
+vec3 specularEnvironmentR0 = surfaceReflectivityColor.rgb;
 vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0);
-vec3 specularEnvironmentReflectanceViewer = FresnelSchlickEnvironmentGGX(clamp(NdotV, 0., 1.), specularEnvironmentR0, specularEnvironmentR90, sqrt(microSurface));
-reflectionColor *= specularEnvironmentReflectanceViewer;
+vec3 specularEnvironmentReflectance = FresnelSchlickEnvironmentGGX(clamp(NdotV, 0., 1.), specularEnvironmentR0, specularEnvironmentR90, sqrt(microSurface));
+environmentRadiance *= specularEnvironmentReflectance;
 
 #ifdef OPACITY
     vec4 opacityMap = texture2D(opacitySampler, vOpacityUV);
@@ -1155,55 +1262,51 @@ reflectionColor *= specularEnvironmentReflectanceViewer;
 #endif
 
     // Emissive
-    vec3 emissiveColor = vEmissiveColor;
+    vec3 surfaceEmissiveColor = vEmissiveColor;
 #ifdef EMISSIVE
     vec3 emissiveColorTex = texture2D(emissiveSampler, vEmissiveUV).rgb;
-    emissiveColor = toLinearSpace(emissiveColorTex.rgb) * emissiveColor * vEmissiveInfos.y;
+    surfaceEmissiveColor = toLinearSpace(emissiveColorTex.rgb) * surfaceEmissiveColor * vEmissiveInfos.y;
 #endif
 
 #ifdef OVERLOADEDVALUES
-    emissiveColor = mix(emissiveColor, vOverloadedEmissive, vOverloadedIntensity.w);
+    surfaceEmissiveColor = mix(surfaceEmissiveColor, vOverloadedEmissive, vOverloadedIntensity.w);
 #endif
 
 #ifdef EMISSIVEFRESNEL
     float emissiveFresnelTerm = computeFresnelTerm(viewDirectionW, normalW, emissiveRightColor.a, emissiveLeftColor.a);
 
-    emissiveColor *= emissiveLeftColor.rgb * (1.0 - emissiveFresnelTerm) + emissiveFresnelTerm * emissiveRightColor.rgb;
+    surfaceEmissiveColor *= emissiveLeftColor.rgb * (1.0 - emissiveFresnelTerm) + emissiveFresnelTerm * emissiveRightColor.rgb;
 #endif
 
-    // Composition
+// Composition
 #ifdef EMISSIVEASILLUMINATION
-    vec3 finalDiffuse = max(diffuseBase * albedoColor + vAmbientColor, 0.0) * baseColor.rgb;
+    vec3 finalDiffuse = max(lightDiffuseContribution * surfaceAlbedoContribution + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
     
     #ifdef OVERLOADEDSHADOWVALUES
-        shadowedOnlyDiffuseBase = max(shadowedOnlyDiffuseBase * albedoColor + vAmbientColor, 0.0) * baseColor.rgb;
+        shadowedOnlyLightDiffuseContribution = max(shadowedOnlyLightDiffuseContribution * surfaceAlbedoContribution + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
     #endif
 #else
     #ifdef LINKEMISSIVEWITHALBEDO
-        vec3 finalDiffuse = max((diffuseBase + emissiveColor) * albedoColor + vAmbientColor, 0.0) * baseColor.rgb;
+        vec3 finalDiffuse = max((lightDiffuseContribution + surfaceEmissiveColor) * surfaceAlbedoContribution + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
 
         #ifdef OVERLOADEDSHADOWVALUES
-            shadowedOnlyDiffuseBase = max((shadowedOnlyDiffuseBase + emissiveColor) * albedoColor + vAmbientColor, 0.0) * baseColor.rgb;
+            shadowedOnlyLightDiffuseContribution = max((shadowedOnlyLightDiffuseContribution + surfaceEmissiveColor) * surfaceAlbedoContribution + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
         #endif
     #else
-        vec3 finalDiffuse = max(diffuseBase * albedoColor + emissiveColor + vAmbientColor, 0.0) * baseColor.rgb;
+        vec3 finalDiffuse = max(lightDiffuseContribution * surfaceAlbedoContribution + surfaceEmissiveColor + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
 
         #ifdef OVERLOADEDSHADOWVALUES
-            shadowedOnlyDiffuseBase = max(shadowedOnlyDiffuseBase * albedoColor + emissiveColor + vAmbientColor, 0.0) * baseColor.rgb;
+            shadowedOnlyLightDiffuseContribution = max(shadowedOnlyLightDiffuseContribution * surfaceAlbedoContribution + surfaceEmissiveColor + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
         #endif
     #endif
 #endif
 
 #ifdef OVERLOADEDSHADOWVALUES
-    finalDiffuse = mix(finalDiffuse, shadowedOnlyDiffuseBase, (1.0 - vOverloadedShadowIntensity.y));
+    finalDiffuse = mix(finalDiffuse, shadowedOnlyLightDiffuseContribution, (1.0 - vOverloadedShadowIntensity.y));
 #endif
 
-// diffuse lighting from environment 0.2 replaces Harmonic...
-// Ambient Reflection already includes the environment intensity.
-finalDiffuse += baseColor.rgb * ambientReflectionColor * 0.2;
-
 #ifdef SPECULARTERM
-    vec3 finalSpecular = specularBase * reflectivityColor * vLightingIntensity.w;
+    vec3 finalSpecular = lightSpecularContribution * surfaceReflectivityColor;
 #else
     vec3 finalSpecular = vec3(0.0);
 #endif
@@ -1219,36 +1322,36 @@ finalDiffuse += baseColor.rgb * ambientReflectionColor * 0.2;
 // Composition
 // Reflection already includes the environment intensity.
 #ifdef EMISSIVEASILLUMINATION
-    vec4 color = vec4(finalDiffuse * baseAmbientColor * vLightingIntensity.x + finalSpecular * vLightingIntensity.x + reflectionColor + emissiveColor * vLightingIntensity.y, alpha);
+    vec4 finalColor = vec4(finalDiffuse * ambientColor * vLightingIntensity.x + surfaceAlbedo.rgb * environmentIrradiance + finalSpecular * vLightingIntensity.x + environmentRadiance + surfaceEmissiveColor * vLightingIntensity.y, alpha);
 #else
-    vec4 color = vec4(finalDiffuse * baseAmbientColor * vLightingIntensity.x + finalSpecular * vLightingIntensity.x + reflectionColor, alpha);
+    vec4 finalColor = vec4(finalDiffuse * ambientColor * vLightingIntensity.x + surfaceAlbedo.rgb * environmentIrradiance + finalSpecular * vLightingIntensity.x + environmentRadiance, alpha);
 #endif
 
 #ifdef LIGHTMAP
     vec3 lightmapColor = texture2D(lightmapSampler, vLightmapUV).rgb * vLightmapInfos.y;
 
     #ifdef USELIGHTMAPASSHADOWMAP
-        color.rgb *= lightmapColor;
+        finalColor.rgb *= lightmapColor;
     #else
-        color.rgb += lightmapColor;
+        finalColor.rgb += lightmapColor;
     #endif
 #endif
 
 #ifdef FOG
     float fog = CalcFogFactor();
-    color.rgb = fog * color.rgb + (1.0 - fog) * vFogColor;
+    finalColor.rgb = fog * finalColor.rgb + (1.0 - fog) * vFogColor;
 #endif
 
-    color = max(color, 0.0);
+    finalColor = max(finalColor, 0.0);
 
 #ifdef CAMERATONEMAP
-    color.rgb = toneMaps(color.rgb);
+    finalColor.rgb = toneMaps(finalColor.rgb);
 #endif
 
-    color.rgb = toGammaSpace(color.rgb);
+    finalColor.rgb = toGammaSpace(finalColor.rgb);
 
 #ifdef CAMERACONTRAST
-    color = contrasts(color);
+    finalColor = contrasts(finalColor);
 #endif
 
     // Normal Display.
@@ -1261,10 +1364,10 @@ finalDiffuse += baseColor.rgb * ambientReflectionColor * 0.2;
     // gl_FragColor = vec4(reflectionColor, 1.0);
 
     // Base color.
-    // gl_FragColor = vec4(baseColor.rgb, 1.0);
+    // gl_FragColor = vec4(surfaceAlbedo.rgb, 1.0);
 
     // Specular color.
-    // gl_FragColor = vec4(reflectivityColor.rgb, 1.0);
+    // gl_FragColor = vec4(surfaceReflectivityColor.rgb, 1.0);
 
     // MicroSurface color.
     // gl_FragColor = vec4(microSurface, microSurface, microSurface, 1.0);
@@ -1276,5 +1379,5 @@ finalDiffuse += baseColor.rgb * ambientReflectionColor * 0.2;
     //vec2 test = vEmissiveUV * 0.5 + 0.5;
     //gl_FragColor = vec4(test.x, test.y, 1.0, 1.0);
 
-    gl_FragColor = color;
+    gl_FragColor = finalColor;
 }

+ 6 - 0
materialsLibrary/materials/pbr/tsconfig.json

@@ -0,0 +1,6 @@
+{
+    "compilerOptions": {
+        "module": "commonjs", 
+        "target": "es5"
+    }
+}

+ 45 - 22
materialsLibrary/test/add/addpbr.js

@@ -1,12 +1,29 @@
 window.preparePBR = function() {
 	var pbr = new BABYLON.PBRMaterial("pbr", scene);
+
 	pbr.albedoTexture = new BABYLON.Texture("textures/amiga.jpg", scene);
 	pbr.albedoTexture.uScale = 5;
 	pbr.albedoTexture.vScale = 5;
-	pbr.reflectionTexture = new BABYLON.CubeTexture("textures/skybox/TropicalSunnyDay", scene);	
+    
+    var hdrTexture = new BABYLON.HDRCubeTexture("textures/hdr/environment.hdr", scene, 512);
+    pbr.reflectionTexture = hdrTexture;
 	pbr.reflectivityColor = new BABYLON.Color3(0.3, 0.3, 0.3);
+    
 	pbr.microSurface = 0.9;
-	
+    
+    // Skybox
+    var hdrSkybox = BABYLON.Mesh.CreateBox("hdrSkyBox", 1000.0, scene);
+    var hdrSkyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
+    hdrSkyboxMaterial.backFaceCulling = false;
+    hdrSkyboxMaterial.reflectionTexture = hdrTexture.clone();
+    hdrSkyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
+    hdrSkyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
+    hdrSkyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
+    hdrSkyboxMaterial.disableLighting = true;
+    hdrSkybox.material = hdrSkyboxMaterial;
+    hdrSkybox.infiniteDistance = true;
+    hdrSkybox.setEnabled(false);
+    
 	registerButtonUI("pbr", "Default", function() {
 		setRangeValues({
 		  "directIntensity": 1,
@@ -27,6 +44,28 @@ window.preparePBR = function() {
 		  "albedoColorLevel": 0
 		});
 	});
+    registerButtonUI("pbr", "Env Irradiance No Lighting", function() {
+		setRangeValues({
+		  "directIntensity": 0,
+		  "emissiveIntensity": 1,
+		  "environmentIntensity": 1,
+		  "specularIntensity": 1,
+		  "ShadowIntensity": 1,
+		  "ShadeIntensity": 1,
+		  "cameraExposure": 1,
+		  "cameraContrast": 1,
+		  "microSurface": 0,
+		  "reflectivityColorR": 0,
+		  "reflectivityColorG": 0,
+		  "reflectivityColorB": 0,
+		  "albedoColorR": 1,
+		  "albedoColorG": 1,
+		  "albedoColorB": 1,
+		  "albedoColorLevel": 1
+		});
+        
+        hdrSkybox.setEnabled(true);
+	});
 	registerButtonUI("pbr", "Rough Gold", function() {
 		setRangeValues({
 		  "directIntensity": 1.3439461727881254,
@@ -67,26 +106,6 @@ window.preparePBR = function() {
 		  "albedoColorLevel": 1
 		});
 	});
-	registerButtonUI("pbr", "Shiny Copper", function() {
-		setRangeValues({
-		  "directIntensity": 1.2355634169181153,
-		  "emissiveIntensity": 0.910415149308085,
-		  "environmentIntensity": 0.21676551174002023,
-		  "specularIntensity": 1,
-		  "ShadowIntensity": 1.018797905178095,
-		  "ShadeIntensity": 0.975444802830091,
-		  "cameraExposure": 1.0621510075260991,
-		  "cameraContrast": 1.0404744563520971,
-		  "microSurface": 0.888738598134083,
-		  "reflectivityColorR": 0.98,
-		  "reflectivityColorG": 0.78,
-		  "reflectivityColorB": 0.706,
-		  "albedoColorR": 0.1,
-		  "albedoColorG": 0.1,
-		  "albedoColorB": 0.1,
-		  "albedoColorLevel": 1
-		});
-	});
 
 	registerRangeUI("pbr", "directIntensity", 0, 2, function(value) {
 		pbr.directIntensity = value;
@@ -183,6 +202,10 @@ window.preparePBR = function() {
 	}, function() {
 		return pbr.overloadedAlbedoIntensity;
 	});
+    
+    registerButtonUI("pbr", "Toggle Skybox", function() {
+        hdrSkybox.setEnabled(!hdrSkybox.isEnabled());
+	});
 
 	return pbr;
 }

文件差異過大導致無法顯示
+ 12097 - 10665
materialsLibrary/test/refs/babylon.max.js


二進制
materialsLibrary/test/textures/hdr/environment.hdr


+ 77 - 0
src/babylon.engine.js

@@ -387,6 +387,82 @@ var BABYLON;
             this._activeTexturesCache = new Array(this._maxTextureChannels);
             this._compiledEffects = {};
             this._uintIndicesCurrentlySet = false;
+            this.createRawCubeTexture = function (url, scene, size, format, type, noMipmap, callback) {
+                var _this = this;
+                var gl = this._gl;
+                var texture = gl.createTexture();
+                scene._addPendingData(texture);
+                texture.isCube = true;
+                texture.references = 1;
+                texture.url = url;
+                var internalFormat = gl.RGBA;
+                switch (format) {
+                    case Engine.TEXTUREFORMAT_ALPHA:
+                        internalFormat = gl.ALPHA;
+                        break;
+                    case Engine.TEXTUREFORMAT_LUMINANCE:
+                        internalFormat = gl.LUMINANCE;
+                        break;
+                    case Engine.TEXTUREFORMAT_LUMINANCE_ALPHA:
+                        internalFormat = gl.LUMINANCE_ALPHA;
+                        break;
+                    case Engine.TEXTUREFORMAT_RGB:
+                        internalFormat = gl.RGB;
+                        break;
+                    case Engine.TEXTUREFORMAT_RGBA:
+                        internalFormat = gl.RGBA;
+                        break;
+                }
+                var textureType = gl.UNSIGNED_BYTE;
+                if (type === Engine.TEXTURETYPE_FLOAT) {
+                    textureType = gl.FLOAT;
+                }
+                var width = size;
+                var height = width;
+                var isPot = (BABYLON.Tools.IsExponentOfTwo(width) && BABYLON.Tools.IsExponentOfTwo(height));
+                texture._width = width;
+                texture._height = height;
+                var onerror = function () {
+                    scene._removePendingData(texture);
+                };
+                var internalCallback = function (data) {
+                    var rgbeDataArrays = callback(data);
+                    var facesIndex = [
+                        gl.TEXTURE_CUBE_MAP_POSITIVE_X, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+                        gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
+                    ];
+                    gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
+                    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
+                    for (var index = 0; index < facesIndex.length; index++) {
+                        var faceData = rgbeDataArrays[index];
+                        gl.texImage2D(facesIndex[index], 0, internalFormat, width, height, 0, internalFormat, textureType, faceData);
+                    }
+                    if (!noMipmap && isPot) {
+                        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+                    }
+                    else {
+                        noMipmap = true;
+                    }
+                    if (textureType == gl.FLOAT && !_this._caps.textureFloatLinearFiltering) {
+                        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+                        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+                    }
+                    else {
+                        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+                        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, noMipmap ? gl.LINEAR : gl.LINEAR_MIPMAP_LINEAR);
+                    }
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+                    gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+                    texture.isReady = true;
+                    _this.resetTextureCache();
+                    scene._removePendingData(texture);
+                };
+                BABYLON.Tools.LoadFile(url, function (data) {
+                    internalCallback(data);
+                }, onerror, scene.database, true);
+                return texture;
+            };
             this._renderingCanvas = canvas;
             options = options || {};
             options.antialias = antialias;
@@ -454,6 +530,7 @@ var BABYLON;
             this._caps.fragmentDepthSupported = this._gl.getExtension('EXT_frag_depth') !== null;
             this._caps.highPrecisionShaderSupported = true;
             this._caps.drawBuffersExtension = this._gl.getExtension('WEBGL_draw_buffers');
+            this._caps.textureFloatLinearFiltering = this._gl.getExtension('OES_texture_float_linear');
             if (this._gl.getShaderPrecisionFormat) {
                 var highp = this._gl.getShaderPrecisionFormat(this._gl.FRAGMENT_SHADER, this._gl.HIGH_FLOAT);
                 this._caps.highPrecisionShaderSupported = highp.precision !== 0;

+ 98 - 4
src/babylon.engine.ts

@@ -386,6 +386,7 @@
         public uintIndices: boolean;
         public highPrecisionShaderSupported: boolean;
         public fragmentDepthSupported: boolean;
+        public textureFloatLinearFiltering: boolean;
         public drawBuffersExtension;
     }
 
@@ -597,10 +598,10 @@
 
             if (!this._gl) {
                 try {
-                    this._gl = <WebGLRenderingContext>(canvas.getContext("webgl", options) || canvas.getContext("experimental-webgl", options));
-                } catch (e) {
-                    throw new Error("WebGL not supported");
-                }
+                this._gl = <WebGLRenderingContext>(canvas.getContext("webgl", options) || canvas.getContext("experimental-webgl", options));
+            } catch (e) {
+                throw new Error("WebGL not supported");
+            }
             }
 
             if (!this._gl) {
@@ -657,6 +658,7 @@
             this._caps.fragmentDepthSupported = this._gl.getExtension('EXT_frag_depth') !== null;
             this._caps.highPrecisionShaderSupported = true;
             this._caps.drawBuffersExtension = this._gl.getExtension('WEBGL_draw_buffers');
+            this._caps.textureFloatLinearFiltering = this._gl.getExtension('OES_texture_float_linear');
 
             if (this._gl.getShaderPrecisionFormat) {
                 var highp = this._gl.getShaderPrecisionFormat(this._gl.FRAGMENT_SHADER, this._gl.HIGH_FLOAT);
@@ -2149,6 +2151,98 @@
             return texture;
         }
 
+        public createRawCubeTexture = function (url: string, scene: Scene, size:number, format:number, type: number, noMipmap:boolean, callback: (ArrayBuffer) => ArrayBufferView[]): WebGLTexture {
+            var gl = this._gl;
+            var texture = gl.createTexture();
+            scene._addPendingData(texture);
+            texture.isCube = true;
+            texture.references = 1;
+            texture.url = url;
+
+            var internalFormat = gl.RGBA;
+            switch (format) {
+                case Engine.TEXTUREFORMAT_ALPHA:
+                    internalFormat = gl.ALPHA;
+                    break;
+                case Engine.TEXTUREFORMAT_LUMINANCE:
+                    internalFormat = gl.LUMINANCE;
+                    break;
+                case Engine.TEXTUREFORMAT_LUMINANCE_ALPHA:
+                    internalFormat = gl.LUMINANCE_ALPHA;
+                    break;
+                case Engine.TEXTUREFORMAT_RGB:
+                    internalFormat = gl.RGB;
+                    break;
+                case Engine.TEXTUREFORMAT_RGBA:
+                    internalFormat = gl.RGBA;
+                    break;
+            }
+
+            var textureType = gl.UNSIGNED_BYTE;
+            if (type === Engine.TEXTURETYPE_FLOAT) {
+                textureType = gl.FLOAT;
+            }
+            
+            var width = size;
+            var height = width;
+            var isPot = (Tools.IsExponentOfTwo(width) && Tools.IsExponentOfTwo(height));                                                                                                    
+             
+            texture._width = width;
+            texture._height = height;
+             
+            var onerror = () => {
+                scene._removePendingData(texture);
+            };
+            
+            var internalCallback = (data) => {
+                var rgbeDataArrays = callback(data);
+                
+                var facesIndex = [                                                                                                          
+                    gl.TEXTURE_CUBE_MAP_POSITIVE_X, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, gl.TEXTURE_CUBE_MAP_POSITIVE_Z,                    
+                    gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z                     
+                ];                                                                                                                     
+                                                                                                                
+                gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);                                                                          
+                gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);                                                                             
+                                                                                                                
+                for (var index = 0; index < facesIndex.length; index++) {                                                                   
+                    var faceData = rgbeDataArrays[index];                                                                                   
+                    gl.texImage2D(facesIndex[index], 0, internalFormat, width, height, 0, internalFormat, textureType, faceData);                            
+                }                                                                                                                      
+                                                                                                                
+                if (!noMipmap && isPot) {                                                                                                       
+                    gl.generateMipmap(gl.TEXTURE_CUBE_MAP);                                                                            
+                } 
+                else {
+                    noMipmap = true;
+                }                                                                                                                     
+
+                if (textureType == gl.FLOAT && !this._caps.textureFloatLinearFiltering) {
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+                }
+                else {
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, noMipmap ? gl.LINEAR : gl.LINEAR_MIPMAP_LINEAR);          
+                }
+
+                gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);                                          
+                gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);                                          
+                gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+
+                texture.isReady = true;
+
+                this.resetTextureCache();
+                scene._removePendingData(texture); 
+            };
+            
+            Tools.LoadFile(url, data => {
+                    internalCallback(data);
+                }, onerror, scene.database, true);                                                                                                
+                                                                                                            
+            return texture;                                                                                                        
+        };                                                                                                                         
+
         public _releaseTexture(texture: WebGLTexture): void {
             var gl = this._gl;
 

+ 6 - 0
src/tsconfig.json

@@ -0,0 +1,6 @@
+{
+    "compilerOptions": {
+        "module": "commonjs", 
+        "target": "es5"
+    }
+}