ソースを参照

Minimally-invasive changes to get IBL working in Babylon Native.

Justin Murray 6 年 前
コミット
05083d67db

+ 2 - 2
src/Engine/babylon.engine.ts

@@ -739,7 +739,7 @@
         private _onContextLost: (evt: Event) => void;
         private _onContextRestored: (evt: Event) => void;
         private _contextWasLost = false;
-        private _doNotHandleContextLost = false;
+        protected _doNotHandleContextLost = false;
 
         /**
          * Gets or sets a boolean indicating if resources should be retained to be able to handle context lost events
@@ -840,7 +840,7 @@
 
         // Hardware supported Compressed Textures
         private _texturesSupported = new Array<string>();
-        private _textureFormatInUse: Nullable<string>;
+        protected _textureFormatInUse: Nullable<string>;
 
         /**
          * Gets the list of texture formats supported

+ 104 - 1
src/Engine/babylon.nativeEngine.ts

@@ -41,6 +41,7 @@
         setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void;
 
         createTexture(): WebGLTexture;
+        createCubeTextureFromData(texture: WebGLTexture, data: Array<Array<ArrayBufferView>>, flipY : boolean): void;
         loadTexture(texture: WebGLTexture, buffer: ArrayBuffer | Blob, mipMap: boolean): void;
         getTextureWidth(texture: WebGLTexture): number;
         getTextureHeight(texture: WebGLTexture): number;
@@ -211,7 +212,7 @@
             this._caps.textureHalfFloatLinearFiltering = false;
             this._caps.textureHalfFloatRender = false;
 
-            this._caps.textureLOD = false;
+            this._caps.textureLOD = true;
             this._caps.drawBuffersExtension = false;
 
             this._caps.depthTextureExtension = false;
@@ -926,6 +927,108 @@
             return texture;
         }
 
+        /**
+         * Creates a cube texture
+         * @param rootUrl defines the url where the files to load is located
+         * @param scene defines the current scene
+         * @param files defines the list of files to load (1 per face)
+         * @param noMipmap defines a boolean indicating that no mipmaps shall be generated (false 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 format defines the format of the data
+         * @param forcedExtension defines the extension to use to pick the right loader
+         * @param createPolynomials if a polynomial sphere should be created for the cube texture
+         * @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
+         * @param fallback defines texture to use while falling back when (compressed) texture file not found.
+         * @returns the cube texture as an InternalTexture
+         */
+        public createCubeTexture(
+            rootUrl: string, 
+            scene: Nullable<Scene>, 
+            files: Nullable<string[]>, 
+            noMipmap?: boolean, 
+            onLoad: Nullable<(data?: any) => void> = null, 
+            onError: Nullable<(message?: string, exception?: any) => void> = null, 
+            format?: number, 
+            forcedExtension: any = null, 
+            createPolynomials = false, 
+            lodScale: number = 0, 
+            lodOffset: number = 0, 
+            fallback: Nullable<InternalTexture> = null): InternalTexture
+        {
+            var texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
+            texture.isCube = true;
+            texture.url = rootUrl;
+            texture.generateMipMaps = !noMipmap;
+            texture._lodGenerationScale = lodScale;
+            texture._lodGenerationOffset = lodOffset;
+
+            if (!this._doNotHandleContextLost) {
+                texture._extension = forcedExtension;
+                texture._files = files;
+            }
+
+            var lastDot = rootUrl.lastIndexOf('.');
+            var extension = forcedExtension ? forcedExtension : (lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "");
+
+            if (extension === ".env") {
+                const onloaddata = (data: any) => {
+                    data = data as ArrayBuffer;
+                    
+                    var info = EnvironmentTextureTools.GetEnvInfo(data)!;
+                    texture.width = info.width;
+                    texture.height = info.width;
+
+                    EnvironmentTextureTools.UploadEnvSpherical(texture, info);
+
+                    if (info.version !== 1) {
+                        throw new Error(`Unsupported babylon environment map version "${info.version}"`);
+                    }
+        
+                    let specularInfo = info.specular as EnvironmentTextureSpecularInfoV1;
+                    if (!specularInfo) {
+                        throw new Error(`Nothing else parsed so far`);
+                    }
+        
+                    texture._lodGenerationScale = specularInfo.lodGenerationScale;
+                    const imageData = EnvironmentTextureTools.CreateImageDataArrayBufferViews(data, info);
+                    
+                    texture.format = Engine.TEXTUREFORMAT_RGBA;
+                    texture.type = Engine.TEXTURETYPE_UNSIGNED_INT;
+                    texture.generateMipMaps = true;
+                    texture.getEngine().updateTextureSamplingMode(Texture.TRILINEAR_SAMPLINGMODE, texture);
+                    texture._isRGBD = true;
+                    texture.invertY = true;
+                    this._native.createCubeTextureFromData(texture._webGLTexture!, imageData, true);
+
+                    texture.isReady = true;
+                    if (onLoad) {
+                        onLoad();
+                    }
+                };
+                if (files && files.length === 6) {
+                    throw new Error(`Multi-file loading not yet supported.`);
+                }
+                else {
+                    let onInternalError = (request?: XMLHttpRequest, exception?: any) => {
+                        if (onError && request) {
+                            onError(request.status + " " + request.statusText, exception);
+                        }
+                    }
+
+                    this._loadFile(rootUrl, onloaddata, undefined, undefined, true, onInternalError);
+                }
+            }
+            else {
+                throw new Error("Cannot load cubemap: non-ENV format not supported.");
+            }
+
+            this._internalTexturesCache.push(texture);
+
+            return texture;
+        }
+
         // Returns a NativeFilter.XXXX value.
         private _getSamplingFilter(samplingMode: number): number {
             switch (samplingMode) {

+ 23 - 13
src/Tools/babylon.environmentTextureTools.ts

@@ -43,7 +43,7 @@ module BABYLON {
      * Defines the specular data enclosed in the file.
      * This corresponds to the version 1 of the data.
      */
-    interface EnvironmentTextureSpecularInfoV1 {
+    export interface EnvironmentTextureSpecularInfoV1 {
         /**
          * Defines where the specular Payload is located. It is a runtime value only not stored in the file.
          */
@@ -305,14 +305,7 @@ module BABYLON {
             } as any;
         }
 
-        /**
-         * Uploads the texture info contained in the env file to the GPU.
-         * @param texture defines the internal texture to upload to
-         * @param arrayBuffer defines the buffer cotaining the data to load
-         * @param info defines the texture info retrieved through the GetEnvInfo method
-         * @returns a promise
-         */
-        public static UploadEnvLevelsAsync(texture: InternalTexture, arrayBuffer: any, info: EnvironmentTextureInfo): Promise<void> {
+        public static CreateImageDataArrayBufferViews(arrayBuffer: any, info: EnvironmentTextureInfo): Array<Array<ArrayBufferView>> {
             if (info.version !== 1) {
                 throw new Error(`Unsupported babylon environment map version "${info.version}"`);
             }
@@ -320,18 +313,15 @@ module BABYLON {
             let specularInfo = info.specular as EnvironmentTextureSpecularInfoV1;
             if (!specularInfo) {
                 // Nothing else parsed so far
-                return Promise.resolve();
+                throw new Error(`Cannot create environment texture without specular info v1`);
             }
 
-            // Double checks the enclosed info
             let mipmapsCount = Scalar.Log2(info.width);
             mipmapsCount = Math.round(mipmapsCount) + 1;
             if (specularInfo.mipmaps.length !== 6 * mipmapsCount) {
                 throw new Error(`Unsupported specular mipmaps number "${specularInfo.mipmaps.length}"`);
             }
 
-            texture._lodGenerationScale = specularInfo.lodGenerationScale;
-
             const imageData = new Array<Array<ArrayBufferView>>(mipmapsCount);
             for (let i = 0; i < mipmapsCount; i++) {
                 imageData[i] = new Array<ArrayBufferView>(6);
@@ -341,6 +331,26 @@ module BABYLON {
                 }
             }
 
+            return imageData;
+        }
+
+        /**
+         * Uploads the texture info contained in the env file to the GPU.
+         * @param texture defines the internal texture to upload to
+         * @param arrayBuffer defines the buffer cotaining the data to load
+         * @param info defines the texture info retrieved through the GetEnvInfo method
+         * @returns a promise
+         */
+        public static UploadEnvLevelsAsync(texture: InternalTexture, arrayBuffer: any, info: EnvironmentTextureInfo): Promise<void> {
+            let specularInfo = info.specular as EnvironmentTextureSpecularInfoV1;
+            if (!specularInfo) {
+                // Nothing else parsed so far
+                return Promise.resolve();
+            }
+            texture._lodGenerationScale = specularInfo.lodGenerationScale;
+
+            const imageData = EnvironmentTextureTools.CreateImageDataArrayBufferViews(arrayBuffer, info);
+
             return EnvironmentTextureTools.UploadLevelsAsync(texture, imageData);
         }