Sebastien Vandenberghe 9 роки тому
батько
коміт
4667beeb71

+ 16 - 2
materialsLibrary/materials/pbr/babylon.pbrMaterial.ts

@@ -91,6 +91,8 @@ module BABYLON {
         public LODBASEDMICROSFURACE = false;
         public USEPHYSICALLIGHTFALLOFF = false;
         public RADIANCEOVERALPHA = false;
+        public USEPMREMREFLECTION = false;
+        public USEPMREMREFRACTION = false;
 
         constructor() {
             super();
@@ -517,6 +519,10 @@ module BABYLON {
                             if (this.reflectionTexture instanceof HDRCubeTexture && (<HDRCubeTexture>this.reflectionTexture)) {
                                 this._defines.USESPHERICALFROMREFLECTIONMAP = true;
                                 needNormals = true;
+                                
+                                if ((<HDRCubeTexture>this.reflectionTexture).isPMREM) {
+                                    this._defines.USEPMREMREFLECTION = true;
+                                }
                             }
                         }
                     }
@@ -574,6 +580,10 @@ module BABYLON {
                         }
                         if (this.refractionTexture instanceof HDRCubeTexture) {
                             this._defines.REFRACTIONMAPINLINEARSPACE = true;
+                            
+                            if ((<HDRCubeTexture>this.refractionTexture).isPMREM) {
+                                this._defines.USEPMREMREFRACTION = true;
+                            }
                         }
                     }
                 }
