瀏覽代碼

Edge Texture Reflection

Sebastien Vandenberghe 8 年之前
父節點
當前提交
ff1b0211c3

+ 8 - 17
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -597,8 +597,7 @@
                         }
 
                         if (reflectionTexture.coordinatesMode !== BABYLON.Texture.SKYBOX_MODE) {
-                            var polynomials = reflectionTexture.getSphericalPolynomial();
-                            if (polynomials) {
+                            if (reflectionTexture.sphericalPolynomial) {
                                 defines.USESPHERICALFROMREFLECTIONMAP = true;
                             }
                         }
@@ -1025,7 +1024,7 @@
                             this._uniformBuffer.updateFloat2("vReflectionInfos", reflectionTexture.level, 0);
 
                             if (defines.USESPHERICALFROMREFLECTIONMAP) {
-                                var polynomials = reflectionTexture.getSphericalPolynomial();
+                                var polynomials = reflectionTexture.sphericalPolynomial;
                                 this._activeEffect.setFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z);
                                 this._activeEffect.setFloat3("vSphericalY", polynomials.y.x, polynomials.y.y, polynomials.y.z);
                                 this._activeEffect.setFloat3("vSphericalZ", polynomials.z.x, polynomials.z.y, polynomials.z.z);
@@ -1144,13 +1143,9 @@
                             this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture);
                         }
                         else {
-                            if (!reflectionTexture._lodTextureMid) {
-                                reflectionTexture._generateFixedLodSamplers();
-                            }
-
-                            this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture._lodTextureMid || reflectionTexture);
-                            this._uniformBuffer.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture);
-                            this._uniformBuffer.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture);
+                            this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture.lodTextureMid || reflectionTexture);
+                            this._uniformBuffer.setTexture("reflectionSamplerLow", reflectionTexture.lodTextureLow || reflectionTexture);
+                            this._uniformBuffer.setTexture("reflectionSamplerHigh", reflectionTexture.lodTextureHigh || reflectionTexture);
                         }
                     }
 
@@ -1163,13 +1158,9 @@
                             this._uniformBuffer.setTexture("refractionSampler", refractionTexture);
                         }
                         else {
-                            if (!refractionTexture._lodTextureMid) {
-                                refractionTexture._generateFixedLodSamplers();
-                            }
-
-                            this._uniformBuffer.setTexture("refractionSampler", refractionTexture._lodTextureMid || refractionTexture);
-                            this._uniformBuffer.setTexture("refractionSamplerLow", refractionTexture._lodTextureLow || refractionTexture);
-                            this._uniformBuffer.setTexture("refractionSamplerHigh", refractionTexture._lodTextureHigh || refractionTexture);
+                            this._uniformBuffer.setTexture("refractionSampler", refractionTexture.lodTextureMid || refractionTexture);
+                            this._uniformBuffer.setTexture("refractionSamplerLow", refractionTexture.lodTextureLow || refractionTexture);
+                            this._uniformBuffer.setTexture("refractionSamplerHigh", refractionTexture.lodTextureHigh || refractionTexture);
                         }
                     }
 

+ 19 - 51
src/Materials/Textures/babylon.baseTexture.ts

@@ -105,12 +105,6 @@
         public _texture: WebGLTexture;
         private _uid: string;
 
-        // The following three fields helps sharing generated fixed LODs for texture filtering
-        // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
-        public _lodTextureHigh: BaseTexture = null;
-        public _lodTextureMid: BaseTexture = null;
-        public _lodTextureLow: BaseTexture = null;
-
         public get isBlocking(): boolean {
             return true;
         }
@@ -235,7 +229,7 @@
             return (this._texture.format !== undefined) ? this._texture.format : Engine.TEXTUREFORMAT_RGBA;
         }
 
