Sfoglia il codice sorgente

Step 4 first pass cleanup (first pass only)

sebastien 7 anni fa
parent
commit
1bd381516c

+ 9 - 0
src/Engine/babylon.engine.ts

@@ -1129,6 +1129,11 @@
         }
 
         /**
+         * Defines whether the engine has been created with the premultipliedAlpha option on or not.
+         */
+        public readonly premultipliedAlpha: boolean = false;
+
+        /**
          * Creates a new engine
          * @param canvasOrContext defines the canvas or WebGL context to use for rendering
          * @param antialias defines enable antialiasing (default: false)
@@ -1177,6 +1182,10 @@
                     options.stencil = true;
                 }
 
+                if (options.premultipliedAlpha) {
+                    this.premultipliedAlpha = true;
+                }
+
                 this._deterministicLockstep = options.deterministicLockstep;
                 this._lockstepMaxSteps = options.lockstepMaxSteps;
                 this._doNotHandleContextLost = options.doNotHandleContextLost ? true : false;

+ 15 - 7
src/Materials/Textures/babylon.baseTexture.ts

@@ -283,6 +283,14 @@
             return (this._texture.format !== undefined) ? this._texture.format : Engine.TEXTUREFORMAT_RGBA;
         }
 
+        /**
+         * Reads the pixels stored in the webgl texture and returns them as an ArrayBuffer.
+         * This will returns an RGBA array buffer containing either in values (0-255) or
+         * float values (0-1) depending of the underlying buffer type.
+         * @param faceIndex The face of the texture to read (in case of cube texture)
+         * @param level The LOD level of the texture to read (in case of Mip Maps)
+         * @returns The Array buffer containing the pixels data.
+         */
         public readPixels(faceIndex = 0, level = 0): Nullable<ArrayBufferView> {
             if (!this._texture) {
                 return null;
@@ -299,15 +307,15 @@
 
             var engine = scene.getEngine();
 
-            if (this._texture.isCube) {
-                if (level != 0) {
-                    width = width / Math.pow(2, level);
-                    height = height / Math.pow(2, level);
+            if (level != 0) {
+                width = width / Math.pow(2, level);
+                height = height / Math.pow(2, level);
 
-                    width = Math.round(width);
-                    height = Math.round(height);
-                }
+                width = Math.round(width);
+                height = Math.round(height);
+            }
 
+            if (this._texture.isCube) {
                 return engine._readTexturePixels(this._texture, width, height, faceIndex, level);
             }
 

+ 3 - 6
src/Materials/Textures/babylon.cubeTexture.ts

@@ -53,9 +53,11 @@
         private _extensions: string[];
         private _textureMatrix: Matrix;
         private _format: number;
-        private _prefiltered: boolean;
         private _createPolynomials: boolean;
 
+        /** @hidden */
+        public readonly _prefiltered: boolean = false;
+
         public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean) {
             let rootUrlKey = "";
 
@@ -143,11 +145,6 @@
             this._files = files;
 
             if (!this._texture) {
-                // Prefiltered are only available in DDS. 
-                if (!isDDS) {
-                    prefiltered = false;
-                }
-
                 if (!scene.useDelayedTextureLoading) {
                     if (prefiltered) {
                         this._texture = scene.getEngine().createPrefilteredCubeTexture(rootUrl, scene, this.lodGenerationScale, this.lodGenerationOffset, onLoad, onError, format, forcedExtension, this._createPolynomials);

+ 119 - 92
src/Tools/babylon.environmentTextureTools.ts

@@ -24,6 +24,36 @@ module BABYLON {
         specular: any;
     }
 
+    /**
+     * Defines One Image in the file. It requires only the position in the file 
+     * as well as the length.
+     */
+    interface BufferImageData {
+        /**
+         * Length of the image data.
+         */
+        length: number;
+        /**
+         * Position of the data from the null terminator delimiting the end of the JSON.
+         */
+        position: number;
+    }
+
+    /**
+     * Defines the specular data enclosed in the file.
+     * This corresponds to the version 1 of the data.
+     */
+    interface EnvironmentTextureSpecularInfoV1 {
+        /**
+         * Defines where the specular Payload is located. It is a runtime value only not stored in the file.
+         */
+        specularDataPosition?: number;
+        /**
+         * This contains all the images data needed to reconstruct the cubemap.
+         */
+        mipmaps: Array<BufferImageData>
+    }
+
     interface EnvironmentTextureIrradianceInfoV1 {
         l00: Array<number>;
 
@@ -38,27 +68,24 @@ module BABYLON {
         l22: Array<number>;
     }
 
-    interface BufferImageData {
-        length: number;
-        position: number;
-    }
+    /**
+     * Sets of helpers addressing the serialization and deserialization of environment texture
+     * stored in a BabylonJS env file.
+     * Those files are usually stored as .env files.
+     */
+    export class EnvironmentTextureTools {
 
-    interface EnvironmentTextureSpecularInfoV1 {
         /**
-         * Defines where the specular Payload is located. It is a runtime value only not stored in the file.
+         * Magic number identifying the env file.
          */
-        specularDataPosition?: number;
-        mipmaps: Array<BufferImageData>
-    }
-
-    export class EnvironmentTextureTools {
-
         private static _MagicBytes = [0x86, 0x16, 0x87, 0x96, 0xf6, 0xd6, 0x96, 0x36];
 
+        /**
+         * Gets the environment info from an env file.
+         * @param data The array buffer containing the .env bytes.
+         * @returns the environment file info (the json header) if successfully parsed.
+         */
         public static GetEnvInfo(data: ArrayBuffer): Nullable<EnvironmentTextureInfo> {
-            // Close to network
-            // let littleEndian = false;
-
             let dataView = new DataView(data);
             let pos = 0;
 
@@ -78,45 +105,64 @@ module BABYLON {
 
             let manifest: EnvironmentTextureInfo = JSON.parse(manifestString);
             if (manifest.specular) {
+                // Extend the header with the position of the payload.
                 manifest.specular.specularDataPosition = pos;
             }
 
             return manifest;
         }
 
-        public static CreateEnvTexture(texture: CubeTexture): Nullable<Promise<ArrayBuffer>> {
+        /**
+         * Creates an environment texture from a loaded cube texture.
+         * @param texture defines the cube texture to convert in env file
+         * @return a promise containing the environment data if succesfull.
+         */
+        public static CreateEnvTextureAsync(texture: CubeTexture): Promise<ArrayBuffer> {
             let internalTexture = texture.getInternalTexture();
             if (!internalTexture) {
-                return null;
+                return Promise.reject("The cube texture is invalid.");
+            }
+
+            if (!texture._prefiltered) {
+                return Promise.reject("The cube texture is invalid (not prefiltered).");
             }
 
             let engine = internalTexture.getEngine();
-            let hostingScene = new Scene(engine);
+            if (engine && !engine.premultipliedAlpha) {
+                return Promise.reject("Env texture can only be created when the engine is created with the premultipliedAlpa option.");
+            }
 
-            let info: EnvironmentTextureInfo = {
-                version: 1,
-                width: internalTexture.width,
-                irradiance: null,
-                specular: null
-            };
+            let canvas = engine.getRenderingCanvas();
+            if (!canvas) {
+                return Promise.reject("Env texture can only be created when the engine is associated to a canvas.");
+            }
+
+            let textureType = Engine.TEXTURETYPE_FLOAT;
+            if (!engine.getCaps().textureFloatRender) {
+                textureType = Engine.TEXTURETYPE_HALF_FLOAT;
+                if (!engine.getCaps().textureHalfFloatRender) {
+                    return Promise.reject("Env texture can only be created when the browser supports half float or full float rendering.");
+                }
+            }
 
+            let cubeWidth = internalTexture.width;
+            let hostingScene = new Scene(engine);
             let specularTextures: { [key: number]: ArrayBuffer } = { };
             let promises: Promise<void>[] = [];
 
-            // All mipmaps
+            // Read and collect all mipmaps data from the cube.
             let mipmapsCount = Scalar.Log2(internalTexture.width);
             mipmapsCount = Math.round(mipmapsCount);
             for (let i = 0; i <= mipmapsCount; i++) {
                 let faceWidth = Math.pow(2, mipmapsCount - i);
 
-                // All faces
+                // All faces of the cube.
                 for (let face = 0; face < 6; face++) {
-
                     let data = texture.readPixels(face, i);
 
-                    let textureType = Engine.TEXTURETYPE_FLOAT;
+                    // Creates a temp texture with the face data.
                     let tempTexture = engine.createRawTexture(data, faceWidth, faceWidth, Engine.TEXTUREFORMAT_RGBA, false, false, Texture.NEAREST_SAMPLINGMODE, null, textureType);
-
+                    // And rgbmEncode them. 
                     let promise = new Promise<void>((resolve, reject) => {
                         let rgbmPostProcess = new PostProcess("rgbmEncode", "rgbmEncode", null, null, 1, null, Texture.NEAREST_SAMPLINGMODE, engine, false, undefined, Engine.TEXTURETYPE_UNSIGNED_INT, undefined, null, false);
                         rgbmPostProcess.getEffect().executeWhenCompiled(() => {
@@ -124,39 +170,26 @@ module BABYLON {
                                 effect._bindTexture("textureSampler", tempTexture);
                             }
             
-                            //let internalTexture = rtt.getInternalTexture();
+                            // As the process needs to happen on the main canvas, keep track of the current size
                             let currentW = engine.getRenderWidth();
                             let currentH = engine.getRenderHeight();
+
+                            // Set the desired size for the texture
                             engine.setSize(faceWidth, faceWidth);
-            
-                            if (internalTexture) {
-                                hostingScene.postProcessManager.directRender([rgbmPostProcess], null);
-                            }
+                            hostingScene.postProcessManager.directRender([rgbmPostProcess], null);
+
+                            // Reading datas from WebGL
+                            canvas!.toBlob((blob) => {
+                                let fileReader = new FileReader();
+                                fileReader.onload = (event) => {
+                                    let arrayBuffer = event.target!.result as ArrayBuffer;
+                                    specularTextures[i * 6 + face] = arrayBuffer;
+                                    resolve();
+                                };
+                                fileReader.readAsArrayBuffer(blob!);
+                            });
 
-                            //Reading datas from WebGL
-                            let canvas = engine.getRenderingCanvas();
-                            if (canvas) {
-                                canvas.toBlob((blob) => {
-                                    // let url = window.URL.createObjectURL(blob);
-
-                                    // let a: any = document.createElement("a");
-                                    //     document.body.appendChild(a);
-                                    //     a.style = "display: none";
-
-                                    // a.href = url;
-                                    // a.download = "env_" + i + "_" + face + ".png";
-                                    // a.click();
-                                    // window.URL.revokeObjectURL(url);
-
-                                    let fileReader = new FileReader();
-                                    fileReader.onload = (event) => {
-                                        let arrayBuffer = event.target!.result as ArrayBuffer;
-                                        specularTextures[i * 6 + face] = arrayBuffer;
-                                        resolve();
-                                    };
-                                    fileReader.readAsArrayBuffer(blob!);
-                                });
-                            }
+                            // Reapply the previous canvas size
                             engine.setSize(currentW, currentH);
                         });
                     });
@@ -164,13 +197,22 @@ module BABYLON {
                 }
             }
 
+            // Once all the textures haves been collected as RGBM stored in PNGs
             return Promise.all(promises).then(() => {
+                // We can delete the hosting scene keeping track of all the creation objects
                 hostingScene.dispose();
 
-                info.specular = {
-                    mipmaps: []
+                // Creates the json header for the env texture
+                let info: EnvironmentTextureInfo = {
+                    version: 1,
+                    width: cubeWidth,
+                    irradiance: null,
+                    specular: {
+                        mipmaps: []
+                    }
                 };
 
+                // Sets the specular image data information
                 let position = 0;
                 for (let i = 0; i <= mipmapsCount; i++) {
                     for (let face = 0; face < 6; face++) {
@@ -183,32 +225,33 @@ module BABYLON {
                     }
                 }
 
-                function str2ab(str: string) {
-                    let buf = new ArrayBuffer(str.length + 1); 
-                    let bufView = new Uint8Array(buf); // Limited to ascii subset matching unicode.
-                    for (let i=0, strLen=str.length; i < strLen; i++) {
-                        bufView[i] = str.charCodeAt(i);
-                    }
-                    bufView[str.length] = 0x00;
-                    return buf;
-                }
-
+                // Encode the JSON as an array buffer
                 let infoString = JSON.stringify(info);
-                let infoBuffer = str2ab(infoString);
+                let infoBuffer = new ArrayBuffer(infoString.length + 1);
+                let infoView = new Uint8Array(infoBuffer); // Limited to ascii subset matching unicode.
+                for (let i= 0, strLen = infoString.length; i < strLen; i++) {
+                    infoView[i] = infoString.charCodeAt(i);
+                }
+                // Ends up with a null terminator for easier parsing
+                infoView[infoString.length] = 0x00;
 
+                // Computes the final required size and creates the storage
                 let totalSize = EnvironmentTextureTools._MagicBytes.length + position + infoBuffer.byteLength;
                 let finalBuffer = new ArrayBuffer(totalSize);
                 let finalBufferView = new Uint8Array(finalBuffer);
                 let dataView = new DataView(finalBuffer);
 
+                // Copy the magic bytes identifying the file in
                 let pos = 0;
                 for (let i = 0; i < EnvironmentTextureTools._MagicBytes.length; i++) {
                     dataView.setUint8(pos++, EnvironmentTextureTools._MagicBytes[i]);
                 }
 
+                // Add the json info
                 finalBufferView.set(new Uint8Array(infoBuffer), pos);
                 pos += infoBuffer.byteLength;
 
+                // Finally inserts the texture data
                 for (let i = 0; i <= mipmapsCount; i++) {
                     for (let face = 0; face < 6; face++) {
                         let dataBuffer = specularTextures[i * 6 + face];
@@ -217,10 +260,14 @@ module BABYLON {
                     }
                 }
 
+                // Voila
                 return finalBuffer;
             });
         }
 
+        /**
+         * Uploads the 
+         */
         public static UploadLevelsAsync(texture: InternalTexture, arrayBuffer: any, info: EnvironmentTextureInfo): Promise<void> {
             if (info.version !== 1) {
                 Tools.Warn('Unsupported babylon environment map version "' + info.version + '"');
@@ -440,24 +487,4 @@ module BABYLON {
             outPolynomialCoefficents.xy.z = 0.858086 * harmonics.l2_2[2] * rPi;
         }
     }
-
-    export class EnvironmentTexture extends CubeTexture {
-        
-        constructor(url: string, scene: Scene) {
-           super(url, scene, null, false, null, null, null, undefined, true, ".env", false);
-
-
-        }
-
-        public clone(): EnvironmentTexture {
-            return SerializationHelper.Clone(() => {
-                let scene = this.getScene();
-
-                if (!scene) {
-                    return this;
-                }
-                return new EnvironmentTexture(this.url, scene);
-            }, this);
-        }
-    }
-} 
+}