diff --git a/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js index d3c3d19a66eaa8..24f84589d78d41 100644 --- a/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js @@ -14,8 +14,8 @@ export default /* glsl */` #if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) ) - // Per-Pixel Tangent Space Normal Mapping - // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html + // Normal Mapping Without Precomputed Tangents + // http://www.thetenthplanet.de/archives/1180 vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) { @@ -26,17 +26,18 @@ export default /* glsl */` vec2 st0 = dFdx( vUv.st ); vec2 st1 = dFdy( vUv.st ); - float scale = sign( st1.t * st0.s - st0.t * st1.s ); // we do not care about the magnitude + vec3 N = surf_norm; // normalized - vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale ); - vec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale ); - vec3 N = normalize( surf_norm ); + vec3 q1perp = cross( q1, N ); + vec3 q0perp = cross( N, q0 ); - mat3 tsn = mat3( S, T, N ); + vec3 T = q1perp * st0.x + q0perp * st1.x; + vec3 B = q1perp * st0.y + q0perp * st1.y; - mapN.xy *= faceDirection; + float det = max( dot( T, T ), dot( B, B ) ); + float scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det ); - return normalize( tsn * mapN ); + return normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z ); }