Browse Source

Updates to raw cube texture

Gary Hsu 7 years ago
parent
commit
8bc8bba545

+ 19 - 22
loaders/src/glTF/2.0/Extensions/EXT_lights_imageBased.ts

@@ -73,35 +73,32 @@ module BABYLON.GLTF2.Extensions {
                 this._loader._parent._logClose();
 
                 light._loaded = Promise.all(promises).then(() => {
-                    return new Promise<void>((resolve, reject) => {
-                        const size = Math.pow(2, imageData.length - 1);
+                    const size = Math.pow(2, imageData.length - 1);
+                    const babylonTexture = new RawCubeTexture(this._loader._babylonScene, null, size);
+                    light._babylonTexture = babylonTexture;
 
-                        const sphericalHarmonics = SphericalHarmonics.FromArray(light.irradianceCoefficients);
-                        sphericalHarmonics.scale(light.intensity);
-
-                        const sphericalPolynomial = SphericalPolynomial.FromHarmonics(sphericalHarmonics);
+                    if (light.intensity != undefined) {
+                        babylonTexture.level = light.intensity;
+                    }
 
-                        light._babylonTexture = new RawCubeTexture(this._loader._babylonScene, imageData, size, undefined, undefined, undefined, undefined, undefined, undefined, () => {
-                            resolve();
-                        }, (message, exception) => {
-                            reject(exception);
-                        }, sphericalPolynomial, true);
+                    if (light.rotation) {
+                        let rotation = Quaternion.FromArray(light.rotation);
 
-                        if (light.intensity != undefined) {
-                            light._babylonTexture.level = light.intensity;
+                        // Invert the rotation so that positive rotation is counter-clockwise.
+                        if (!this._loader._babylonScene.useRightHandedSystem) {
+                            rotation = Quaternion.Inverse(rotation);
                         }
 
-                        if (light.rotation) {
-                            let rotation = Quaternion.FromArray(light.rotation);
+                        Matrix.FromQuaternionToRef(rotation, babylonTexture.getReflectionTextureMatrix());
+                    }
 
-                            // Invert the rotation so that positive rotation is counter-clockwise.
-                            if (!this._loader._babylonScene.useRightHandedSystem) {
-                                rotation = Quaternion.Inverse(rotation);
-                            }
+                    const sphericalHarmonics = SphericalHarmonics.FromArray(light.irradianceCoefficients);
+                    sphericalHarmonics.scale(light.intensity);
 
-                            Matrix.FromQuaternionToRef(rotation, light._babylonTexture.getReflectionTextureMatrix());
-                        }
-                    });
+                    sphericalHarmonics.convertIrradianceToLambertianRadiance();
+                    const sphericalPolynomial = SphericalPolynomial.FromHarmonics(sphericalHarmonics);
+
+                    return babylonTexture.updateRGBDAsync(imageData, sphericalPolynomial);
                 });
             }
 

+ 5 - 43
src/Engine/babylon.engine.ts

@@ -5859,9 +5859,6 @@
             // this.resetTextureCache();
 
             texture.isReady = true;
-
-            texture.onLoadedObservable.notifyObservers(texture);
-            texture.onLoadedObservable.clear();
         }
 
         /**
@@ -5874,28 +5871,17 @@
          * @param invertY defines if data must be stored with Y axis inverted
          * @param samplingMode defines the required sampling mode (like BABYLON.Texture.NEAREST_SAMPLINGMODE)
          * @param compression defines the compression used (null by default)
-         * @param onLoad defines an optional callback raised when the texture is loaded
-         * @param onError defines an optional callback raised if there is an issue to load the texture
-         * @param sphericalPolynomial defines the spherical polynomial for irradiance
-         * @param rgbd defines if the data is stored as RGBD
-         * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
-         * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
          * @returns the cube texture as an InternalTexture
          */
-        public createRawCubeTexture(data: Nullable<ArrayBufferView[] | ArrayBufferView[][]>, size: number, format: number, type: number,
-                                    generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string> = null,
-                                    onLoad: Nullable<() => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null,
-                                    sphericalPolynomial: Nullable<SphericalPolynomial> = null, rgbd = false, lodScale: number = 0, lodOffset: number = 0): InternalTexture {
+        public createRawCubeTexture(data: Nullable<ArrayBufferView[]>, size: number, format: number, type: number,
+                                    generateMipMaps: boolean, invertY: boolean, samplingMode: number,
+                                    compression: Nullable<string> = null): InternalTexture {
             var gl = this._gl;
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_CUBERAW);
             texture.isCube = true;
             texture.generateMipMaps = generateMipMaps;
             texture.format = format;
             texture.type = type;
-            texture._lodGenerationScale = lodScale;
-            texture._lodGenerationOffset = lodOffset;
-            texture._sourceIsRGBD = rgbd;
-            texture._sphericalPolynomial = sphericalPolynomial;
             if (!this._doNotHandleContextLost) {
                 texture._bufferViewArray = data;
             }
@@ -5920,32 +5906,8 @@
             }
 
             // Upload data if needed. The texture won't be ready until then.
