diff --git a/docs/api/materials/MeshPhongMaterial.html b/docs/api/materials/MeshPhongMaterial.html index 2f024e38db597b51da517bb19cc70ff4b555d4db..08c031e2b136fe48688811bbbec705793cfb34d8 100644 --- a/docs/api/materials/MeshPhongMaterial.html +++ b/docs/api/materials/MeshPhongMaterial.html @@ -178,6 +178,13 @@ the way the color is lit. Normal maps do not change the actual shape of the surface, only the lighting.

+

[property:Integer normalMapType]

+

+ The type of normal map.

+ + Options are [page:constant THREE.TangentSpaceNormalMap] (default), and [page:constant THREE.ObjectSpaceNormalMap]. +

+

[property:Vector2 normalScale]

How much the normal map affects the material. Typical ranges are 0-1. diff --git a/docs/api/materials/MeshStandardMaterial.html b/docs/api/materials/MeshStandardMaterial.html index f13d11aa6b8a51658f1ccd16a7858dfc28658bd0..a1aef746ceb963639a934a870e3f17cd4e4455de 100644 --- a/docs/api/materials/MeshStandardMaterial.html +++ b/docs/api/materials/MeshStandardMaterial.html @@ -220,6 +220,13 @@ the way the color is lit. Normal maps do not change the actual shape of the surface, only the lighting.

+

[property:Integer normalMapType]

+

+ The type of normal map.

+ + Options are [page:constant THREE.TangentSpaceNormalMap] (default), and [page:constant THREE.ObjectSpaceNormalMap]. +

+

[property:Vector2 normalScale]

