sebastien 7 anos atrás
pai
commit
03d421bda4

+ 19 - 6
src/Engine/babylon.engine.ts

@@ -2415,8 +2415,9 @@
          * @param requiredHeight The height of the target to render to
          * @param forceFullscreenViewport Forces the viewport to be the entire texture/screen if true
          * @param depthStencilTexture The depth stencil texture to use to render
+         * @param lodLevel defines le lod level to bind to the frame buffer
          */
-        public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean, depthStencilTexture?: InternalTexture): void {
+        public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean, depthStencilTexture?: InternalTexture, lodLevel = 0): void {
             if (this._currentRenderTarget) {
                 this.unBindFramebuffer(this._currentRenderTarget);
             }
@@ -2427,14 +2428,14 @@
                 if (faceIndex === undefined) {
                     faceIndex = 0;
                 }
-                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, 0);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, lodLevel);
 
                 if (depthStencilTexture) {
                     if (depthStencilTexture._generateStencilBuffer) {
-                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, 0);
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, lodLevel);
                     }
                     else {
-                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, 0);
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, lodLevel);
                     }
                 }
             }
@@ -2442,7 +2443,20 @@
             if (this._cachedViewport && !forceFullscreenViewport) {
                 this.setViewport(this._cachedViewport, requiredWidth, requiredHeight);
             } else {
-                gl.viewport(0, 0, requiredWidth || texture.width, requiredHeight || texture.height);
+                if (!requiredWidth) {
+                    requiredWidth = texture.width;
+                    if (lodLevel) {
+                        requiredWidth = requiredWidth / (2 * lodLevel);
+                    }
+                }
+                if (!requiredHeight) {
+                    requiredHeight = texture.height;
+                    if (lodLevel) {
+                        requiredHeight = requiredHeight / (2 * lodLevel);
+                    }
+                }
+
+                gl.viewport(0, 0, requiredWidth, requiredHeight);
             }
 
             this.wipeCaches();
