Browse Source

Merge pull request #3706 from mlimper/object-space-normal-maps

Object Space Normal Maps
David Catuhe 7 years ago
parent
commit
5aeda70660

+ 17 - 10
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -57,6 +57,7 @@
         public TANGENT = false;
         public BUMP = false;
         public BUMPDIRECTUV = 0;
+        public OBJECTSPACE_NORMALMAP = false;
         public PARALLAX = false;
         public PARALLAXOCCLUSION = false;
         public NORMALXYSCALE = true;
@@ -387,6 +388,11 @@
         protected _useRadianceOverAlpha = true;
 
         /**
+         * Allows using an object space normal map (instead of tangent space).
+         */
+        protected _useObjectSpaceNormalMap = false;
+
+        /**
          * Allows using the bump map in parallax mode.
          */
         protected _useParallax = false;
@@ -932,7 +938,7 @@
                 "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vReflectionPosition", "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", 
                 "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                 "mBones",
-                "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "normalMatrix", "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
                 "vLightingIntensity",
                 "logarithmicDepthConstant",
                 "vSphericalX", "vSphericalY", "vSphericalZ",
@@ -1139,9 +1145,11 @@
                         else {
                             defines.PARALLAX = false;
                         }
+                        
+                        defines.OBJECTSPACE_NORMALMAP = this._useObjectSpaceNormalMap;
                     } else {
                         defines.BUMP = false;
-                    }
+                    }                
 
                     var refractionTexture = this._getRefractionTexture();
                     if (refractionTexture && StandardMaterial.RefractionTextureEnabled) {
@@ -1299,14 +1307,6 @@
         }
 
         /**
-         * Binds to the world matrix.
-         * @param world - The world matrix.
-         */
-        public bindOnlyWorldMatrix(world: Matrix): void {
-            this._activeEffect.setMatrix("world", world);
-        }
-
-        /**
          * Binds the submesh data.
          * @param world - The world matrix.
          * @param mesh - The BJS mesh.
@@ -1331,6 +1331,13 @@
             // Matrices
             this.bindOnlyWorldMatrix(world);
 
+            // Normal Matrix
+            if (defines.OBJECTSPACE_NORMALMAP)
+            {
+                world.toNormalMatrix(this._normalMatrix);
+                this.bindOnlyNormalMatrix(this._normalMatrix);                
+            }
+
             let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
 
             // Bones

+ 7 - 0
src/Materials/PBR/babylon.pbrMaterial.ts

@@ -358,6 +358,13 @@
         public useRadianceOverAlpha = true;
 
         /**
+         * Allows using an object space normal map (instead of tangent space).
+         */
+        @serialize()
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useObjectSpaceNormalMap = false;
+        
+        /**
          * Allows using the bump map in parallax mode.
          */
         @serialize()

+ 16 - 0
src/Materials/babylon.pushMaterial.ts

@@ -3,6 +3,8 @@
 
         protected _activeEffect: Effect;
 
+        protected _normalMatrix : Matrix = new Matrix();
+
         constructor(name: string, scene: Scene) {
             super(name, scene);
             this.storeEffectOnSubMeshes = true;
@@ -24,10 +26,24 @@
             return this.isReadyForSubMesh(mesh, mesh.subMeshes[0], useInstances);
         }
 
+         /**
+         * Binds the given world matrix to the active effect
+         * 
+         * @param world the matrix to bind
+         */
         public bindOnlyWorldMatrix(world: Matrix): void {
             this._activeEffect.setMatrix("world", world);
         }
 
