Browse Source

Merge pull request #14239 from WestLangley/dev-object_space_normal_map

Support object-space normal maps
Mr.doob 7 years ago
parent
commit
6e89128f1a

+ 7 - 0
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.
 			the way the color is lit. Normal maps do not change the actual shape of the surface, only the lighting.
 		</p>
 		</p>
 
 
+		<h3>[property:Integer normalMapType]</h3>
+		<p>
+			The type of normal map.<br /><br />
+
+			Options are [page:constant THREE.TangentSpaceNormalMap] (default), and [page:constant THREE.ObjectSpaceNormalMap].
+		</p>
+
 		<h3>[property:Vector2 normalScale]</h3>
 		<h3>[property:Vector2 normalScale]</h3>
 		<p>
 		<p>
 			How much the normal map affects the material. Typical ranges are 0-1.
 			How much the normal map affects the material. Typical ranges are 0-1.

+ 7 - 0
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.
 			the way the color is lit. Normal maps do not change the actual shape of the surface, only the lighting.
 		</p>
 		</p>
 
 
+		<h3>[property:Integer normalMapType]</h3>
+		<p>
+			The type of normal map.<br /><br />
+
+			Options are [page:constant THREE.TangentSpaceNormalMap] (default), and [page:constant THREE.ObjectSpaceNormalMap].
+		</p>
+
 		<h3>[property:Vector2 normalScale]</h3>
 		<h3>[property:Vector2 normalScale]</h3>
 		<p>
 		<p>
 			How much the normal map affects the material. Typical ranges are 0-1.
 			How much the normal map affects the material. Typical ranges are 0-1.

+ 2 - 0
src/constants.js

@@ -137,3 +137,5 @@ export var RGBM16Encoding = 3005;
 export var RGBDEncoding = 3006;
 export var RGBDEncoding = 3006;
 export var BasicDepthPacking = 3200;
 export var BasicDepthPacking = 3200;
 export var RGBADepthPacking = 3201;
 export var RGBADepthPacking = 3201;
+export var TangentSpaceNormalMap = 0;
+export var ObjectSpaceNormalMap = 1;

+ 2 - 1
src/materials/Material.js