@@ -712,6 +722,10 @@ module BABYLON {
                 if (this._defines.REFLECTION) {
                     fallbacks.addFallback(0, "REFLECTION");
                 }
+                
+                if (this._defines.REFRACTION) {
+                    fallbacks.addFallback(0, "REFRACTION");
+                }
 
                 if (this._defines.REFLECTIVITY) {
                     fallbacks.addFallback(0, "REFLECTIVITY");
@@ -897,7 +911,7 @@ module BABYLON {
                     }
 
                     if (this.reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
-                        this._microsurfaceTextureLods.x = Math.log(this.reflectionTexture.getSize().width) * Math.LOG2E;
+                        this._microsurfaceTextureLods.x = Math.round(Math.log(this.reflectionTexture.getSize().width) * Math.LOG2E);
                         
                         if (this.reflectionTexture.isCube) {
                             this._effect.setTexture("reflectionCubeSampler", this.reflectionTexture);
@@ -968,7 +982,7 @@ module BABYLON {
                     }
 
                     if (this.refractionTexture && StandardMaterial.RefractionTextureEnabled) {
-                        this._microsurfaceTextureLods.y = Math.log(this.refractionTexture.getSize().width) * Math.LOG2E;
+                        this._microsurfaceTextureLods.y = Math.round(Math.log(this.refractionTexture.getSize().width) * Math.LOG2E);
                         
                         var depth = 1.0;
                         if (this.refractionTexture.isCube) {

+ 46 - 3
materialsLibrary/materials/pbr/pbr.fragment.fx

@@ -172,6 +172,14 @@ float getMipMapIndexFromAverageSlope(float maxMipLevel, float alpha)
     return clamp(mip, 0., maxMipLevel);
 }
 
+float getMipMapIndexFromAverageSlopeWithPMREM(float maxMipLevel, float alphaG)
+{
+    float specularPower = clamp(2. / alphaG - 2., 0.000001, 2048.);
+    
+    // Based on CubeMapGen for cosine power with 2048 spec default and 0.25 dropoff 
+    return clamp(- 0.5 * log2(specularPower) + 5.5, 0., maxMipLevel);
+}
+
 // From Microfacet Models for Refraction through Rough Surfaces, Walter et al. 2007
 float smithVisibilityG1_TrowbridgeReitzGGX(float dot, float alphaG)
 {
@@ -1078,10 +1086,15 @@ vec3 surfaceRefractionColor = vec3(0., 0., 0.);
 #endif
         
 #ifdef REFRACTION
-	vec3 refractionVector = normalize(refract(-viewDirectionW, normalW, vRefractionInfos.y));
+	//vec3 refractionVector = normalize(refract(-viewDirectionW, normalW, vRefractionInfos.y));
+    vec3 refractionVector = refract(-viewDirectionW, normalW, vRefractionInfos.y);
     
     #ifdef LODBASEDMICROSFURACE
-        float lodRefraction = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.y, alphaG);
+        #ifdef USEPMREMREFRACTION
+            float lodRefraction = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.y, alphaG);
+        #else
+            float lodRefraction = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.y, alphaG);
+        #endif
     #endif
     
     #ifdef REFRACTIONMAP_3D
@@ -1090,6 +1103,19 @@ vec3 surfaceRefractionColor = vec3(0., 0., 0.);
         if (dot(refractionVector, viewDirectionW) < 1.0)
         {
             #ifdef LODBASEDMICROSFURACE
+                #ifdef USEPMREMREFRACTION
+                    // Empiric Threshold
+                    if (microSurface > 0.5)
+                    {
+                        // Bend to not reach edges.
+                        float scaleRefraction = 1. - exp2(lodRefraction) / exp2(vMicrosurfaceTextureLods.y); // CubemapSize is the size of the base mipmap
+                        float maxRefraction = max(max(abs(refractionVector.x), abs(refractionVector.y)), abs(refractionVector.z));
+                        if (abs(refractionVector.x) != maxRefraction) refractionVector.x *= scaleRefraction;
+                        if (abs(refractionVector.y) != maxRefraction) refractionVector.y *= scaleRefraction;
+                        if (abs(refractionVector.z) != maxRefraction) refractionVector.z *= scaleRefraction;
+                    }
+                #endif
+                
                 surfaceRefractionColor = textureCubeLodEXT(refractionCubeSampler, refractionVector, lodRefraction).rgb * vRefractionInfos.x;
             #else
                 surfaceRefractionColor = textureCube(refractionCubeSampler, refractionVector, bias).rgb * vRefractionInfos.x;
@@ -1124,12 +1150,29 @@ vec3 environmentIrradiance = vReflectionColor.rgb;
     vec3 vReflectionUVW = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
 
     #ifdef LODBASEDMICROSFURACE
-        float lodReflection = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.x, alphaG);
+        #ifdef USEPMREMREFLECTION
+            float lodReflection = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.x, alphaG);
+        #else
+            float lodReflection = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.x, alphaG);
+        #endif
     #endif
     
     #ifdef REFLECTIONMAP_3D
         
         #ifdef LODBASEDMICROSFURACE
+            #ifdef USEPMREMREFLECTION
+                // Empiric Threshold
+                if (microSurface > 0.5)
+                {
+                    // Bend to not reach edges.
+                    float scaleReflection = 1. - exp2(lodReflection) / exp2(vMicrosurfaceTextureLods.x); // CubemapSize is the size of the base mipmap
+                    float maxReflection = max(max(abs(vReflectionUVW.x), abs(vReflectionUVW.y)), abs(vReflectionUVW.z));
+                    if (abs(vReflectionUVW.x) != maxReflection) vReflectionUVW.x *= scaleReflection;
+                    if (abs(vReflectionUVW.y) != maxReflection) vReflectionUVW.y *= scaleReflection;
+                    if (abs(vReflectionUVW.z) != maxReflection) vReflectionUVW.z *= scaleReflection;
+                }
+            #endif
+                
             environmentRadiance = textureCubeLodEXT(reflectionCubeSampler, vReflectionUVW, lodReflection).rgb * vReflectionInfos.x;
         #else
             environmentRadiance = textureCube(reflectionCubeSampler, vReflectionUVW, bias).rgb * vReflectionInfos.x;

+ 3 - 0
materialsLibrary/test/add/addpbr.js

@@ -6,6 +6,9 @@ window.preparePBR = function() {
 	pbr.albedoTexture.vScale = 5;
     
     var hdrTexture = new BABYLON.HDRCubeTexture("textures/hdr/environment.hdr", scene, 512);
+    
+    // Uncomment for PMREM Generation
+    // var hdrTexture = new BABYLON.HDRCubeTexture("textures/hdr/environment.hdr", scene, 128, false, true, false, true);
     pbr.reflectionTexture = hdrTexture;
     pbr.refractionTexture = hdrTexture;
     pbr.linkRefractionWithTransparency = true;

+ 27 - 9
src/Materials/Textures/babylon.hdrcubetexture.ts

@@ -9,19 +9,22 @@ module BABYLON {
         private _extensions: string[];
         private _textureMatrix: Matrix;
         private _size: number;
+        private _usePMREMGenerator: boolean;
 
         private static _facesMapping = [
-            "left",
-            "down",
-            "front",
             "right",
             "up",
+            "front",
+            "left",
+            "down",
             "back"
         ];
 
         public sphericalPolynomial: SphericalPolynomial = null;
+        
+        public isPMREM = false;
 
-        constructor(url: string, scene: Scene, size: number, noMipmap = false, generateHarmonics = true, useInGammaSpace = false) {
+        constructor(url: string, scene: Scene, size: number, noMipmap = false, generateHarmonics = true, useInGammaSpace = false, usePMREMGenerator = false) {
             super(scene);
 
             this.name = url;
@@ -30,6 +33,8 @@ module BABYLON {
             this.hasAlpha = false;
             this._size = size;
             this._useInGammaSpace = useInGammaSpace;
+            this._usePMREMGenerator = usePMREMGenerator;
+            this.isPMREM = usePMREMGenerator;
 
             if (!url) {
                 return;
@@ -106,10 +111,22 @@ module BABYLON {
             }
             
             var mipmapGenerator = null;
-            if (this._noMipmap)
+            if (!this._noMipmap && this._usePMREMGenerator)
             {
-                // TODO. Parameterized num level.
-                mipmapGenerator = new BABYLON.Internals.PMREMGenerator(5);
+                mipmapGenerator = (data: ArrayBufferView[]) => { 
+                    var generator = new BABYLON.Internals.PMREMGenerator(data,
+                        this._size,
+                        this._size,
+                        0,
+                        3,
+                        this.getScene().getEngine().getCaps().textureFloat,
+                        2048,
+                        0.25,
+                        false,
+                        true);
+                        
+                    return generator.filterCubeMap();
+                };
             }
 
             this._texture = (<any>this.getScene().getEngine()).createRawCubeTexture(this.url, this.getScene(), this._size, Engine.TEXTUREFORMAT_RGB, Engine.TEXTURETYPE_FLOAT, this._noMipmap, callback, mipmapGenerator);
@@ -117,7 +134,7 @@ module BABYLON {
 
         public clone(): HDRCubeTexture {
             var newTexture = new HDRCubeTexture(this.url, this.getScene(), this._size, this._noMipmap,
-                this._generateHarmonics, this._useInGammaSpace);
+                this._generateHarmonics, this._useInGammaSpace, this._usePMREMGenerator);
 
             // Base texture
             newTexture.level = this.level;
@@ -151,7 +168,7 @@ module BABYLON {
             var texture = null;
             if (parsedTexture.name && !parsedTexture.isRenderTarget) {
                 texture = new BABYLON.HDRCubeTexture(rootUrl + parsedTexture.name, scene, parsedTexture.size,
-                    texture.generateHarmonics, texture.useInGammaSpace);
+                    texture.generateHarmonics, texture.useInGammaSpace, texture.usePMREMGenerator);
                 texture.name = parsedTexture.name;
                 texture.hasAlpha = parsedTexture.hasAlpha;
                 texture.level = parsedTexture.level;
@@ -174,6 +191,7 @@ module BABYLON {
             serializationObject.coordinatesMode = this.coordinatesMode;
             serializationObject.useInGammaSpace = this._useInGammaSpace;
             serializationObject.generateHarmonics = this._generateHarmonics;
+            serializationObject.usePMREMGenerator = this._usePMREMGenerator;
 
             return serializationObject;
         }

+ 4 - 4
src/Tools/HDR/babylon.tools.cubemaptosphericalpolynomial.ts

@@ -18,10 +18,10 @@ module BABYLON.Internals {
     export class CubeMapToSphericalPolynomialTools {        
 
         private static FileFaces: FileFaceOrientation[] = [
-            new FileFaceOrientation("left", new Vector3(1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, -1, 0)), // +X east
-            new FileFaceOrientation("right", new Vector3(-1, 0, 0), new Vector3(0, 0, 1), new Vector3(0, -1, 0)), // -X west
-            new FileFaceOrientation("down", new Vector3(0, 1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, 1)), // +Y north
-            new FileFaceOrientation("up", new Vector3(0, -1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, -1)), // -Y south
+            new FileFaceOrientation("right", new Vector3(1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, -1, 0)), // +X east
+            new FileFaceOrientation("left", new Vector3(-1, 0, 0), new Vector3(0, 0, 1), new Vector3(0, -1, 0)), // -X west
+            new FileFaceOrientation("up", new Vector3(0, 1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, 1)), // +Y north
+            new FileFaceOrientation("down", new Vector3(0, -1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, -1)), // -Y south
             new FileFaceOrientation("front", new Vector3(0, 0, 1), new Vector3(1, 0, 0), new Vector3(0, -1, 0)), // +Z top
             new FileFaceOrientation("back", new Vector3(0, 0, -1), new Vector3(-1, 0, 0), new Vector3(0, -1, 0))// -Z bottom
         ];

+ 4 - 4
src/Tools/HDR/babylon.tools.panoramaToCubemap.ts

@@ -23,25 +23,25 @@ module BABYLON.Internals {
             new Vector3(1.0, 1.0, 1.0),
             new Vector3(-1.0, 1.0, 1.0)
         ];
-        private static FACE_LEFT = [
+        private static FACE_RIGHT = [
             new Vector3(1.0, -1.0, -1.0),
             new Vector3(1.0, -1.0, 1.0),
             new Vector3(1.0, 1.0, -1.0),
             new Vector3(1.0, 1.0, 1.0)
         ];
-        private static FACE_RIGHT = [
+        private static FACE_LEFT = [
             new Vector3(-1.0, -1.0, 1.0),
             new Vector3(-1.0, -1.0, -1.0),
             new Vector3(-1.0, 1.0, 1.0),
             new Vector3(-1.0, 1.0, -1.0)
         ];
-        private static FACE_UP = [
+        private static FACE_DOWN = [
             new Vector3(-1.0, 1.0, -1.0),
             new Vector3(1.0, 1.0, -1.0),
             new Vector3(-1.0, 1.0, 1.0),
             new Vector3(1.0, 1.0, 1.0)
         ];
-        private static FACE_DOWN = [
+        private static FACE_UP = [
             new Vector3(-1.0, -1.0, 1.0),
             new Vector3(1.0, -1.0, 1.0),
             new Vector3(-1.0, -1.0, -1.0),

Різницю між файлами не показано, бо вона завелика
+ 1183 - 53
src/Tools/HDR/babylon.tools.pmremgenerator.ts


+ 33 - 14
src/babylon.engine.ts

@@ -1950,22 +1950,41 @@
                 gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
                 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
 
-                for (var index = 0; index < facesIndex.length; index++) {
-                    var faceData = rgbeDataArrays[index];
-                    gl.texImage2D(facesIndex[index], 0, internalFormat, width, height, 0, internalFormat, textureType, faceData);
-                }
-
-                if (!noMipmap && isPot && mipmmapGenerator) {
-                    var mipData = mipmmapGenerator(rgbeDataArrays);
-                    for (var level = 1; level <= mipData.length; level++) {
-                        for (var mipFaceIndex = 0; mipFaceIndex < mipData[level - 1].length; mipFaceIndex++) {
-                            var mipSize = Math.pow(2, Math.log(width) * Math.LOG2E - level);
-                            gl.texImage2D(facesIndex[index], level, internalFormat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level - 1][mipFaceIndex]);
+                if (!noMipmap && isPot) {
+                    if (mipmmapGenerator) {
+                        
+                        var arrayTemp: ArrayBufferView[] = [];
+                        // Data are known to be in +X +Y +Z -X -Y -Z
+                        // mipmmapGenerator data is expected to be order in +X -X +Y -Y +Z -Z
+                        arrayTemp.push(rgbeDataArrays[0]); // +X
+                        arrayTemp.push(rgbeDataArrays[3]); // -X
+                        arrayTemp.push(rgbeDataArrays[1]); // +Y
+                        arrayTemp.push(rgbeDataArrays[4]); // -Y
+                        arrayTemp.push(rgbeDataArrays[2]); // +Z
+                        arrayTemp.push(rgbeDataArrays[5]); // -Z
+                        
+                        var mipData = mipmmapGenerator(arrayTemp);
+                        for (var level = 0; level < mipData.length; level++) {
+                            var mipSize = width >> level;
+                            
+                            // mipData is order in +X -X +Y -Y +Z -Z
+                            gl.texImage2D(facesIndex[0], level, internalFormat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][0]);
+                            gl.texImage2D(facesIndex[1], level, internalFormat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][2]);
+                            gl.texImage2D(facesIndex[2], level, internalFormat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][4]);
+                            gl.texImage2D(facesIndex[3], level, internalFormat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][1]);
+                            gl.texImage2D(facesIndex[4], level, internalFormat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][3]);
+                            gl.texImage2D(facesIndex[5], level, internalFormat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][5]);
                         }
                     }
-                }
-                else if (!noMipmap && isPot) {
-                    gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+                    else {
+                        // Data are known to be in +X +Y +Z -X -Y -Z
+                        for (var index = 0; index < facesIndex.length; index++) {
+                            var faceData = rgbeDataArrays[index];
+                            gl.texImage2D(facesIndex[index], 0, internalFormat, width, height, 0, internalFormat, textureType, faceData);
+                        }
+                        
+                        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+                    }
                 }
                 else {
                     noMipmap = true;