浏览代码

Started to experimenting with tangent-less bump mapping by Morten Mikkelsen.

It requires OES_standard_derivatives extension and benefits a lot from having EXT_texture_filter_anisotropic extension (set high anisotropy for bump texture).

Added new LeePerry example and modified materials2 WebGL example to show this in action.

Still quite a few things not solved:

- why there are seams at LeePerry model? (I suspect mesh discontinuities? this method is supposed to have less seams problems than normal mapping :S)
- it will crash without color map due to missing UVs, need to solve better UV initialization / sharing of shader parameters between chunks
- didn't check impact on environment mapping yet
- maybe also Lambert could be extended
- it should be somehow possible to precompute derivative maps and use this instead of "dHdxy_fwd()" method
alteredq 13 年之前
父节点
当前提交
f390c95562

文件差异内容过多而无法显示
+ 9 - 8
build/Three.js


+ 7 - 7
build/custom/ThreeCanvas.js

@@ -194,13 +194,13 @@ THREE.MeshLambertMaterial=function(a){THREE.Material.call(this);this.color=new T
 this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=false;this.setValues(a)};THREE.MeshLambertMaterial.prototype=Object.create(THREE.Material.prototype);
 THREE.MeshLambertMaterial.prototype.clone=function(){var a=new THREE.MeshLambertMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=
 this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a};
-THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.specular=new THREE.Color(1118481);this.shininess=30;this.wrapAround=this.perPixel=this.metal=false;this.wrapRGB=new THREE.Vector3(1,1,1);this.envMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=0.98;this.fog=true;this.shading=THREE.SmoothShading;this.wireframe=false;
-this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=false;this.setValues(a)};THREE.MeshPhongMaterial.prototype=Object.create(THREE.Material.prototype);
-THREE.MeshPhongMaterial.prototype.clone=function(){var a=new THREE.MeshPhongMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.specular.copy(this.specular);a.shininess=this.shininess;a.metal=this.metal;a.perPixel=this.perPixel;a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=
-this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a};THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.wireframe=false;this.wireframeLinewidth=1;this.setValues(a)};
-THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.shading=THREE.FlatShading;this.wireframe=false;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype);
-THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(){};THREE.MeshFaceMaterial.prototype.clone=function(){return new THREE.MeshFaceMaterial};
-THREE.ParticleBasicMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.map=null;this.size=1;this.sizeAttenuation=true;this.vertexColors=false;this.fog=true;this.setValues(a)};THREE.ParticleBasicMaterial.prototype=Object.create(THREE.Material.prototype);
+THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.specular=new THREE.Color(1118481);this.shininess=30;this.wrapAround=this.perPixel=this.metal=false;this.wrapRGB=new THREE.Vector3(1,1,1);this.bumpMap=this.lightMap=this.map=null;this.bumpScale=1;this.envMap=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=0.98;this.fog=true;this.shading=THREE.SmoothShading;
+this.wireframe=false;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=false;this.setValues(a)};THREE.MeshPhongMaterial.prototype=Object.create(THREE.Material.prototype);
+THREE.MeshPhongMaterial.prototype.clone=function(){var a=new THREE.MeshPhongMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.specular.copy(this.specular);a.shininess=this.shininess;a.metal=this.metal;a.perPixel=this.perPixel;a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.bumpMap=this.bumpMap;a.bumpScale=this.bumpScale;a.envMap=this.envMap;a.combine=this.combine;
+a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a};
+THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.wireframe=false;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};
+THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.shading=THREE.FlatShading;this.wireframe=false;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(){};
+THREE.MeshFaceMaterial.prototype.clone=function(){return new THREE.MeshFaceMaterial};THREE.ParticleBasicMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.map=null;this.size=1;this.sizeAttenuation=true;this.vertexColors=false;this.fog=true;this.setValues(a)};THREE.ParticleBasicMaterial.prototype=Object.create(THREE.Material.prototype);
 THREE.ParticleBasicMaterial.prototype.clone=function(){var a=new THREE.ParticleBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.size=this.size;a.sizeAttenuation=this.sizeAttenuation;a.vertexColors=this.vertexColors;a.fog=this.fog;return a};THREE.ParticleCanvasMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.program=function(){};this.setValues(a)};THREE.ParticleCanvasMaterial.prototype=Object.create(THREE.Material.prototype);
 THREE.ParticleCanvasMaterial.prototype.clone=function(){var a=new THREE.ParticleCanvasMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.program=this.program;return a};
 THREE.Texture=function(a,b,c,d,f,e,g,l,m){this.id=THREE.TextureCount++;this.image=a;this.mapping=b!==void 0?b:new THREE.UVMapping;this.wrapS=c!==void 0?c:THREE.ClampToEdgeWrapping;this.wrapT=d!==void 0?d:THREE.ClampToEdgeWrapping;this.magFilter=f!==void 0?f:THREE.LinearFilter;this.minFilter=e!==void 0?e:THREE.LinearMipMapLinearFilter;this.anisotropy=m!==void 0?m:1;this.format=g!==void 0?g:THREE.RGBAFormat;this.type=l!==void 0?l:THREE.UnsignedByteType;this.offset=new THREE.Vector2(0,0);this.repeat=

文件差异内容过多而无法显示
+ 9 - 8
build/custom/ThreeWebGL.js


二进制
examples/obj/leeperrysmith/Infinite-Level_02_Disp_NoSmoothUV-4096.jpg


+ 15 - 10
examples/webgl_materials2.html

@@ -37,7 +37,7 @@
 				container = document.createElement( 'div' );
 				document.body.appendChild( container );
 
-				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
+				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
 				camera.position.set( 0, 200, 0 );
 
 				scene = new THREE.Scene();
@@ -45,29 +45,34 @@
 				// Materials
 
 				var imgTexture2 = THREE.ImageUtils.loadTexture( "textures/planets/moon_1024.jpg" );
+				imgTexture2.wrapS = imgTexture2.wrapT = THREE.RepeatWrapping;
+				imgTexture2.anisotropy = 16;
 
 				var imgTexture = THREE.ImageUtils.loadTexture( "textures/lava/lavatile.jpg" );
 				imgTexture.repeat.set( 4, 2 );
 				imgTexture.wrapS = imgTexture.wrapT = THREE.RepeatWrapping;
+				imgTexture.anisotropy = 16;
 
-				var shininess = 15, shading = THREE.SmoothShading;
+				var shininess = 50, specular = 0x333333, bumpScale = 1, shading = THREE.SmoothShading;
 
 				var materials = [];
 
-				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, color: 0xffffff, ambient: 0x777777, specular: 0x999999, shininess: shininess, shading: shading } ) );
-				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, color: 0x00ff00, ambient: 0x777777, specular: 0x999999, shininess: shininess, shading: shading } ) );
-				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, color: 0x00ff00, ambient: 0x007700, specular: 0x999999, shininess: shininess, shading: shading } ) );
-				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, color: 0x000000, ambient: 0x00ff00, specular: 0x999999, shininess: shininess, shading: shading } ) );
+				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: 0xffffff, ambient: 0x777777, specular: specular, shininess: shininess, shading: shading, perPixel: true } ) );
+				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: 0x00ff00, ambient: 0x777777, specular: specular, shininess: shininess, shading: shading, perPixel: true } ) );
+				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: 0x00ff00, ambient: 0x007700, specular: specular, shininess: shininess, shading: shading, perPixel: true } ) );
+				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: 0x000000, ambient: 0x00ff00, specular: specular, shininess: shininess, shading: shading, perPixel: true } ) );
 
 				materials.push( new THREE.MeshLambertMaterial( { map: imgTexture, color: 0xffffff, ambient: 0x777777, shading: shading } ) );
 				materials.push( new THREE.MeshLambertMaterial( { map: imgTexture, color: 0xff0000, ambient: 0x777777, shading: shading } ) );
 				materials.push( new THREE.MeshLambertMaterial( { map: imgTexture, color: 0xff0000, ambient: 0x770000, shading: shading } ) );
 				materials.push( new THREE.MeshLambertMaterial( { map: imgTexture, color: 0x000000, ambient: 0xff0000, shading: shading } ) );
 