-            if (data && data.length) {
-                if (rgbd) {
-                    EnvironmentTextureTools.UploadLevelsAsync(texture, data as ArrayBufferView[][]).then(() => {
-                        texture.isReady = true;
-
-                        texture.onLoadedObservable.notifyObservers(texture);
-                        texture.onLoadedObservable.clear();
-
-                        if (onLoad) {
-                            onLoad();
-                        }
-                    }, reason => {
-                        if (onError) {
-                            onError("Failed to upload raw cube texture data to the GPU", reason);
-                        }
-                    });
-                }
-                else {
-                    Tools.SetImmediate(() => {
-                        this.updateRawCubeTexture(texture, data as ArrayBufferView[], format, type, invertY, compression);
-
-                        if (onLoad) {
-                            onLoad();
-                        }
-                    });
-                }
+            if (data) {
+                this.updateRawCubeTexture(texture, data as ArrayBufferView[], format, type, invertY, compression);
             }
 
             this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);

+ 12 - 6
src/Materials/Textures/babylon.internalTexture.ts

@@ -53,6 +53,10 @@ module BABYLON {
          * Texture content is a depth texture
          */
         public static DATASOURCE_DEPTHTEXTURE = 11;
+        /**
+         * Texture data comes from a raw cube data encoded with RGBD
+         */
+        public static DATASOURCE_CUBERAW_RGBD = 12;
 
         /**
          * Defines if the texture is ready
@@ -144,7 +148,9 @@ module BABYLON {
         /** @hidden */
         public _bufferView: Nullable<ArrayBufferView>;
         /** @hidden */
-        public _bufferViewArray: Nullable<ArrayBufferView[] | ArrayBufferView[][]>;
+        public _bufferViewArray: Nullable<ArrayBufferView[]>;
+        /** @hidden */
+        public _bufferViewArrayArray: Nullable<ArrayBufferView[][]>;
         /** @hidden */
         public _size: number;
         /** @hidden */
@@ -191,8 +197,6 @@ module BABYLON {
         public _lodGenerationScale: number = 0;
         /** @hidden */
         public _lodGenerationOffset: number = 0;
-        /** @hidden */
-        public _sourceIsRGBD: boolean = false;
 
         // 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.
@@ -352,9 +356,11 @@ module BABYLON {
                     return;
 
                 case InternalTexture.DATASOURCE_CUBERAW:
-                    proxy = this._engine.createRawCubeTexture(this._bufferViewArray, this.width, this.format, this.type, this.generateMipMaps, this.invertY, this.samplingMode, this._compression, () => {
-                        this.isReady = true;
-                    }, null, this._sphericalPolynomial, this._sourceIsRGBD, this._lodGenerationScale, this._lodGenerationOffset);
+                case InternalTexture.DATASOURCE_CUBERAW_RGBD:
+                    proxy = this._engine.createRawCubeTexture(null, this.width, this.format, this.type, this.generateMipMaps, this.invertY, this.samplingMode, this._compression);
+                    if (this._dataSource) {
+                        RawCubeTexture._UpdateRGBDAsync(proxy, this._bufferViewArrayArray!, this._sphericalPolynomial, this._lodGenerationScale, this._lodGenerationOffset);
+                    }
                     proxy._swapAndDie(this);
                     return;
 

+ 55 - 16
src/Materials/Textures/babylon.rawCubeTexture.ts

@@ -1,4 +1,7 @@
 module BABYLON {
+    /**
+     * Raw cube texture where the raw buffers are passed in
+     */
     export class RawCubeTexture extends CubeTexture {
         /**
          * Creates a cube texture where the raw buffers are passed in.
@@ -11,36 +14,72 @@ module BABYLON {
          * @param invertY defines if data must be stored with Y axis inverted
          * @param samplingMode defines the required sampling mode (like BABYLON.Texture.NEAREST_SAMPLINGMODE)
          * @param compression defines the compression used (null by default)
-         * @param onLoad defines an optional callback raised when the texture is loaded
-         * @param onError defines an optional callback raised if there is an issue to load the texture
-         * @param sphericalPolynomial defines the spherical polynomial for irradiance
-         * @param rgbd defines if the data is stored as RGBD
-         * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
-         * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
          */
-        constructor(scene: Scene, data: ArrayBufferView[] | ArrayBufferView[][], size: number,
+        constructor(scene: Scene, data: Nullable<ArrayBufferView[]>, size: number,
                     format: number = Engine.TEXTUREFORMAT_RGBA, type: number = Engine.TEXTURETYPE_UNSIGNED_INT,
                     generateMipMaps: boolean = false, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE,
-                    compression: Nullable<string> = null, onLoad: Nullable<() => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null,
-                    sphericalPolynomial: Nullable<SphericalPolynomial> = null, rgbd = false, lodScale: number = 0.8, lodOffset: number = 0) {
+                    compression: Nullable<string> = null) {
             super("", scene);
 
-            this._texture = scene.getEngine().createRawCubeTexture(
-                data, size, format, type, generateMipMaps, invertY, samplingMode, compression,
-                onLoad, onError, sphericalPolynomial, rgbd, lodScale, lodOffset);
+            this._texture = scene.getEngine().createRawCubeTexture(data, size, format, type, generateMipMaps, invertY, samplingMode, compression);
+        }
+
+        /**
+         * Updates the raw cube texture.
+         * @param data defines the data to store
+         * @param format defines the data format
+         * @param type defines the type fo the data (BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT by default)
+         * @param invertY defines if data must be stored with Y axis inverted
+         * @param compression defines the compression used (null by default)
+         * @param level defines which level of the texture to update
+         */
+        public update(data: ArrayBufferView[], format: number, type: number, invertY: boolean, compression: Nullable<string> = null, level = 0): void {
+            this._texture!.getEngine().updateRawCubeTexture(this._texture!, data, format, type, invertY, compression);
+        }
+
+        /**
+         * Creates a raw cube texture from RGBD encoded data.
+         * @param data defines the array of data [mipmap][face] to use to create each face
+         * @param sphericalPolynomial defines the spherical polynomial for irradiance
+         * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
+         * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
+         * @returns a promsie that resolves when the operation is complete
+         */
+        public updateRGBDAsync(data: ArrayBufferView[][], sphericalPolynomial: Nullable<SphericalPolynomial> = null, lodScale: number = 0.8, lodOffset: number = 0): Promise<void> {
+            return RawCubeTexture._UpdateRGBDAsync(this._texture!, data, sphericalPolynomial, lodScale, lodOffset);
         }
 
         /**
          * Clones the raw cube texture.
+         * @return a new cube texture
          */
         public clone(): CubeTexture {
             return SerializationHelper.Clone(() => {
                 const scene = this.getScene()!;
-                const texture = this._texture!;
-                return new RawCubeTexture(scene, texture._bufferViewArray!, texture.width, texture.format, texture.type,
-                    texture.generateMipMaps, texture.invertY, texture.samplingMode, texture._compression, null, null,
-                    texture._sphericalPolynomial, texture._sourceIsRGBD, texture._lodGenerationScale, texture._lodGenerationOffset);
+                const internalTexture = this._texture!;
+
+                const texture = new RawCubeTexture(scene, internalTexture._bufferViewArray!, internalTexture.width, internalTexture.format, internalTexture.type,
+                    internalTexture.generateMipMaps, internalTexture.invertY, internalTexture.samplingMode, internalTexture._compression);
+
+                if (internalTexture.dataSource === InternalTexture.DATASOURCE_CUBERAW_RGBD) {
+                    texture.updateRGBDAsync(internalTexture._bufferViewArrayArray!, internalTexture._sphericalPolynomial, internalTexture._lodGenerationScale, internalTexture._lodGenerationOffset);
+                }
+
+                return texture;
             }, this);
         }
+
+        /** @hidden */
+        public static _UpdateRGBDAsync(internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: Nullable<SphericalPolynomial>, lodScale: number, lodOffset: number): Promise<void> {
+            internalTexture._dataSource = InternalTexture.DATASOURCE_CUBERAW_RGBD;
+            internalTexture._bufferViewArrayArray = data;
+            internalTexture._lodGenerationScale = lodScale;
+            internalTexture._lodGenerationOffset = lodOffset;
+            internalTexture._sphericalPolynomial = sphericalPolynomial;
+
+            return EnvironmentTextureTools.UploadLevelsAsync(internalTexture, data).then(() => {
+                internalTexture.isReady = true;
+            });
+        }
     }
 }

+ 12 - 54
src/Tools/babylon.environmentTextureTools.ts

@@ -58,20 +58,6 @@ module BABYLON {
      * Defines the required storage to save the environment irradiance information.
      */
     interface EnvironmentTextureIrradianceInfoV1 {
-        polynomials: boolean;
-
-        l00: Array<number>;
-
-        l1_1: Array<number>;
-        l10: Array<number>;
-        l11: Array<number>;
-
-        l2_2: Array<number>;
-        l2_1: Array<number>;
-        l20: Array<number>;
-        l21: Array<number>;
-        l22: Array<number>;
-
         x: Array<number>;
         y: Array<number>;
         z: Array<number>;
@@ -294,8 +280,6 @@ module BABYLON {
             }
 
             return {
-                polynomials: true,
-
                 x: [polynmials.x.x, polynmials.x.y, polynmials.x.z],
                 y: [polynmials.y.x, polynmials.y.y, polynmials.y.z],
                 z: [polynmials.z.x, polynmials.z.y, polynmials.z.z],
@@ -341,17 +325,6 @@ module BABYLON {
                 for (let face = 0; face < 6; face++) {
                     const imageInfo = specularInfo.mipmaps[i * 6 + face];
                     imageData[i][face] = new Uint8Array(arrayBuffer, specularInfo.specularDataPosition! + imageInfo.position, imageInfo.length);
-
-
-                    // {
-                    //     const link = document.createElement('a');
-                    //     document.body.appendChild(link);
-                    //     link.setAttribute("type", "hidden");
-                    //     link.download = `image${face}${i}`;
-                    //     const blob = new Blob([imageData[i][face]], { type: "image/png" });
-                    //     link.href = window.URL.createObjectURL(blob);
-                    //     link.click();
-                    // }
                 }
             }
 
@@ -433,7 +406,7 @@ module BABYLON {
                         let roughness = 1 - smoothness;
 
                         let minLODIndex = offset; // roughness = 0
-                        let maxLODIndex = mipmapsCount * scale + offset; // roughness = 1
+                        let maxLODIndex = (mipmapsCount - 1) * scale + offset; // roughness = 1
 
                         let lodIndex = minLODIndex + (maxLODIndex - minLODIndex) * roughness;
                         let mipmapIndex = Math.round(Math.min(Math.max(lodIndex, 0), maxLODIndex));
@@ -565,32 +538,17 @@ module BABYLON {
                 return;
             }
 
-            if (irradianceInfo.polynomials) {
-                const sp = new SphericalPolynomial();
-                Vector3.FromArrayToRef(irradianceInfo.x, 0, sp.x);
-                Vector3.FromArrayToRef(irradianceInfo.y, 0, sp.y);
-                Vector3.FromArrayToRef(irradianceInfo.z, 0, sp.z);
-                Vector3.FromArrayToRef(irradianceInfo.xx, 0, sp.xx);
-                Vector3.FromArrayToRef(irradianceInfo.yy, 0, sp.yy);
-                Vector3.FromArrayToRef(irradianceInfo.zz, 0, sp.zz);
-                Vector3.FromArrayToRef(irradianceInfo.yz, 0, sp.yz);
-                Vector3.FromArrayToRef(irradianceInfo.zx, 0, sp.zx);
-                Vector3.FromArrayToRef(irradianceInfo.xy, 0, sp.xy);
-                texture._sphericalPolynomial = sp;
-            }
-            else {
-                const sh = new SphericalHarmonics();
-                Vector3.FromArrayToRef(irradianceInfo.l00, 0, sh.L00);
-                Vector3.FromArrayToRef(irradianceInfo.l1_1, 0, sh.L1_1);
-                Vector3.FromArrayToRef(irradianceInfo.l10, 0, sh.L10);
-                Vector3.FromArrayToRef(irradianceInfo.l11, 0, sh.L11);
-                Vector3.FromArrayToRef(irradianceInfo.l2_2, 0, sh.L2_2);
-                Vector3.FromArrayToRef(irradianceInfo.l2_1, 0, sh.L2_1);
-                Vector3.FromArrayToRef(irradianceInfo.l20, 0, sh.L20);
-                Vector3.FromArrayToRef(irradianceInfo.l21, 0, sh.L21);
-                Vector3.FromArrayToRef(irradianceInfo.l22, 0, sh.L22);
-                texture._sphericalPolynomial = SphericalPolynomial.FromHarmonics(sh);
-            }
+            const sp = new SphericalPolynomial();
+            Vector3.FromArrayToRef(irradianceInfo.x, 0, sp.x);
+            Vector3.FromArrayToRef(irradianceInfo.y, 0, sp.y);
+            Vector3.FromArrayToRef(irradianceInfo.z, 0, sp.z);
+            Vector3.FromArrayToRef(irradianceInfo.xx, 0, sp.xx);
+            Vector3.FromArrayToRef(irradianceInfo.yy, 0, sp.yy);
+            Vector3.FromArrayToRef(irradianceInfo.zz, 0, sp.zz);
+            Vector3.FromArrayToRef(irradianceInfo.yz, 0, sp.yz);
+            Vector3.FromArrayToRef(irradianceInfo.zx, 0, sp.zx);
+            Vector3.FromArrayToRef(irradianceInfo.xy, 0, sp.xy);
+            texture._sphericalPolynomial = sp;
         }
     }
 }