How much the normal map affects the material. Typical ranges are 0-1. diff --git a/src/constants.js b/src/constants.js index 82dc80f4c67ddc30ad7a6f81017ccdd668c0e1d8..85f678827b393bee1430f4dde8dc89ca0ba00ba4 100644 --- a/src/constants.js +++ b/src/constants.js @@ -137,3 +137,5 @@ export var RGBM16Encoding = 3005; export var RGBDEncoding = 3006; export var BasicDepthPacking = 3200; export var RGBADepthPacking = 3201; +export var TangentSpaceNormalMap = 0; +export var ObjectSpaceNormalMap = 1; diff --git a/src/materials/Material.js b/src/materials/Material.js index 3d8f37c3e344c90566fe47b6cb0ddf27ca984f07..f4aa807eee53c2388cb07dc0b0425908edcc0fdc 100644 --- a/src/materials/Material.js +++ b/src/materials/Material.js @@ -1,5 +1,5 @@ import { EventDispatcher } from '../core/EventDispatcher.js'; -import { NoColors, FrontSide, FlatShading, NormalBlending, LessEqualDepth, AddEquation, OneMinusSrcAlphaFactor, SrcAlphaFactor } from '../constants.js'; +import { NoColors, FrontSide, FlatShading, NormalBlending, LessEqualDepth, AddEquation, OneMinusSrcAlphaFactor, SrcAlphaFactor, TangentSpaceNormalMap } from '../constants.js'; import { _Math } from '../math/Math.js'; /** @@ -194,6 +194,7 @@ Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), if ( this.normalMap && this.normalMap.isTexture ) { data.normalMap = this.normalMap.toJSON( meta ).uuid; + if ( this.normalMapType !== TangentSpaceNormalMap ) data.normalMapType = this.normalMapType; data.normalScale = this.normalScale.toArray(); } diff --git a/src/materials/MeshNormalMaterial.js b/src/materials/MeshNormalMaterial.js index 109225f949359d5f7f9ed7360f5caed236c104ba..c95f335dd02ca6a7efff41647ac71cbbe33cf848 100644 --- a/src/materials/MeshNormalMaterial.js +++ b/src/materials/MeshNormalMaterial.js @@ -1,3 +1,4 @@ +import { TangentSpaceNormalMap } from '../constants.js'; import { Material } from './Material.js'; import { Vector2 } from '../math/Vector2.js'; @@ -12,6 +13,7 @@ import { Vector2 } from '../math/Vector2.js'; * bumpScale: , * * normalMap: new THREE.Texture( ), + * normalMapType: THREE.TangentSpaceNormalMap, * normalScale: , * * displacementMap: new THREE.Texture( ), @@ -37,6 +39,7 @@ function MeshNormalMaterial( parameters ) { this.bumpScale = 1; this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; this.normalScale = new Vector2( 1, 1 ); this.displacementMap = null; @@ -70,6 +73,7 @@ MeshNormalMaterial.prototype.copy = function ( source ) { this.bumpScale = source.bumpScale; this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; this.normalScale.copy( source.normalScale ); this.displacementMap = source.displacementMap; diff --git a/src/materials/MeshPhongMaterial.js b/src/materials/MeshPhongMaterial.js index aacf4aa7586a508253ae1867dc25059c8b6bae73..e040b1fd037ec697ad5d9600efcfd9aaaf4447ee 100644 --- a/src/materials/MeshPhongMaterial.js +++ b/src/materials/MeshPhongMaterial.js @@ -1,5 +1,5 @@ +import { MultiplyOperation, TangentSpaceNormalMap } from '../constants.js'; import { Material } from './Material.js'; -import { MultiplyOperation } from '../constants.js'; import { Vector2 } from '../math/Vector2.js'; import { Color } from '../math/Color.js'; @@ -29,6 +29,7 @@ import { Color } from '../math/Color.js'; * bumpScale: , * * normalMap: new THREE.Texture( ), + * normalMapType: THREE.TangentSpaceNormalMap, * normalScale: , * * displacementMap: new THREE.Texture( ), @@ -79,6 +80,7 @@ function MeshPhongMaterial( parameters ) { this.bumpScale = 1; this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; this.normalScale = new Vector2( 1, 1 ); this.displacementMap = null; @@ -136,6 +138,7 @@ MeshPhongMaterial.prototype.copy = function ( source ) { this.bumpScale = source.bumpScale; this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; this.normalScale.copy( source.normalScale ); this.displacementMap = source.displacementMap; diff --git a/src/materials/MeshStandardMaterial.js b/src/materials/MeshStandardMaterial.js index b1ca6d4b8ba3e951566185aa16f390a8f0da78ec..cbbe32dc34d1cfb4a2e6bcf102c708af2978e50e 100644 --- a/src/materials/MeshStandardMaterial.js +++ b/src/materials/MeshStandardMaterial.js @@ -1,3 +1,4 @@ +import { TangentSpaceNormalMap } from '../constants.js'; import { Material } from './Material.js'; import { Vector2 } from '../math/Vector2.js'; import { Color } from '../math/Color.js'; @@ -27,6 +28,7 @@ import { Color } from '../math/Color.js'; * bumpScale: , * * normalMap: new THREE.Texture( ), + * normalMapType: THREE.TangentSpaceNormalMap, * normalScale: , * * displacementMap: new THREE.Texture( ), @@ -81,6 +83,7 @@ function MeshStandardMaterial( parameters ) { this.bumpScale = 1; this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; this.normalScale = new Vector2( 1, 1 ); this.displacementMap = null; @@ -142,6 +145,7 @@ MeshStandardMaterial.prototype.copy = function ( source ) { this.bumpScale = source.bumpScale; this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; this.normalScale.copy( source.normalScale ); this.displacementMap = source.displacementMap; diff --git a/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl b/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl index f3abc7c95b264407925537a18db4c2338d5a1fc9..5339430ae94691656a7fadeb5c226713e9964a78 100644 --- a/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl +++ b/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl @@ -1,6 +1,28 @@ #ifdef USE_NORMALMAP - normal = perturbNormal2Arb( -vViewPosition, normal ); + #ifdef OBJECTSPACE_NORMALMAP + + normal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; // overrides both flatShading and attribute normals + + #ifdef FLIP_SIDED + + normal = - normal; + + #endif + + #ifdef DOUBLE_SIDED + + normal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 ); + + #endif + + normal = normalize( normalMatrix * normal ); + + #else // tangent-space normal map + + normal = perturbNormal2Arb( -vViewPosition, normal ); + + #endif #elif defined( USE_BUMPMAP ) diff --git a/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl index 9f3e6171ebb1ede520e7c08e46b6b60d9db7b4c1..c3470182c4b3eac94e7a08b37025f418e983d963 100644 --- a/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl @@ -3,32 +3,40 @@ uniform sampler2D normalMap; uniform vec2 normalScale; - // Per-Pixel Tangent Space Normal Mapping - // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html + #ifdef OBJECTSPACE_NORMALMAP - vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) { + uniform mat3 normalMatrix; - // Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988 + #else - vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) ); - vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) ); - vec2 st0 = dFdx( vUv.st ); - vec2 st1 = dFdy( vUv.st ); + // Per-Pixel Tangent Space Normal Mapping + // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html - float scale = sign( st1.t * st0.s - st0.t * st1.s ); // we do not care about the magnitude + vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) { - 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 ); - mat3 tsn = mat3( S, T, N ); + // Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988 - vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; + vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) ); + vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) ); + vec2 st0 = dFdx( vUv.st ); + vec2 st1 = dFdy( vUv.st ); - mapN.xy *= normalScale; - mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 ); + float scale = sign( st1.t * st0.s - st0.t * st1.s ); // we do not care about the magnitude - return normalize( tsn * mapN ); + 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 ); + mat3 tsn = mat3( S, T, N ); - } + vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; + + mapN.xy *= normalScale; + mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 ); + + return normalize( tsn * mapN ); + + } + + #endif #endif diff --git a/src/renderers/shaders/ShaderLib/normal_frag.glsl b/src/renderers/shaders/ShaderLib/normal_frag.glsl index 2d8bbe016ad6bc1446e75edfdf425a2bd655f1db..88a2c4331c659e2eddb4588d4c95c4e7f15a394a 100644 --- a/src/renderers/shaders/ShaderLib/normal_frag.glsl +++ b/src/renderers/shaders/ShaderLib/normal_frag.glsl @@ -2,7 +2,7 @@ uniform float opacity; -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) ) varying vec3 vViewPosition; diff --git a/src/renderers/shaders/ShaderLib/normal_vert.glsl b/src/renderers/shaders/ShaderLib/normal_vert.glsl index 034d580c983e2707538aaf32f8ead641b3472989..131edc6a03cf5a16de2113e43377ec0ec9f57331 100644 --- a/src/renderers/shaders/ShaderLib/normal_vert.glsl +++ b/src/renderers/shaders/ShaderLib/normal_vert.glsl @@ -1,6 +1,6 @@ #define NORMAL -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) ) varying vec3 vViewPosition; @@ -41,7 +41,7 @@ void main() { #include #include -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) ) vViewPosition = - mvPosition.xyz; diff --git a/src/renderers/webgl/WebGLProgram.js b/src/renderers/webgl/WebGLProgram.js index b2ffa49f26971b0a689dff5c156deb9baf000706..4757403495009a1b79fab8f22b563cb4d4b828a3 100644 --- a/src/renderers/webgl/WebGLProgram.js +++ b/src/renderers/webgl/WebGLProgram.js @@ -84,7 +84,7 @@ function generateExtensions( extensions, parameters, rendererExtensions ) { extensions = extensions || {}; var chunks = [ - ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || ( parameters.normalMap && ! parameters.objectSpaceNormalMap ) || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', ( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '', ( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '', ( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : '' @@ -349,6 +349,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', + ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', parameters.specularMap ? '#define USE_SPECULARMAP' : '', parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', @@ -455,6 +456,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', + ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', parameters.specularMap ? '#define USE_SPECULARMAP' : '', parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', diff --git a/src/renderers/webgl/WebGLPrograms.js b/src/renderers/webgl/WebGLPrograms.js index 633a3397e7c7a18c453e1d6a052e7b9d136f2075..8c83379f9c3653400654703ac3a59edc168c221a 100644 --- a/src/renderers/webgl/WebGLPrograms.js +++ b/src/renderers/webgl/WebGLPrograms.js @@ -2,7 +2,7 @@ * @author mrdoob / http://mrdoob.com/ */ -import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, GammaEncoding, LinearEncoding } from '../../constants.js'; +import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, GammaEncoding, LinearEncoding, ObjectSpaceNormalMap } from '../../constants.js'; import { WebGLProgram } from './WebGLProgram.js'; function WebGLPrograms( renderer, extensions, capabilities ) { @@ -27,7 +27,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { var parameterNames = [ "precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding", - "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap", + "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "displacementMap", "specularMap", "roughnessMap", "metalnessMap", "gradientMap", "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp", "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", @@ -148,6 +148,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ), bumpMap: !! material.bumpMap, normalMap: !! material.normalMap, + objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, displacementMap: !! material.displacementMap, roughnessMap: !! material.roughnessMap, metalnessMap: !! material.metalnessMap,