-				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, color: 0x000000, ambient: 0x000000, specular: 0xffaa00, shininess: shininess, metal: true, shading: shading } ) );
-				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, color: 0x000000, ambient: 0x000000, specular: 0xaaff00, shininess: shininess, metal: true, shading: shading } ) );
-				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, color: 0x000000, ambient: 0x000000, specular: 0x00ffaa, shininess: shininess, metal: true, shading: shading } ) );
-				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, color: 0x000000, ambient: 0x000000, specular: 0x00aaff, shininess: shininess, metal: true, shading: shading } ) );
+				shininess = 15;
+
+				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, bumpMap: imgTexture2, bumpScale: bumpScale, color: 0x000000, ambient: 0x000000, specular: 0xffaa00, shininess: shininess, metal: true, shading: shading, perPixel: true } ) );
+				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, bumpMap: imgTexture2, bumpScale: bumpScale, color: 0x000000, ambient: 0x000000, specular: 0xaaff00, shininess: shininess, metal: true, shading: shading, perPixel: true } ) );
+				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, bumpMap: imgTexture2, bumpScale: bumpScale, color: 0x000000, ambient: 0x000000, specular: 0x00ffaa, shininess: shininess, metal: true, shading: shading, perPixel: true } ) );
+				materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, bumpMap: imgTexture2, bumpScale: bumpScale, color: 0x000000, ambient: 0x000000, specular: 0x00aaff, shininess: shininess, metal: true, shading: shading, perPixel: true } ) );
 
 				// Spheres geometry
 

+ 269 - 0
examples/webgl_materials_bumpmap.html