@@ -5528,7 +5542,6 @@
                 }, undefined, undefined, true, onerror);
             }
             else if (isEnv) {
-                texture._isRGBM = true;
                 this._loadFile(rootUrl, (data) => {
                     data = data as ArrayBuffer;
                     var info = EnvironmentTextureTools.GetEnvInfo(data);

+ 4 - 2
src/PostProcess/babylon.postProcessManager.ts

@@ -88,8 +88,10 @@
          * @param postProcesses An array of post processes to be run.
          * @param targetTexture The target texture to render to.
          * @param forceFullscreenViewport force gl.viewport to be full screen eg. 0,0,textureWidth,textureHeight
+         * @param faceIndex defines the face to render to if a cubemap is defined as the target
+         * @param lodLevel defines which lod of the texture to render to
          */
-        public directRender(postProcesses: PostProcess[], targetTexture: Nullable<InternalTexture> = null, forceFullscreenViewport = false): void {
+        public directRender(postProcesses: PostProcess[], targetTexture: Nullable<InternalTexture> = null, forceFullscreenViewport = false, faceIndex = 0, lodLevel = 0): void {
             var engine = this._scene.getEngine();
 
             for (var index = 0; index < postProcesses.length; index++) {
@@ -97,7 +99,7 @@
                     postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture);
                 } else {
                     if (targetTexture) {
-                        engine.bindFramebuffer(targetTexture, 0, undefined, undefined, forceFullscreenViewport);
+                        engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, forceFullscreenViewport, undefined, lodLevel);
                     } else {
                         engine.restoreDefaultFramebuffer();
                     }

+ 10 - 13
src/Shaders/ShadersInclude/helperFunctions.fx

@@ -77,26 +77,23 @@ float dither(vec2 seed, float varianceAmount) {
 	return dither;
 }
 
-const float rgbmMaxRange = 10.0;
+// Check if configurable value is needed.
+const float rgbmMaxRange = 100.0;
 
 vec4 toRGBM(vec3 color) {
 	vec4 rgbm = vec4(0.);
-	// color *= 1.0 / rgbmMaxRange;
-	// rgbm.a = clamp( max( max( color.r, color.g ), max( color.b, 0.000001 ) ), 0., 1. );
-	// rgbm.a = ceil( rgbm.a * 255.0 ) / 255.0;
-	// rgbm.rgb = color / rgbm.a;
-	// //rgbm.rgb = sqrt(rgbm.rgb);
-	// rgbm.rgb = rgbm.rgb * rgbm.rgb;
-
-	rgbm.rgba = vec4(color.rgb, 0.01);
+	color *= 1.0 / rgbmMaxRange;
+	rgbm.a = clamp( max( max( color.r, color.g ), max( color.b, 0.000001 ) ), 0., 1. );
+	rgbm.a = ceil( rgbm.a * 255.0 ) / 255.0;
+	rgbm.rgb = color / rgbm.a;
 
+	// Helps with png quantization.
+	rgbm.rgb = toGammaSpace(rgbm.rgb);
 	return rgbm;
 }
 
 vec3 fromRGBM(vec4 rgbm) {
-	return rgbm.rgb;
-	rgbm.rgb = sqrt(rgbm.rgb);
-	//rgbm.rgb = rgbm.rgb * rgbm.rgb;
-	
+	// Helps with png quantization.
+	rgbm.rgb = toLinearSpace(rgbm.rgb);
 	return rgbmMaxRange * rgbm.rgb * rgbm.a;
 }

+ 10 - 0
src/Shaders/rgbmDecode.fragment.fx

@@ -0,0 +1,10 @@
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+#include<helperFunctions>
+
+void main(void) 
+{
+	gl_FragColor = vec4(fromRGBM(texture2D(textureSampler, vUV)), 1.0);
+}

+ 90 - 86
src/Tools/babylon.environmentTextureTools.ts

@@ -85,27 +85,26 @@ module BABYLON {
         }
 
         public static CreateEnvTexture(texture: CubeTexture): Nullable<Promise<ArrayBuffer>> {
-            var internalTexture = texture.getInternalTexture();
+            let internalTexture = texture.getInternalTexture();
             if (!internalTexture) {
                 return null;
             }
 
-            var engine = internalTexture.getEngine();
-            var hostingScene = new Scene(engine);
-            var screenshotCanvas = document.createElement('canvas');
+            let engine = internalTexture.getEngine();
+            let hostingScene = new Scene(engine);
 
-            var info: EnvironmentTextureInfo = {
+            let info: EnvironmentTextureInfo = {
                 version: 1,
                 width: internalTexture.width,
                 irradiance: null,
                 specular: null
             };
 
-            var specularTextures: { [key: number]: ArrayBuffer } = { };
-            var promises: Promise<void>[] = [];
+            let specularTextures: { [key: number]: ArrayBuffer } = { };
+            let promises: Promise<void>[] = [];
 
             // All mipmaps
-            var mipmapsCount = Scalar.Log2(internalTexture.width);
+            let mipmapsCount = Scalar.Log2(internalTexture.width);
             mipmapsCount = Math.round(mipmapsCount);
             for (let i = 0; i <= mipmapsCount; i++) {
                 let faceWidth = Math.pow(2, mipmapsCount - i);
@@ -118,73 +117,39 @@ module BABYLON {
                     let textureType = Engine.TEXTURETYPE_FLOAT;
                     let tempTexture = engine.createRawTexture(data, faceWidth, faceWidth, Engine.TEXTUREFORMAT_RGBA, false, false, Texture.NEAREST_SAMPLINGMODE, null, textureType);
 
-                    let rtt = new RenderTargetTexture(
-                        'resized' + i + "_" + face,
-                        faceWidth,
-                        hostingScene,
-                        true,
-                        true,
-                        Engine.TEXTURETYPE_UNSIGNED_INT,
-                        false,
-                        Texture.NEAREST_SAMPLINGMODE,
-                        false
-                    );
-        
                     let promise = new Promise<void>((resolve, reject) => {
-                        //let passPostProcess = new PassPostProcess("rgbmEncode", 1, null, Texture.NEAREST_SAMPLINGMODE, engine, false, Engine.TEXTURETYPE_UNSIGNED_INT);
                         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(() => {
-                            rgbmPostProcess.onApply = function (effect) {
+                            rgbmPostProcess.onApply = (effect) => {
                                 effect._bindTexture("textureSampler", tempTexture);
                             }
             
-                            let internalTexture = rtt.getInternalTexture();
+                            //let internalTexture = rtt.getInternalTexture();
+                            let currentW = engine.getRenderWidth();
+                            let currentH = engine.getRenderHeight();
+                            engine.setSize(faceWidth, faceWidth);
             
                             if (internalTexture) {
-                                hostingScene.postProcessManager.directRender([rgbmPostProcess], internalTexture);
+                                hostingScene.postProcessManager.directRender([rgbmPostProcess], null);
                             }
 
                             //Reading datas from WebGL
-                            let data = engine.readPixels(0, 0, faceWidth, faceWidth);
-
-                            // //To flip image on Y axis.
-                            // for (var i = 0; i < halfHeight; i++) {
-                            //     for (var j = 0; j < numberOfChannelsByLine; j++) {
-                            //         var currentCell = j + i * numberOfChannelsByLine;
-                            //         var targetLine = height - i - 1;
-                            //         var targetCell = j + targetLine * numberOfChannelsByLine;
-
-                            //         var temp = data[currentCell];
-                            //         data[currentCell] = data[targetCell];
-                            //         data[targetCell] = temp;
-                            //     }
-                            // }
-
-                            screenshotCanvas.width = faceWidth;
-                            screenshotCanvas.height = faceWidth;
-                            let context = screenshotCanvas.getContext('2d');
-
-                            if (context) {
-                                // Copy the pixels to a 2D canvas
-                                let imageData = context.createImageData(faceWidth, faceWidth);
-                                let castData = <any>(imageData.data);
-                                castData.set(data);
-                                context.putImageData(imageData, 0, 0);
-
-                                screenshotCanvas.toBlob((blob) => {
-                                    var url = window.URL.createObjectURL(blob);
-
-                                    var 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 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 = function(event) {
+                                    fileReader.onload = (event) => {
                                         let arrayBuffer = event.target!.result as ArrayBuffer;
                                         specularTextures[i * 6 + face] = arrayBuffer;
                                         resolve();
@@ -192,6 +157,7 @@ module BABYLON {
                                     fileReader.readAsArrayBuffer(blob!);
                                 });
                             }
+                            engine.setSize(currentW, currentH);
                         });
                     });
                     promises.push(promise);
@@ -245,7 +211,7 @@ module BABYLON {
 
                 for (let i = 0; i <= mipmapsCount; i++) {
                     for (let face = 0; face < 6; face++) {
-                        var dataBuffer = specularTextures[i * 6 + face];
+                        let dataBuffer = specularTextures[i * 6 + face];
                         finalBufferView.set(new Uint8Array(dataBuffer), pos);
                         pos += dataBuffer.byteLength;
                     }
@@ -255,37 +221,52 @@ module BABYLON {
             });
         }
 
-        public static UploadLevelsAsync(texture: InternalTexture, arrayBuffer: any, info: EnvironmentTextureInfo): Promise<void[]> {
+        public static UploadLevelsAsync(texture: InternalTexture, arrayBuffer: any, info: EnvironmentTextureInfo): Promise<void> {
             if (info.version !== 1) {
                 Tools.Warn('Unsupported babylon environment map version "' + info.version + '"');
             }
 
-            var specularInfo = info.specular as EnvironmentTextureSpecularInfoV1;
+            let specularInfo = info.specular as EnvironmentTextureSpecularInfoV1;
             if (!specularInfo) {
-                return Promise.resolve([]);
+                return Promise.resolve();
             }
 
-            var mipmapsCount = Scalar.Log2(info.width);
+            let mipmapsCount = Scalar.Log2(info.width);
             mipmapsCount = Math.round(mipmapsCount) + 1;
             if (specularInfo.mipmaps.length !== 6 * mipmapsCount) {
                 Tools.Warn('Unsupported specular mipmaps number "' + specularInfo.mipmaps.length + '"');
             }
 
-            var engine = texture.getEngine();
-            var textureType = Engine.TEXTURETYPE_UNSIGNED_INT;
-            var targetTextureType = Engine.TEXTURETYPE_UNSIGNED_INT;
-            var expandTexture = false;
+            let engine = texture.getEngine();
+            let textureType = Engine.TEXTURETYPE_UNSIGNED_INT;
+            let expandTexture = false;
+            let rgbmPostProcess: Nullable<PostProcess> = null;
+            let cubeRtt: Nullable<InternalTexture> = null;
+
             if (engine.getCaps().textureHalfFloatRender) {
-                targetTextureType = Engine.TEXTURETYPE_HALF_FLOAT;
+                textureType = Engine.TEXTURETYPE_HALF_FLOAT;
                 expandTexture = true;
+                rgbmPostProcess = new PostProcess("rgbmDecode", "rgbmDecode", null, null, 1, null, Texture.NEAREST_SAMPLINGMODE, engine, false, undefined, textureType, undefined, null, false);
+                texture._isRGBM = false;
+                texture.invertY = false;
+                cubeRtt = engine.createRenderTargetCubeTexture(texture.width, {
+                    generateDepthBuffer: false,
+                    generateMipMaps: true,
+                    generateStencilBuffer: false,
+                    samplingMode: Texture.TRILINEAR_SAMPLINGMODE,
+                    type: textureType,
+                    format: Engine.TEXTUREFORMAT_RGBA
+                })
+            }
+            else {
+                texture.invertY = true;
+                texture._isRGBM = true;
             }
             texture.type = textureType;
             texture.format = Engine.TEXTUREFORMAT_RGBA;
-            texture.invertY = false;
-            texture._isRGBM = true;
             texture.samplingMode = Texture.TRILINEAR_SAMPLINGMODE;
 
-            var promises: Promise<void>[] = [];
+            let promises: Promise<void>[] = [];
             // All mipmaps
             for (let i = 0; i < mipmapsCount; i++) {
                 // All faces
@@ -300,8 +281,31 @@ module BABYLON {
                     // Enqueue promise to upload to the texture.
                     let promise = new Promise<void>((resolve, reject) => {;
                         image.onload = () => {
-                            engine._uploadImageToTexture(texture, face, i, image);
-                            resolve();
+                            if (expandTexture) {
+                                let tempTexture = engine.createTexture(null, true, true, null, Texture.NEAREST_SAMPLINGMODE, null,
+                                (message) => {
+                                    reject(message);
+                                },
+                                image);
+
+                                rgbmPostProcess!.getEffect().executeWhenCompiled(() => {
+                                    rgbmPostProcess!.onApply = (effect) => {
+                                        effect._bindTexture("textureSampler", tempTexture);
+                                        // TODO
+                                        if (i) {
+                                            effect.setFloat2("scale", i + 1, i + 1);
+                                        }
+                                    }
+                                    engine.scenes[0].postProcessManager.directRender([rgbmPostProcess!], cubeRtt, true, face, i);
+                                    engine.restoreDefaultFramebuffer();
+                                    tempTexture.dispose();
+                                    resolve();
+                                });
+                            }
+                            else {
+                                engine._uploadImageToTexture(texture, face, i, image);
+                                resolve();
+                            }
                         };
                         image.onerror = (error) => {
                             reject(error);
@@ -311,14 +315,14 @@ module BABYLON {
                 }
             }
 
-            // if (expandTexture) {
-            //     return Promise.all(promises).then(() => {
-            //         return this._expandTexture(texture, targetTextureType);
-            //     });
-            // }
-            // else {
-                return Promise.all(promises);
-            //}
+            return Promise.all(promises).then(() => {
+                if (cubeRtt) {
+                    texture._webGLTexture = cubeRtt._webGLTexture;
+                }
+                if (rgbmPostProcess) {
+                    rgbmPostProcess.dispose();
+                }
+            });
         }
 
         public static UploadPolynomials(texture: InternalTexture, arrayBuffer: any, info: EnvironmentTextureInfo): void {
@@ -326,7 +330,7 @@ module BABYLON {
                 Tools.Warn('Unsupported babylon environment map version "' + info.version + '"');
             }
 
-            var irradianceInfo = info.irradiance as EnvironmentTextureIrradianceInfoV1;
+            let irradianceInfo = info.irradiance as EnvironmentTextureIrradianceInfoV1;
             if (!irradianceInfo) {
                 return;
             }