-        public readPixels(faceIndex = 0, lodIndex = 0): ArrayBufferView {
+        public readPixels(faceIndex = 0): ArrayBufferView {
             if (!this._texture) {
                 return null;
             }
@@ -244,10 +238,10 @@
             var engine = this.getScene().getEngine();
 
             if (this._texture.isCube) {
-                return engine._readTexturePixels(this._texture, size.width, size.height, faceIndex, lodIndex);
+                return engine._readTexturePixels(this._texture, size.width, size.height, faceIndex);
             }
 
-            return engine._readTexturePixels(this._texture, size.width, size.height, -1, lodIndex);
+            return engine._readTexturePixels(this._texture, size.width, size.height, -1);
         }
 
         public releaseInternalTexture(): void {
@@ -257,7 +251,7 @@
             }
         }
 
-        public getSphericalPolynomial(): SphericalPolynomial {
+        public get sphericalPolynomial(): SphericalPolynomial {
             if (!this._texture || !Internals.CubeMapToSphericalPolynomialTools || !this.isReady()) {
                 return null;
             }
@@ -270,60 +264,34 @@
             return this._texture._sphericalPolynomial;
         }
 
-        public setSphericalPolynomial(value: SphericalPolynomial) {
+        public set sphericalPolynomial(value: SphericalPolynomial) {
             if (this._texture) {
                 this._texture._sphericalPolynomial = value;
             }
         }
 
-        public _generateFixedLodSamplers(): void {
-            // Only Cube Texture Supports so far as this is dedicated to PBR reflection
-            // and refraction. This should be open in case of user request.
-            if (!this.isCube) {
-                return;
+        public get lodTextureHigh(): BaseTexture {
+            if (this._texture) {
+                return this._texture._lodTextureHigh;
             }
+            return null;
+        }
 
-            const mipSlices = 3;
-            const width = this.getSize().width;
-            if (!width) {
-                return;
+        public get lodTextureMid(): BaseTexture {
+            if (this._texture) {
+                return this._texture._lodTextureMid;
             }
+            return null;
+        }
 
-            const textures: BaseTexture[] = [];
-            const engine = this._scene.getEngine();
-            for (let i = 0; i < mipSlices; i++) {
-                //compute LOD from even spacing in smoothness (matching PBR shader calculation)
-                let smoothness = i / (mipSlices - 1);
-                let roughness = 1 - smoothness;
-                const kMinimumVariance = 0.0005;
-                let alphaG = roughness * roughness + kMinimumVariance;
-                let microsurfaceAverageSlopeTexels = alphaG * width;
-
-                let environmentSpecularLOD = this.lodGenerationScale * (MathTools.Log2(microsurfaceAverageSlopeTexels)) + this.lodGenerationOffset;
-
-                let maxLODIndex = MathTools.Log2(width);
-                let mipmapIndex = Math.min(Math.max(Math.round(environmentSpecularLOD), 0), maxLODIndex);
-
-                textures[i] = engine._createCubeTextureFromLOD(this, this.name + i, mipmapIndex);
+        public get lodTextureLow(): BaseTexture {
+            if (this._texture) {
+                return this._texture._lodTextureLow;
             }
-
-            this._lodTextureHigh = textures[2];
-            this._lodTextureMid = textures[1];
-            this._lodTextureLow = textures[0];
+            return null;
         }
 
         public dispose(): void {
-            // Intergated fixed lod samplers.
-            if (this._lodTextureHigh) {
-                this._lodTextureHigh.dispose();
-            }
-            if (this._lodTextureMid) {
-                this._lodTextureMid.dispose();
-            }
-            if (this._lodTextureLow) {
-                this._lodTextureLow.dispose();
-            }
-
             // Animations
             this.getScene().stopAnimation(this);
 

+ 20 - 4
src/Materials/Textures/babylon.cubeTexture.ts

@@ -8,12 +8,17 @@
         private _extensions: string[];
         private _textureMatrix: Matrix;
         private _format: number;
+        private _prefiletered: boolean;
 
         public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean) {
             return new CubeTexture("", scene, null, noMipmap, files);
         }
 
-        constructor(rootUrl: string, scene: Scene, extensions?: string[], noMipmap?: boolean, files?: string[], onLoad: () => void = null, onError: () => void = null, format: number = Engine.TEXTUREFORMAT_RGBA) {
+        public static CreateFromPrefilteredData(url: string, scene: Scene) {
+            return new CubeTexture(url, scene, null, false, null, null, null, undefined, true);
+        }
+
+        constructor(rootUrl: string, scene: Scene, extensions?: string[], noMipmap?: boolean, files?: string[], onLoad: () => void = null, onError: () => void = null, format: number = Engine.TEXTUREFORMAT_RGBA, prefiltered = false) {
             super(scene);
 
             this.name = rootUrl;
@@ -21,6 +26,7 @@
             this._noMipmap = noMipmap;
             this.hasAlpha = false;
             this._format = format;
+            this._prefiletered = prefiltered;
 
             if (!rootUrl && !files) {
                 return;
@@ -47,7 +53,12 @@
 
             if (!this._texture) {
                 if (!scene.useDelayedTextureLoading) {
-                    this._texture = scene.getEngine().createCubeTexture(rootUrl, scene, files, noMipmap, onLoad, onError, this._format);
+                    if (prefiltered) {
+                        this._texture = scene.getEngine().createPrefilteredCubeTexture(rootUrl, scene, this.lodGenerationScale, this.lodGenerationOffset, onLoad, onError, format);
+                    }
+                    else {
+                        this._texture = scene.getEngine().createCubeTexture(rootUrl, scene, files, noMipmap, onLoad, onError, this._format);
+                    }
                 } else {
                     this.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;
                 }
@@ -74,7 +85,12 @@
             this._texture = this._getFromCache(this.url, this._noMipmap);
 
             if (!this._texture) {
-                this._texture = this.getScene().getEngine().createCubeTexture(this.url, this.getScene(), this._files, this._noMipmap, undefined, undefined, this._format);
+                if (this._prefiletered) {
+                    this._texture = this.getScene().getEngine().createPrefilteredCubeTexture(this.url, this.getScene(), this.lodGenerationScale, this.lodGenerationOffset, undefined, undefined, this._format);
+                }
+                else {
+                    this._texture = this.getScene().getEngine().createCubeTexture(this.url, this.getScene(), this._files, this._noMipmap, undefined, undefined, this._format);
+                }
             }
         }
 
@@ -101,7 +117,7 @@
             }
 
             return texture;
-        }        
+        }
 
         public clone(): CubeTexture {
             return SerializationHelper.Clone(() => {

+ 2 - 2
src/Materials/Textures/babylon.hdrCubeTexture.ts

@@ -166,7 +166,7 @@ module BABYLON {
                 sphericalPolynomial.xy.copyFromFloats(floatArrayView[20], floatArrayView[21], floatArrayView[22]);
                 sphericalPolynomial.yz.copyFromFloats(floatArrayView[23], floatArrayView[24], floatArrayView[25]);
                 sphericalPolynomial.zx.copyFromFloats(floatArrayView[26], floatArrayView[27], floatArrayView[28]);
-                this.setSphericalPolynomial(sphericalPolynomial);
+                this.sphericalPolynomial = sphericalPolynomial;
 
                 // Fill pixel data.
                 mipLevels = intArrayView[29]; // Number of mip levels.
@@ -262,7 +262,7 @@ module BABYLON {
                 // Generate harmonics if needed.
                 if (this._generateHarmonics) {
                     var sphericalPolynomial = BABYLON.Internals.CubeMapToSphericalPolynomialTools.ConvertCubeMapToSphericalPolynomial(data);
-                    this.setSphericalPolynomial(sphericalPolynomial);
+                    this.sphericalPolynomial = sphericalPolynomial;
                 }
 
                 var results = [];

+ 14 - 0
src/Shaders/ShadersInclude/pbrVertexDeclaration.fx

@@ -44,3 +44,17 @@ uniform mat4 bumpMatrix;
 #ifdef POINTSIZE
 uniform float pointSize;
 #endif
+
+// Refraction
+#ifdef REFRACTION
+    uniform vec4 vRefractionInfos;
+    uniform mat4 refractionMatrix;
+    uniform vec3 vRefractionMicrosurfaceInfos;
+#endif
+
+// Reflection
+#ifdef REFLECTION
+    uniform vec2 vReflectionInfos;
+    uniform mat4 reflectionMatrix;
+    uniform vec3 vReflectionMicrosurfaceInfos;
+#endif

+ 43 - 38
src/Tools/babylon.dds.ts

@@ -314,14 +314,14 @@
             return byteArray;
         }
 
-        public static UploadDDSLevels(engine: Engine, arrayBuffer: any, info: DDSInfo, loadMipmaps: boolean, faces: number): void {
+        public static UploadDDSLevels(engine: Engine, arrayBuffer: any, info: DDSInfo, loadMipmaps: boolean, faces: number, lodIndex = -1): void {
             var gl = engine._gl;
             var ext = engine.getCaps().s3tc;
 
             var header = new Int32Array(arrayBuffer, 0, headerLengthInt),
                 fourCC, blockBytes, internalFormat, format,
                 width, height, dataLength, dataOffset,
-                byteArray, mipmapCount, i;
+                byteArray, mipmapCount, mip;
 
             if (header[off_magic] != DDS_MAGIC) {
                 Tools.Error("Invalid magic number in DDS header");
@@ -394,45 +394,50 @@
                 width = header[off_width];
                 height = header[off_height];
 
-                for (i = 0; i < mipmapCount; ++i) {
-                    if (!info.isCompressed && info.isFourCC) {
-                        dataLength = width * height * 4;
-                        var floatArray: ArrayBufferView;
-                        if (bpp === 128) {
-                            floatArray = DDSTools._GetFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
-                        } else if (bpp === 64 && !engine.getCaps().textureHalfFloat) { // Let's fallback to full float
-                            floatArray = DDSTools._GetHalfFloatAsFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
-
-                            info.textureType = Engine.TEXTURETYPE_FLOAT;
-                            format = engine._getWebGLTextureType(info.textureType);    
-                            internalFormat = engine._getRGBABufferInternalSizedFormat(info.textureType);                            
-                        } else { // 64
-                            floatArray = DDSTools._GetHalfFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
-                        }
+                for (mip = 0; mip < mipmapCount; ++mip) {
+                    if (lodIndex === -1 || lodIndex === mip) {
+                        // In case of fixed LOD, if the lod has just been uploaded, early exit.
+                        const i = (lodIndex === -1) ? mip : 0;
 
-                        engine._uploadDataToTexture(sampler, i, internalFormat, width, height, gl.RGBA, format, floatArray);
-                    } else if (info.isRGB) {
-                        if (bpp === 24) {
-                            dataLength = width * height * 3;
-                            byteArray = DDSTools._GetRGBArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer);
-                            engine._uploadDataToTexture(sampler, i, gl.RGB, width, height, gl.RGB, gl.UNSIGNED_BYTE, byteArray);
-                        } else { // 32
+                        if (!info.isCompressed && info.isFourCC) {
                             dataLength = width * height * 4;
-                            byteArray = DDSTools._GetRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer);
-                            engine._uploadDataToTexture(sampler, i, gl.RGBA, width, height, gl.RGBA, gl.UNSIGNED_BYTE, byteArray);
+                            var floatArray: ArrayBufferView;
+                            if (bpp === 128) {
+                                floatArray = DDSTools._GetFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
+                            } else if (bpp === 64 && !engine.getCaps().textureHalfFloat) { // Let's fallback to full float
+                                floatArray = DDSTools._GetHalfFloatAsFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
+
+                                info.textureType = Engine.TEXTURETYPE_FLOAT;
+                                format = engine._getWebGLTextureType(info.textureType);    
+                                internalFormat = engine._getRGBABufferInternalSizedFormat(info.textureType);                            
+                            } else { // 64
+                                floatArray = DDSTools._GetHalfFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
+                            }
+
+                            engine._uploadDataToTexture(sampler, i, internalFormat, width, height, gl.RGBA, format, floatArray);
+                        } else if (info.isRGB) {
+                            if (bpp === 24) {
+                                dataLength = width * height * 3;
+                                byteArray = DDSTools._GetRGBArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer);
+                                engine._uploadDataToTexture(sampler, i, gl.RGB, width, height, gl.RGB, gl.UNSIGNED_BYTE, byteArray);
+                            } else { // 32
+                                dataLength = width * height * 4;
+                                byteArray = DDSTools._GetRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer);
+                                engine._uploadDataToTexture(sampler, i, gl.RGBA, width, height, gl.RGBA, gl.UNSIGNED_BYTE, byteArray);
+                            }
+                        } else if (info.isLuminance) {
+                            var unpackAlignment = gl.getParameter(gl.UNPACK_ALIGNMENT);
+                            var unpaddedRowSize = width;
+                            var paddedRowSize = Math.floor((width + unpackAlignment - 1) / unpackAlignment) * unpackAlignment;
+                            dataLength = paddedRowSize * (height - 1) + unpaddedRowSize;
+
+                            byteArray = DDSTools._GetLuminanceArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer);
+                            engine._uploadDataToTexture(sampler, i, gl.LUMINANCE, width, height, gl.LUMINANCE, gl.UNSIGNED_BYTE, byteArray);
+                        } else {
+                            dataLength = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockBytes;
+                            byteArray = new Uint8Array(arrayBuffer, dataOffset, dataLength);
+                            engine._uploadCompressedDataToTexture(sampler, i, internalFormat, width, height, byteArray);
                         }
-                    } else if (info.isLuminance) {
-                        var unpackAlignment = gl.getParameter(gl.UNPACK_ALIGNMENT);
-                        var unpaddedRowSize = width;
-                        var paddedRowSize = Math.floor((width + unpackAlignment - 1) / unpackAlignment) * unpackAlignment;
-                        dataLength = paddedRowSize * (height - 1) + unpaddedRowSize;
-
-                        byteArray = DDSTools._GetLuminanceArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer);
-                        engine._uploadDataToTexture(sampler, i, gl.LUMINANCE, width, height, gl.LUMINANCE, gl.UNSIGNED_BYTE, byteArray);
-                    } else {
-                        dataLength = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockBytes;
-                        byteArray = new Uint8Array(arrayBuffer, dataOffset, dataLength);
-                        engine._uploadCompressedDataToTexture(sampler, i, internalFormat, width, height, byteArray);
                     }
                     dataOffset += width * height * (bpp / 8);
                     width *= 0.5;

+ 95 - 44
src/babylon.engine.ts

@@ -741,7 +741,7 @@
             this._caps.drawBuffersExtension = this._webGLVersion > 1 || this._gl.getExtension('WEBGL_draw_buffers');
 
             // Checks if some of the format renders first to allow the use of webgl inspector.
-            this._caps.colorBufferFloat = this._webGLVersion > 1 && this._gl.getExtension('EXT_color_buffer_float')
+            this._caps.colorBufferFloat = this._webGLVersion > 1 && this._gl.getExtension('EXT_color_buffer_float');
 
             this._caps.textureFloat = this._webGLVersion > 1 || this._gl.getExtension('OES_texture_float');
             this._caps.textureFloatLinearFiltering = this._caps.textureFloat && this._gl.getExtension('OES_texture_float_linear');
@@ -2401,9 +2401,6 @@
             var lastDot = url.lastIndexOf('.');
             var extension = (lastDot > 0) ? url.substring(lastDot).toLowerCase() : "";
             var isDDS = this.getCaps().s3tc && (extension === ".dds");
-            if (isDDS) {
-                BABYLON.Tools.Warn("DDS files deprecated since 3.0, use KTX files");
-            }
             var isTGA = (extension === ".tga");
             
             // determine if a ktx file should be substituted
@@ -3117,7 +3114,79 @@
             return texture;
         }
 
-        public createCubeTexture(rootUrl: string, scene: Scene, files: string[], noMipmap?: boolean, onLoad: () => void = null, onError: () => void = null, format?: number): WebGLTexture {
+        public createPrefilteredCubeTexture(rootUrl: string, scene: Scene, scale: number, offset: number, onLoad: () => void, onError: () => void = null, format?: number): WebGLTexture {
+            var callback = (loadData) => {
+                if (this._caps.textureLOD || !loadData) {
+                    // Do not add extra process if texture lod is supported.
+                    if (onLoad) {
+                        onLoad();
+                    }
+                    return;
+                }
+
+                const mipSlices = 3;
+                
+                var gl = this._gl;
+                const width = loadData.width;
+                if (!width) {
+                    return;
+                }
+
+                const textures: BaseTexture[] = [];
+                for (let i = 0; i < mipSlices; i++) {
+                    //compute LOD from even spacing in smoothness (matching shader calculation)
+                    let smoothness = i / (mipSlices - 1);
+                    let roughness = 1 - smoothness;
+                    const kMinimumVariance = 0.0005;
+                    let alphaG = roughness * roughness + kMinimumVariance;
+                    let microsurfaceAverageSlopeTexels = alphaG * width;
+
+                    let environmentSpecularLOD = scale * (MathTools.Log2(microsurfaceAverageSlopeTexels)) + offset;
+
+                    let maxLODIndex = MathTools.Log2(width);
+                    let mipmapIndex = Math.min(Math.max(Math.round(environmentSpecularLOD), 0), maxLODIndex);
+
+                    var glTextureFromLod = gl.createTexture();
+                    glTextureFromLod.isCube = true;
+                    this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, glTextureFromLod);
+
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.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);
+
+                    if (loadData.isDDS) {
+                        var info: Internals.DDSInfo = loadData.info;
+                        var data: any = loadData.data;
+                        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, info.isCompressed ? 1 : 0);
+
+                        Internals.DDSTools.UploadDDSLevels(this, data, info, true, 6, mipmapIndex);
+                    }
+
+                    this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
+
+                    // Wrap in a base texture for easy binding.
+                    const lodTexture = new BaseTexture(scene);
+                    lodTexture.isCube = true;
+                    lodTexture._texture = glTextureFromLod;
+                    
+                    glTextureFromLod.isReady = true;
+                    textures.push(lodTexture);
+                }
+
+                (loadData.texture as WebGLTexture)._lodTextureHigh = textures[2];
+                (loadData.texture as WebGLTexture)._lodTextureMid = textures[1];
+                (loadData.texture as WebGLTexture)._lodTextureLow = textures[0];
+
+                if (onLoad) {
+                    onLoad();
+                }
+            };
+
+            return this.createCubeTexture(rootUrl, scene, null, false, callback, onError, format);
+        }
+
+        public createCubeTexture(rootUrl: string, scene: Scene, files: string[], noMipmap?: boolean, onLoad: (data?: any) => void = null, onError: () => void = null, format?: number): WebGLTexture {
             var gl = this._gl;
 
             var texture = gl.createTexture();
@@ -3190,6 +3259,10 @@
                     texture._height = info.height;
                     texture.isReady = true;
                     texture.type = info.textureType;
+
+                    if (onLoad) {
+                        onLoad({ isDDS: true, width: info.width, info, data, texture });
+                    }
                 }, null, null, true, onError);
             } else {
                 cascadeLoad(rootUrl, scene, imgs => {
@@ -3303,6 +3376,8 @@
             texture.isCube = true;
             texture.references = 1;
             texture.noMipmap = !generateMipMaps;
+            texture.format = format;
+            texture.type = type;
 
             var textureType = this._getWebGLTextureType(type);
             var internalFormat = this._getInternalFormat(format);
@@ -3503,6 +3578,17 @@
             if (index !== -1) {
                 this._loadedTexturesCache.splice(index, 1);
             }
+
+            // Intergated fixed lod samplers.
+            if (texture._lodTextureHigh) {
+                texture._lodTextureHigh.dispose();
+            }
+            if (texture._lodTextureMid) {
+                texture._lodTextureMid.dispose();
+            }
+            if (texture._lodTextureLow) {
+                texture._lodTextureLow.dispose();
+            }
         }
 
         private setProgram(program: WebGLProgram): void {
@@ -3945,7 +4031,7 @@
             }
         }
 
-        public _readTexturePixels(texture: WebGLTexture, width: number, height: number, faceIndex = -1, lodIndex = 0): ArrayBufferView {
+        public _readTexturePixels(texture: WebGLTexture, width: number, height: number, faceIndex = -1): ArrayBufferView {
             let gl = this._gl;
             if (!this._dummyFramebuffer) {
                 this._dummyFramebuffer = gl.createFramebuffer();
@@ -3953,9 +4039,9 @@
             gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
 
             if (faceIndex > -1) {
-                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture, lodIndex);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture, 0);
             } else {
-                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, lodIndex);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
             }
 
             let readFormat = (texture.format !== undefined) ? this._getRGBABufferInternalSizedFormat(texture.format) : gl.RGBA;
@@ -3972,48 +4058,13 @@
                     readType = gl.FLOAT;
                     break;
             }
+
             gl.readPixels(0, 0, width, height, gl.RGBA, readType, buffer);
-            
             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
 
             return buffer;
         }
 
-        public _createCubeTextureFromLOD(texture: BaseTexture, name: string, lodIndex: number): BaseTexture {
-            if (!texture.isCube) {
-                return null;
-            }
-
-            const gl = this._gl;
-            const maxSize = texture.getSize().width;
-            const numLod = MathTools.Log2(maxSize);
-            const targetSize = Math.pow(2, numLod - lodIndex);
-
-            var data: ArrayBufferView[] = [];
-            for (var i = 0; i < 6; i++) {
-                data.push(texture.readPixels(i, lodIndex));
-            }
-
-            const glTextureFromLod = this.createRawCubeTexture(data, targetSize, texture.textureFormat, texture.textureType, false, false, texture._texture.samplingMode);
-
-            // Wrap in a base texture for easy binding.
-            var lodTexture = new BaseTexture(texture.getScene());
-            lodTexture.isCube = true;
-            lodTexture.anisotropicFilteringLevel = texture.anisotropicFilteringLevel;
-            lodTexture.coordinatesIndex = texture.coordinatesIndex;
-            lodTexture.coordinatesMode = texture.coordinatesMode;
-            lodTexture.gammaSpace = texture.gammaSpace;
-            lodTexture.getAlphaFromRGB = texture.getAlphaFromRGB;
-            lodTexture.hasAlpha = texture.hasAlpha;
-            lodTexture.invertZ = texture.invertZ;
-            lodTexture.level = texture.level;
-            lodTexture.name = name;
-            lodTexture.wrapU = texture.wrapU;
-            lodTexture.wrapV = texture.wrapV;
-
-            return lodTexture;
-        }
-
         private _canRenderToFloatFramebuffer(): boolean {
             if (this._webGLVersion > 1) {
                 return this._caps.colorBufferFloat;

+ 6 - 0
src/babylon.mixins.ts

@@ -127,6 +127,12 @@ interface WebGLTexture {
     _generateStencilBuffer: boolean;
     _generateDepthBuffer: boolean;
     _sphericalPolynomial: BABYLON.SphericalPolynomial;
+    // The following three fields helps sharing generated fixed LODs for texture filtering
+    // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
+    // They are at the level of the gl texture to benefit from the cache.
+    _lodTextureHigh: BABYLON.BaseTexture;
+    _lodTextureMid: BABYLON.BaseTexture;
+    _lodTextureLow: BABYLON.BaseTexture;
 }
 
 interface WebGLBuffer {