@@ -0,0 +1,269 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - materials - bump map [Lee Perry-Smith]</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				background:#000;
+				color:#fff;
+				padding:0;
+				margin:0;
+				font-weight: bold;
+				overflow:hidden;
+			}
+
+			a {	color: #ffffff;	}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				color: #ffffff;
+				padding: 5px;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				z-index:1000;
+			}
+
+			#oldie {
+				background:rgb(200,100,0) !important;
+				color:#fff;
+			}
+
+			#vt { display:none }
+			#vt, #vt a { color:orange; }
+			.code { }
+
+		</style>
+	</head>
+
+	<body>
+		<div id="info">
+			<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - webgl bump mapping without tangents using <a href="http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html">Morten Mikkelsen's</a> method -
+			<a href="http://www.ir-ltd.net/infinite-3d-head-scan-released/" target="_blank">Lee Perry-Smith</a> head
+		</div>
+
+		<script src="../build/Three.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/Stats.js"></script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var statsEnabled = true;
+
+			var container, stats, loader;
+
+			var camera, scene, renderer;
+
+			var mesh;
+
+			var directionalLight, pointLight, ambientLight, spotLight;
+
+			var mouseX = 0;
+			var mouseY = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				//
+
+				camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera.position.z = 1200;
+
+				scene = new THREE.Scene();
+
+				// LIGHTS
+
+				ambientLight = new THREE.AmbientLight( 0x444444 );
+				scene.add( ambientLight );
+
+				//
+
+				pointLight = new THREE.PointLight( 0xffffff, 1.5, 1000 );
+				pointLight.color.setHSV( 0.05, 0.05, 1 );
+				pointLight.position.set( 0, 0, 600 );
+
+				scene.add( pointLight );
+
+				// shadow for PointLight
+
+				spotLight = new THREE.SpotLight( 0xffffff, 1.5 );
+				spotLight.position.copy( pointLight.position );
+				spotLight.color.setHSV( 0.6, 0.05, 1 );
+				scene.add( spotLight );
+
+				spotLight.position.multiplyScalar( 700 );
+
+				spotLight.castShadow = true;
+				spotLight.onlyShadow = true;
+				//spotLight.shadowCameraVisible = true;
+
+				spotLight.shadowMapWidth = 2048;
+				spotLight.shadowMapHeight = 2048;
+
+				spotLight.shadowCameraNear = 200;
+				spotLight.shadowCameraFar = 1500;
+
+				spotLight.shadowCameraFov = 40;
+
+				spotLight.shadowBias = -0.005;
+				spotLight.shadowDarkness = 0.35;
+
+				//
+
+				directionalLight = new THREE.DirectionalLight( 0xffffff, 1.5 );
+				directionalLight.position.set( 1, -0.5, 1 );
+				directionalLight.color.setHSV( 0.6, 0.05, 1 );
+				scene.add( directionalLight );
+
+				directionalLight.position.multiplyScalar( 500 );
+
+				directionalLight.castShadow = true;
+				//directionalLight.shadowCameraVisible = true;
+
+				directionalLight.shadowMapWidth = 2048;
+				directionalLight.shadowMapHeight = 2048;
+
+				directionalLight.shadowCameraNear = 200;
+				directionalLight.shadowCameraFar = 1500;
+
+				directionalLight.shadowCameraLeft = -500;
+				directionalLight.shadowCameraRight = 500;
+				directionalLight.shadowCameraTop = 500;
+				directionalLight.shadowCameraBottom = -500;
+
+				directionalLight.shadowBias = -0.005;
+				directionalLight.shadowDarkness = 0.35;
+
+
+				var mapHeight = THREE.ImageUtils.loadTexture( "obj/leeperrysmith/Infinite-Level_02_Disp_NoSmoothUV-4096.jpg" );
+				var mapDummy = THREE.ImageUtils.generateDataTexture( 1, 1, new THREE.Color( 0xffffff ) );
+
+				mapHeight.anisotropy = 16;
+
+				var material = new THREE.MeshPhongMaterial( { ambient: 0x555555, color: 0x555555, specular: 0x333333, shininess: 25, perPixel: true, map: mapDummy, bumpMap: mapHeight, bumpScale: 19, metal: false } );
+
+				loader = new THREE.JSONLoader( true );
+				document.body.appendChild( loader.statusDomElement );
+
+				loader.load( "obj/leeperrysmith/LeePerrySmith.js", function( geometry ) { createScene( geometry, 100, material ) } );
+
+				renderer = new THREE.WebGLRenderer( { antialias: true, clearColor: 0x060708, clearAlpha: 1 } );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( renderer.domElement );
+
+				renderer.shadowMapEnabled = true;
+				renderer.shadowMapCullFrontFaces = false;
+
+				//
+
+				renderer.gammaInput = true;
+				renderer.gammaOutput = true;
+				renderer.physicallyBasedShading = true;
+
+				//
+
+				if ( statsEnabled ) {
+
+					stats = new Stats();
+					stats.domElement.style.position = 'absolute';
+					stats.domElement.style.top = '0px';
+					stats.domElement.style.zIndex = 100;
+
+					stats.domElement.children[ 0 ].children[ 0 ].style.color = "#aaa";
+					stats.domElement.children[ 0 ].style.background = "transparent";
+					stats.domElement.children[ 0 ].children[ 1 ].style.display = "none";
+
+					container.appendChild( stats.domElement );
+
+				}
+
+				// EVENTS
+
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function createScene( geometry, scale, material ) {
+
+				geometry.computeTangents();
+
+				mesh = new THREE.Mesh( geometry, material );
+
+				mesh.position.y = - 50;
+				mesh.scale.set( scale, scale, scale );
+
+				mesh.castShadow = true;
+				mesh.receiveShadow = true;
+
+				scene.add( mesh );
+
+				loader.statusDomElement.style.display = "none";
+
+			}
+
+			//
+
+			function onWindowResize( event ) {
+
+				SCREEN_WIDTH = window.innerWidth;
+				SCREEN_HEIGHT = window.innerHeight;
+
+				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
+
+				camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
+				camera.updateProjectionMatrix();
+
+			}
+
+			function onDocumentMouseMove(event) {
+
+				mouseX = ( event.clientX - windowHalfX ) * 10;
+				mouseY = ( event.clientY - windowHalfY ) * 10;
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				if ( statsEnabled ) stats.update();
+
+			}
+
+			function render() {
+
+				var ry = mouseX * 0.0003, rx = mouseY * 0.0003;
+
+				if ( mesh ) {
+
+					mesh.rotation.y = ry;
+					mesh.rotation.x = rx;
+
+				}
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 9 - 0
src/materials/MeshPhongMaterial.js

@@ -14,6 +14,9 @@
  *
  *  lightMap: new THREE.Texture( <Image> ),
  *
+ *  bumpMap: new THREE.Texture( <Image> ),
+ *  bumpScale: <float>,
+ *
  *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
  *  combine: THREE.Multiply,
  *  reflectivity: <float>,
@@ -56,6 +59,9 @@ THREE.MeshPhongMaterial = function ( parameters ) {
 
 	this.lightMap = null;
 
+	this.bumpMap = null;
+	this.bumpScale = 1;
+
 	this.envMap = null;
 	this.combine = THREE.MultiplyOperation;
 	this.reflectivity = 1;
@@ -104,6 +110,9 @@ THREE.MeshPhongMaterial.prototype.clone = function () {
 
 	material.lightMap = this.lightMap;
 
+	material.bumpMap = this.bumpMap;
+	material.bumpScale= this.bumpScale;
+
 	material.envMap = this.envMap;
 	material.combine = this.combine;
 	material.reflectivity = this.reflectivity;

+ 11 - 1
src/renderers/WebGLRenderer.js

@@ -928,7 +928,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		// material must use some texture to require uvs
 
-		if ( material.map || material.lightMap || material instanceof THREE.ShaderMaterial ) {
+		if ( material.map || material.lightMap || material.bumpMap || material instanceof THREE.ShaderMaterial ) {
 
 			return true;
 
@@ -4646,6 +4646,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			map: !!material.map,
 			envMap: !!material.envMap,
 			lightMap: !!material.lightMap,
+			bumpMap: !!material.bumpMap,
 
 			vertexColors: material.vertexColors,
 
@@ -4993,6 +4994,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 		}
 
 		uniforms.lightMap.texture = material.lightMap;
+		uniforms.bumpMap.texture = material.bumpMap;
+
+		if ( material.bumpMap ) {
+
+			uniforms.bumpScale.value = material.bumpScale;
+
+		}
 
 		uniforms.envMap.texture = material.envMap;
 		uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1;
@@ -5837,6 +5845,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			parameters.map ? "#define USE_MAP" : "",
 			parameters.envMap ? "#define USE_ENVMAP" : "",
 			parameters.lightMap ? "#define USE_LIGHTMAP" : "",
+			parameters.bumpMap ? "#define USE_BUMPMAP" : "",
 			parameters.vertexColors ? "#define USE_COLOR" : "",
 
 			parameters.skinning ? "#define USE_SKINNING" : "",
@@ -5935,6 +5944,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			parameters.map ? "#define USE_MAP" : "",
 			parameters.envMap ? "#define USE_ENVMAP" : "",
 			parameters.lightMap ? "#define USE_LIGHTMAP" : "",
+			parameters.bumpMap ? "#define USE_BUMPMAP" : "",
 			parameters.vertexColors ? "#define USE_COLOR" : "",
 
 			parameters.metal ? "#define METAL" : "",

+ 59 - 0
src/renderers/WebGLShaders.js

@@ -260,6 +260,55 @@ THREE.ShaderChunk = {
 
 	].join("\n"),
 
+	// BUMP MAP
+
+	bumpmap_pars_fragment: [
+
+		"#ifdef USE_BUMPMAP",
+
+			"#extension GL_OES_standard_derivatives : enable",
+
+			"uniform sampler2D bumpMap;",
+			"uniform float bumpScale;",
+
+			// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen
+			//	http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html
+
+			// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
+
+			"vec2 dHdxy_fwd() {",
+
+				"vec2 dSTdx = dFdx( vUv );",
+				"vec2 dSTdy = dFdy( vUv );",
+
+				"float Hll = bumpScale * texture2D( bumpMap, vUv ).x;",
+				"float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;",
+				"float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;",
+
+				"return vec2( dBx, dBy );",
+
+			"}",
+
+			"vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {",
+
+				"vec3 vSigmaX = dFdx( surf_pos );",
+				"vec3 vSigmaY = dFdy( surf_pos );",
+				"vec3 vN = surf_norm;",		// normalized
+
+				"vec3 R1 = cross( vSigmaY, vN );",
+				"vec3 R2 = cross( vN, vSigmaX );",
+
+				"float fDet = dot( vSigmaX, R1 );",
+
+				"vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );",
+				"return normalize( abs( fDet ) * surf_norm - vGrad );",
+
+			"}",
+
+		"#endif"
+
+	].join("\n"),
+
 	// LIGHTS LAMBERT
 
 	lights_lambert_pars_vertex: [
@@ -642,6 +691,12 @@ THREE.ShaderChunk = {
 
 		"#endif",
 
+		"#ifdef USE_BUMPMAP",
+
+			"normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );",
+
+		"#endif",
+
 		"#if MAX_POINT_LIGHTS > 0",
 
 			"vec3 pointDiffuse  = vec3( 0.0 );",
@@ -1487,6 +1542,9 @@ THREE.UniformsLib = {
 
 		"lightMap" : { type: "t", value: 2, texture: null },
 
+		"bumpMap" : { type: "t", value: 3, texture: null },
+		"bumpScale" : { type: "f", value: 1 },
+
 		"envMap" : { type: "t", value: 1, texture: null },
 		"flipEnvMap" : { type: "f", value: -1 },
 		"useRefract" : { type: "i", value: 0 },
@@ -1912,6 +1970,7 @@ THREE.ShaderLib = {
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
+			THREE.ShaderChunk[ "bumpmap_pars_fragment" ],
 
 			"void main() {",
 

部分文件因为文件数量过多而无法显示