@@ -1,5 +1,5 @@
 import { EventDispatcher } from '../core/EventDispatcher.js';
 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';
 import { _Math } from '../math/Math.js';
 
 
 /**
 /**
@@ -194,6 +194,7 @@ Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 		if ( this.normalMap && this.normalMap.isTexture ) {
 		if ( this.normalMap && this.normalMap.isTexture ) {
 
 
 			data.normalMap = this.normalMap.toJSON( meta ).uuid;
 			data.normalMap = this.normalMap.toJSON( meta ).uuid;
+			if ( this.normalMapType !== TangentSpaceNormalMap ) data.normalMapType = this.normalMapType;
 			data.normalScale = this.normalScale.toArray();
 			data.normalScale = this.normalScale.toArray();
 
 
 		}
 		}

+ 4 - 0
src/materials/MeshNormalMaterial.js

@@ -1,3 +1,4 @@
+import { TangentSpaceNormalMap } from '../constants.js';
 import { Material } from './Material.js';
 import { Material } from './Material.js';
 import { Vector2 } from '../math/Vector2.js';
 import { Vector2 } from '../math/Vector2.js';
 
 
@@ -12,6 +13,7 @@ import { Vector2 } from '../math/Vector2.js';
  *  bumpScale: <float>,
  *  bumpScale: <float>,
  *
  *
  *  normalMap: new THREE.Texture( <Image> ),
  *  normalMap: new THREE.Texture( <Image> ),
+ *  normalMapType: THREE.TangentSpaceNormalMap,
  *  normalScale: <Vector2>,
  *  normalScale: <Vector2>,
  *
  *
  *  displacementMap: new THREE.Texture( <Image> ),
  *  displacementMap: new THREE.Texture( <Image> ),
@@ -37,6 +39,7 @@ function MeshNormalMaterial( parameters ) {
 	this.bumpScale = 1;
 	this.bumpScale = 1;
 
 
 	this.normalMap = null;
 	this.normalMap = null;
+	this.normalMapType = TangentSpaceNormalMap;
 	this.normalScale = new Vector2( 1, 1 );
 	this.normalScale = new Vector2( 1, 1 );
 
 
 	this.displacementMap = null;
 	this.displacementMap = null;
@@ -70,6 +73,7 @@ MeshNormalMaterial.prototype.copy = function ( source ) {
 	this.bumpScale = source.bumpScale;
 	this.bumpScale = source.bumpScale;
 
 
 	this.normalMap = source.normalMap;
 	this.normalMap = source.normalMap;
+	this.normalMapType = source.normalMapType;
 	this.normalScale.copy( source.normalScale );
 	this.normalScale.copy( source.normalScale );
 
 
 	this.displacementMap = source.displacementMap;
 	this.displacementMap = source.displacementMap;

+ 4 - 1
src/materials/MeshPhongMaterial.js

@@ -1,5 +1,5 @@
+import { MultiplyOperation, TangentSpaceNormalMap } from '../constants.js';
 import { Material } from './Material.js';
 import { Material } from './Material.js';
-import { MultiplyOperation } from '../constants.js';
 import { Vector2 } from '../math/Vector2.js';
 import { Vector2 } from '../math/Vector2.js';
 import { Color } from '../math/Color.js';
 import { Color } from '../math/Color.js';
 
 
@@ -29,6 +29,7 @@ import { Color } from '../math/Color.js';
  *  bumpScale: <float>,
  *  bumpScale: <float>,
  *
  *
  *  normalMap: new THREE.Texture( <Image> ),
  *  normalMap: new THREE.Texture( <Image> ),
+ *  normalMapType: THREE.TangentSpaceNormalMap,
  *  normalScale: <Vector2>,
  *  normalScale: <Vector2>,
  *
  *
  *  displacementMap: new THREE.Texture( <Image> ),
  *  displacementMap: new THREE.Texture( <Image> ),
@@ -79,6 +80,7 @@ function MeshPhongMaterial( parameters ) {
 	this.bumpScale = 1;
 	this.bumpScale = 1;
 
 
 	this.normalMap = null;
 	this.normalMap = null;
+	this.normalMapType = TangentSpaceNormalMap;
 	this.normalScale = new Vector2( 1, 1 );
 	this.normalScale = new Vector2( 1, 1 );
 
 
 	this.displacementMap = null;
 	this.displacementMap = null;
@@ -136,6 +138,7 @@ MeshPhongMaterial.prototype.copy = function ( source ) {
 	this.bumpScale = source.bumpScale;
 	this.bumpScale = source.bumpScale;
 
 
 	this.normalMap = source.normalMap;
 	this.normalMap = source.normalMap;
+	this.normalMapType = source.normalMapType;
 	this.normalScale.copy( source.normalScale );
 	this.normalScale.copy( source.normalScale );
 
 
 	this.displacementMap = source.displacementMap;
 	this.displacementMap = source.displacementMap;

+ 4 - 0
src/materials/MeshStandardMaterial.js

@@ -1,3 +1,4 @@
+import { TangentSpaceNormalMap } from '../constants.js';
 import { Material } from './Material.js';
 import { Material } from './Material.js';
 import { Vector2 } from '../math/Vector2.js';
 import { Vector2 } from '../math/Vector2.js';
 import { Color } from '../math/Color.js';
 import { Color } from '../math/Color.js';
@@ -27,6 +28,7 @@ import { Color } from '../math/Color.js';
  *  bumpScale: <float>,
  *  bumpScale: <float>,
  *
  *
  *  normalMap: new THREE.Texture( <Image> ),
  *  normalMap: new THREE.Texture( <Image> ),
+ *  normalMapType: THREE.TangentSpaceNormalMap,
  *  normalScale: <Vector2>,
  *  normalScale: <Vector2>,
  *
  *
  *  displacementMap: new THREE.Texture( <Image> ),
  *  displacementMap: new THREE.Texture( <Image> ),
@@ -81,6 +83,7 @@ function MeshStandardMaterial( parameters ) {
 	this.bumpScale = 1;
 	this.bumpScale = 1;
 
 
 	this.normalMap = null;
 	this.normalMap = null;
+	this.normalMapType = TangentSpaceNormalMap;
 	this.normalScale = new Vector2( 1, 1 );
 	this.normalScale = new Vector2( 1, 1 );
 
 
 	this.displacementMap = null;
 	this.displacementMap = null;
@@ -142,6 +145,7 @@ MeshStandardMaterial.prototype.copy = function ( source ) {
 	this.bumpScale = source.bumpScale;
 	this.bumpScale = source.bumpScale;
 
 
 	this.normalMap = source.normalMap;
 	this.normalMap = source.normalMap;
+	this.normalMapType = source.normalMapType;
 	this.normalScale.copy( source.normalScale );
 	this.normalScale.copy( source.normalScale );
 
 
 	this.displacementMap = source.displacementMap;
 	this.displacementMap = source.displacementMap;

+ 23 - 1
src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl

@@ -1,6 +1,28 @@
 #ifdef USE_NORMALMAP
 #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 )
 #elif defined( USE_BUMPMAP )
 
 

+ 26 - 18
src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl

@@ -3,32 +3,40 @@
 	uniform sampler2D normalMap;
 	uniform sampler2D normalMap;
 	uniform vec2 normalScale;
 	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
 #endif

+ 1 - 1
src/renderers/shaders/ShaderLib/normal_frag.glsl

@@ -2,7 +2,7 @@
 
 
 uniform float opacity;
 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;
 	varying vec3 vViewPosition;
 
 

+ 2 - 2
src/renderers/shaders/ShaderLib/normal_vert.glsl

@@ -1,6 +1,6 @@
 #define NORMAL
 #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;
 	varying vec3 vViewPosition;
 
 
@@ -41,7 +41,7 @@ void main() {
 	#include <project_vertex>
 	#include <project_vertex>
 	#include <logdepthbuf_vertex>
 	#include <logdepthbuf_vertex>
 
 
-#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;
 	vViewPosition = - mvPosition.xyz;
 
 

+ 3 - 1
src/renderers/webgl/WebGLProgram.js

@@ -84,7 +84,7 @@ function generateExtensions( extensions, parameters, rendererExtensions ) {
 	extensions = extensions || {};
 	extensions = extensions || {};
 
 
 	var chunks = [
 	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.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.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' : ''
 		( 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.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
 			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
 			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
 			parameters.normalMap ? '#define USE_NORMALMAP' : '',
 			parameters.normalMap ? '#define USE_NORMALMAP' : '',
+			( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
 			parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
 			parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
 			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
@@ -455,6 +456,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters
 			parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
 			parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
 			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
 			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
 			parameters.normalMap ? '#define USE_NORMALMAP' : '',
 			parameters.normalMap ? '#define USE_NORMALMAP' : '',
+			( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
 			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
 			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
 			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',

+ 3 - 2
src/renderers/webgl/WebGLPrograms.js

@@ -2,7 +2,7 @@
  * @author mrdoob / http://mrdoob.com/
  * @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';
 import { WebGLProgram } from './WebGLProgram.js';
 
 
 function WebGLPrograms( renderer, extensions, capabilities ) {
 function WebGLPrograms( renderer, extensions, capabilities ) {
@@ -27,7 +27,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 
 
 	var parameterNames = [
 	var parameterNames = [
 		"precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
 		"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",
 		"roughnessMap", "metalnessMap", "gradientMap",
 		"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
 		"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
 		"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
 		"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
@@ -148,6 +148,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 			emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
 			emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
 			bumpMap: !! material.bumpMap,
 			bumpMap: !! material.bumpMap,
 			normalMap: !! material.normalMap,
 			normalMap: !! material.normalMap,
+			objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
 			displacementMap: !! material.displacementMap,
 			displacementMap: !! material.displacementMap,
 			roughnessMap: !! material.roughnessMap,
 			roughnessMap: !! material.roughnessMap,
 			metalnessMap: !! material.metalnessMap,
 			metalnessMap: !! material.metalnessMap,