+        /**
+         * Binds the given normal matrix to the active effect
+         * 
+         * @param normalMatrix the matrix to bind
+         */
+        public bindOnlyNormalMatrix(normalMatrix: Matrix): void {                        
+            this._activeEffect.setMatrix("normalMatrix", normalMatrix);
+        }
+
         public bind(world: Matrix, mesh?: Mesh): void {
             if (!mesh) {
                 return;

+ 20 - 2
src/Materials/babylon.standardMaterial.ts

@@ -48,6 +48,7 @@ module BABYLON {
         public REFLECTIONFRESNELFROMSPECULAR = false;
         public LIGHTMAP = false;
         public LIGHTMAPDIRECTUV = 0;
+        public OBJECTSPACE_NORMALMAP = false;
         public USELIGHTMAPASSHADOWMAP = false;
         public REFLECTIONMAP_3D = false;
         public REFLECTIONMAP_SPHERICAL = false;
@@ -198,6 +199,14 @@ module BABYLON {
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         public disableLighting: boolean;
 
+        @serialize("useObjectSpaceNormalMap")
+        private _useObjectSpaceNormalMap = false;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        /**
+         * Allows using an object space normal map (instead of tangent space).
+         */
+        public useObjectSpaceNormalMap: boolean;
+
         @serialize("useParallax")
         private _useParallax = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
@@ -667,6 +676,8 @@ module BABYLON {
                             defines.PARALLAX = this._useParallax;
                             defines.PARALLAXOCCLUSION = this._useParallaxOcclusion;
                         }
+
+                        defines.OBJECTSPACE_NORMALMAP = this._useObjectSpaceNormalMap;
                     } else {
                         defines.BUMP = false;
                     }
@@ -849,7 +860,7 @@ module BABYLON {
                     "vFogInfos", "vFogColor", "pointSize",
                     "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                     "mBones",
-                    "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                    "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "normalMatrix", "lightmapMatrix", "refractionMatrix",
                     "diffuseLeftColor", "diffuseRightColor", "opacityParts", "reflectionLeftColor", "reflectionRightColor", "emissiveLeftColor", "emissiveRightColor", "refractionLeftColor", "refractionRightColor",
                     "vReflectionPosition", "vReflectionSize",
                     "logarithmicDepthConstant", "vTangentSpaceParams"
@@ -973,6 +984,13 @@ module BABYLON {
             // Matrices        
             this.bindOnlyWorldMatrix(world);
 
+            // Normal Matrix
+            if (defines.OBJECTSPACE_NORMALMAP)
+            {
+                world.toNormalMatrix(this._normalMatrix);
+                this.bindOnlyNormalMatrix(this._normalMatrix);               
+            }
+
             let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
 
             // Bones
@@ -1160,7 +1178,7 @@ module BABYLON {
                 // View
                 if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE || this._reflectionTexture || this._refractionTexture) {
                     this.bindView(effect);
-                }
+                }              
 
                 // Fog
                 MaterialHelper.BindFogParameters(scene, mesh, effect);

+ 17 - 0
src/Math/babylon.math.ts

@@ -3894,6 +3894,22 @@
 
             return true;
         }
+
+        /**
+         * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).  
+         * @param ref matrix to store the result
+         */
+        public toNormalMatrix(ref : Matrix): void {            
+            this.invertToRef(ref)
+            ref.transpose();
+            var m = ref.m;
+            Matrix.FromValuesToRef(
+                m[0], m[1], m[2],  0,
+                m[4], m[5], m[6],  0,
+                m[8], m[9], m[10], 0,
+                0,    0,    0,     1, ref);
+        }
+
         /**
          * Returns a new Matrix as the extracted rotation matrix from the current one.  
          */
@@ -3902,6 +3918,7 @@
             this.getRotationMatrixToRef(result);
             return result;
         }
+       
         /**
          * Extracts the rotation matrix from the current one and sets it as the passed "result".  
          * Returns the current Matrix.  

+ 5 - 0
src/Shaders/ShadersInclude/bumpFragment.fx

@@ -25,5 +25,10 @@
 #endif
 
 #ifdef BUMP
+#ifdef OBJECTSPACE_NORMALMAP
+	normalW = normalize(texture2D(bumpSampler, vBumpUV).xyz  * 2.0 - 1.0);
+	normalW = normalize(mat3(normalMatrix) * normalW);	
+#else
 	normalW = perturbNormal(TBN, vBumpUV + uvOffset);
+#endif
 #endif

+ 4 - 0
src/Shaders/ShadersInclude/bumpFragmentFunctions.fx

@@ -11,6 +11,10 @@
 	varying mat3 vTBN;
 #endif
 
+#ifdef OBJECTSPACE_NORMALMAP
+uniform mat4 normalMatrix;
+#endif
+
 	// Thanks to http://www.thetenthplanet.de/archives/1180
 	mat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv)
 	{