浏览代码

Merge remote branch 'alteredq/master'

Mr.doob 14 年之前
父节点
当前提交
cee1d4832f

+ 282 - 0
examples/materials_normalmap.html

@@ -0,0 +1,282 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js - webgl normal map</title>
+		<meta charset="utf-8">
+		<style type="text/css">
+			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 {
+				font-family:monospace;
+				font-size:13px;
+				
+				text-align:center;
+				background:rgb(200,100,0);
+				color:#fff;
+				padding:1em;
+				
+				width:475px;
+				margin:5em auto 0;
+				
+				border:solid 2px #fff;
+				border-radius:10px;
+				
+				display:none;
+			}
+			
+			#vt { display:none } 
+			#vt, #vt a { color:orange; }
+			.code { }
+			
+			#log { position:absolute; top:50px; text-align:left; display:block; z-index:100 }
+		</style>
+	</head>
+
+	<body>
+		<pre id="log"></pre>
+		
+		<div id="info">
+			<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - webgl (<span id="description">normal + ao + displacement</span>) map demo. 
+			ninja head from <a href="http://developer.amd.com/archive/gpu/MeshMapper/pages/default.aspx" target="_blank">AMD GPU MeshMapper</a>
+			
+			<div id="vt">displacement mapping needs vertex textures (GPU with Shader Model 3.0)<br/>
+			on Windows use <span class="code">Chrome --use-gl=desktop</span> or Firefox 4<br/>
+			please star this <a href="http://code.google.com/p/chromium/issues/detail?id=52497">Chrome issue</a> to get ANGLE support
+			</div>
+		</div>
+		
+		<center>
+		<div id="oldie">
+			Sorry, your browser doesn't support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">WebGL</a> 
+			and <a href="http://www.whatwg.org/specs/web-workers/current-work/">Web Workers</a>.<br/>
+			<br/>
+			Please try in 
+			<a href="http://www.chromium.org/getting-involved/dev-channel">Chrome 9+</a> / 
+			<a href="http://www.mozilla.com/en-US/firefox/all-beta.html">Firefox 4+</a> / 
+			<a href="http://nightly.webkit.org/">Safari OSX 10.6+</a>
+		</div>
+		</center>
+
+		<script type="text/javascript" src="../build/ThreeExtras.js"></script> 
+		<script type="text/javascript" src="js/Stats.js"></script>
+		
+		<script type="text/javascript">
+
+			if ( !is_browser_compatible() ) {
+			
+				document.getElementById( "oldie" ).style.display = "block";
+				
+			}
+			
+			var statsEnabled = true;
+
+			var container, stats, loader;
+
+			var camera, scene, webglRenderer;
+
+			var mesh, zmesh, lightMesh, geometry;
+			var mesh1, mesh2;
+	
+			var directionalLight, pointLight, ambientLight;
+
+			var mouseX = 0;
+			var mouseY = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			var r = 0.0;
+
+			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+
+			init();
+			setInterval( loop, 1000 / 60 );
+
+			function init() {
+
+				container = document.createElement('div');
+				document.body.appendChild(container);
+
+				camera = new THREE.Camera( 60, window.innerWidth / window.innerHeight, 1, 100000 );
+				camera.projectionMatrix = THREE.Matrix4.makeOrtho( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, -10000, 10000 );
+				camera.position.z = 6200;
+
+				scene = new THREE.Scene();
+
+				// LIGHTS
+
+				ambientLight = new THREE.AmbientLight( 0x111111 );
+				scene.addLight( ambientLight );
+
+				pointLight = new THREE.PointLight( 0xffff55 );
+				pointLight.position.z = 10000;
+				scene.addLight( pointLight );
+
+				directionalLight = new THREE.DirectionalLight( 0xaaaa88 );
+				directionalLight.position.x = 1;
+				directionalLight.position.y = 1;
+				directionalLight.position.z = 0.5;
+				directionalLight.position.normalize();
+				scene.addLight( directionalLight );
+
+				// light representation
+				
+				var sphere = new Sphere( 100, 16, 8, 1 );
+				lightMesh = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( { color:0xffaa00 } ) );
+				lightMesh.position = pointLight.position;
+				lightMesh.scale.x = lightMesh.scale.y = lightMesh.scale.z = 0.05;
+				scene.addObject(lightMesh);
+
+				// common material parameters
+				
+				var ambient = 0x050505, diffuse = 0x555555, specular = 0xaa6600, shininess = 10, scale = 23;
+
+				// normal map shader
+				
+				var fragment_shader = ShaderUtils.lib[ "normal" ].fragment_shader;
+				var vertex_shader = ShaderUtils.lib[ "normal" ].vertex_shader;
+				var uniforms = ShaderUtils.lib[ "normal" ].uniforms;
+
+				uniforms[ "tNormal" ].texture = ImageUtils.loadTexture( "textures/normal/ninja/normal.jpg" );
+				uniforms[ "tAO" ].texture = ImageUtils.loadTexture( "textures/normal/ninja/ao.jpg" );
+				
+				uniforms[ "tDisplacement" ].texture = ImageUtils.loadTexture( "textures/normal/ninja/displacement.jpg" );
+				uniforms[ "uDisplacementBias" ].value = -0.428408 * scale;
+				uniforms[ "uDisplacementScale" ].value = 2.436143 * scale;
+				
+				uniforms[ "uPointLightPos" ].value = pointLight.position;
+				uniforms[ "uPointLightColor" ].value = pointLight.color;
+
+				uniforms[ "uDirLightPos" ].value = directionalLight.position;
+				uniforms[ "uDirLightColor" ].value = directionalLight.color;
+				
+				uniforms[ "uAmbientLightColor" ].value = ambientLight.color;
+				
+				uniforms[ "uDiffuseColor" ].value.setHex( diffuse );
+				uniforms[ "uSpecularColor" ].value.setHex( specular );
+				uniforms[ "uAmbientColor" ].value.setHex( ambient );
+				
+				uniforms[ "uShininess" ].value = shininess;
+
+				var material1 = new THREE.MeshShaderMaterial( { fragment_shader: fragment_shader, 
+															    vertex_shader: vertex_shader, 
+															    uniforms: uniforms
+															  } );
+
+				var material2 = new THREE.MeshPhongMaterial( { color: diffuse, specular: specular, ambient: ambient, shininess: shininess } );
+
+				loader = new THREE.Loader( true );
+				document.body.appendChild( loader.statusDomElement );
+				
+				loader.loadBinary( "obj/ninja/NinjaLo_bin.js", function( geometry ) { createScene( geometry, scale, material1, material2 ) }, "obj/ninja" );
+
+				webglRenderer = new THREE.WebGLRenderer( scene );
+				webglRenderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( webglRenderer.domElement );
+
+				var description = "normal + ao" + ( webglRenderer.supportsVertexTextures() ? " + displacement" : " + <strike>displacement</strike>" );
+				document.getElementById( "description" ).innerHTML = description;
+				document.getElementById( "vt" ).style.display = webglRenderer.supportsVertexTextures() ? "none" : "block";
+				
+				if ( statsEnabled ) {
+
+					stats = new Stats();
+					stats.domElement.style.position = 'absolute';
+					stats.domElement.style.top = '0px';
+					stats.domElement.style.zIndex = 100;
+					container.appendChild( stats.domElement );
+
+				}
+
+			}
+
+			function createScene( geometry, scale, material1, material2 ) {
+				
+				geometry.computeTangents();
+				
+				mesh1 = SceneUtils.addMesh( scene, geometry, scale, -scale * 12, 0, 0, 0,0,0, material1 );
+				mesh2 = SceneUtils.addMesh( scene, geometry, scale,  scale * 12, 0, 0, 0,0,0, material2 );
+				
+				loader.statusDomElement.style.display = "none";
+				
+			}
+			
+			function onDocumentMouseMove(event) {
+
+				mouseX = ( event.clientX - windowHalfX ) * 10;
+				mouseY = ( event.clientY - windowHalfY ) * 10;
+
+			}
+			
+			function loop() {
+
+				var ry = mouseX * 0.0003, rx = mouseY * 0.0003;
+				
+				if( mesh1 ) {
+				
+					mesh1.rotation.y = ry;
+					mesh1.rotation.x = rx;
+					
+				}
+				
+				if( mesh2 ) {
+					
+					mesh2.rotation.y = ry;
+					mesh2.rotation.x = rx;
+					
+				}
+				
+				lightMesh.position.x = 2500 * Math.cos( r );
+				lightMesh.position.z = 2500 * Math.sin( r );
+
+				r += 0.01;
+
+				webglRenderer.render( scene, camera );
+
+				if ( statsEnabled ) stats.update();
+
+			}
+
+			function log( text ) {
+
+				var e = document.getElementById("log");
+				e.innerHTML = text + "<br/>" + e.innerHTML;
+
+			}
+			
+			function is_browser_compatible() {
+				
+				// WebGL support
+				
+				try { var test = new Float32Array(1); } catch(e) { return false; }
+				
+				// Web workers
+				
+				return !!window.Worker;
+			
+			}
+
+		</script>
+
+	</body>
+</html>

+ 7 - 0
examples/obj/ninja/.htaccess

@@ -0,0 +1,7 @@
+<Files *.js>
+SetOutputFilter DEFLATE
+</Files>
+
+<Files *.bin>
+SetOutputFilter DEFLATE
+</Files>

二进制
examples/obj/ninja/NinjaLo_bin.bin


+ 22 - 0
examples/obj/ninja/NinjaLo_bin.js

@@ -0,0 +1,22 @@
+// Converted from: ../../examples/obj/ninja/ninjaHead_Low.obj
+//  vertices: 4485
+//  faces: 4810 
+//  materials: 0
+//
+//  Generated with OBJ -> Three.js converter
+//  http://github.com/alteredq/three.js/blob/master/utils/exporters/convert_obj_threejs_slim.py
+
+
+var model = {
+    'materials': [	{
+	"a_dbg_color" : 0xeeeeee,
+	"a_dbg_index" : 0,
+	"a_dbg_name" : "default"
+	}],
+
+    'buffers': 'NinjaLo_bin.bin',
+
+    'end': (new Date).getTime()
+    }
+    
+postMessage( model );

二进制
examples/textures/normal/ninja/ao.jpg


二进制
examples/textures/normal/ninja/displacement.jpg


+ 2 - 0
examples/textures/normal/ninja/displacement.txt

@@ -0,0 +1,2 @@
+DisplacementMap Scale: 2.436143
+DisplacementMap Bias : -0.428408

二进制
examples/textures/normal/ninja/normal.jpg


+ 117 - 0
src/core/Geometry.js

@@ -12,6 +12,8 @@ THREE.Geometry = function () {
 
 
 	this.geometryChunks = {};
 	this.geometryChunks = {};
 
 
+	this.hasTangents = false;
+	
 };
 };
 
 
 THREE.Geometry.prototype = {
 THREE.Geometry.prototype = {
@@ -167,6 +169,121 @@ THREE.Geometry.prototype = {
 
 
 	},
 	},
 
 
+	computeTangents: function() {
+		
+		// based on http://www.terathon.com/code/tangent.html
+		// tangents go to vertices
+		
+		var f, fl, v, vl, face, uv, vA, vB, vC, uvA, uvB, uvC,
+			x1, x2, y1, y2, z1, z2,
+			s1, s2, t1, t2, r, t, n,
+			tan1 = [], tan2 = [],
+			sdir = new THREE.Vector3(), tdir = new THREE.Vector3(),
+			tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), 
+			n = new THREE.Vector3(), w;
+		
+		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+
+			tan1[ v ] = new THREE.Vector3();
+			tan2[ v ] = new THREE.Vector3();
+
+		}
+		
+		function handleTriangle( context, a, b, c ) {
+			
+			vA = context.vertices[ a ].position;
+			vB = context.vertices[ b ].position;
+			vC = context.vertices[ c ].position;
+			
+			uvA = uv[ 0 ];
+			uvB = uv[ 1 ];
+			uvC = uv[ 2 ];
+			
+			x1 = vB.x - vA.x;
+			x2 = vC.x - vA.x;
+			y1 = vB.y - vA.y;
+			y2 = vC.y - vA.y;
+			z1 = vB.z - vA.z;
+			z2 = vC.z - vA.z;
+
+			s1 = uvB.u - uvA.u;
+			s2 = uvC.u - uvA.u;
+			t1 = uvB.v - uvA.v;
+			t2 = uvC.v - uvA.v;
+
+			r = 1.0 / ( s1 * t2 - s2 * t1 );
+			sdir.set( ( t2 * x1 - t1 * x2 ) * r, 
+					  ( t2 * y1 - t1 * y2 ) * r,
+					  ( t2 * z1 - t1 * z2 ) * r );
+			tdir.set( ( s1 * x2 - s2 * x1 ) * r, 
+					  ( s1 * y2 - s2 * y1 ) * r,
+					  ( s1 * z2 - s2 * z1 ) * r );
+			
+			tan1[ a ].addSelf( sdir );
+			tan1[ b ].addSelf( sdir );
+			tan1[ c ].addSelf( sdir );
+			
+			tan2[ a ].addSelf( tdir );
+			tan2[ b ].addSelf( tdir );
+			tan2[ c ].addSelf( tdir );
+			
+		}
+		
+		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+			
+			face = this.faces[ f ];
+			uv = this.uvs[ f ];
+			
+			if ( face instanceof THREE.Face3 ) {
+				
+				handleTriangle( this, face.a, face.b, face.c );
+				
+				this.vertices[ face.a ].normal.copy( face.vertexNormals[ 0 ] );
+				this.vertices[ face.b ].normal.copy( face.vertexNormals[ 1 ] );
+				this.vertices[ face.c ].normal.copy( face.vertexNormals[ 2 ] );
+				
+				
+			} else if ( face instanceof THREE.Face4 ) {
+				
+				handleTriangle( this, face.a, face.b, face.c );
+				
+				// this messes up everything
+				// quads need to be handled differently
+				//handleTriangle( this, face.a, face.c, face.d );
+
+				this.vertices[ face.a ].normal.copy( face.vertexNormals[ 0 ] );
+				this.vertices[ face.b ].normal.copy( face.vertexNormals[ 1 ] );
+				this.vertices[ face.c ].normal.copy( face.vertexNormals[ 2 ] );
+				this.vertices[ face.d ].normal.copy( face.vertexNormals[ 3 ] );
+				
+			}
+			
+		}
+		
+		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+			
+			n.copy( this.vertices[ v ].normal );
+			t = tan1[ v ];
+			
+			// Gram-Schmidt orthogonalize
+			
+			tmp.copy( t );
+			tmp.subSelf( n.multiplyScalar( n.dot( t ) ) ).normalize();
+			
+			// Calculate handedness
+			
+			tmp2.cross( this.vertices[ v ].normal, t );
+			test = tmp2.dot( tan2[ v ] );
+			w = (test < 0.0) ? -1.0 : 1.0;
+			
+			this.vertices[ v ].tangent.set( tmp.x, tmp.y, tmp.z, w );
+			
+		}
+		
+		this.hasTangents = true;
+		
+	},
+	
 	computeBoundingBox: function () {
 	computeBoundingBox: function () {
 
 
 		if ( this.vertices.length > 0 ) {
 		if ( this.vertices.length > 0 ) {

+ 2 - 0
src/core/Vertex.js

@@ -12,6 +12,8 @@ THREE.Vertex = function ( position, normal ) {
 	this.normalWorld = new THREE.Vector3();
 	this.normalWorld = new THREE.Vector3();
 	this.normalScreen = new THREE.Vector3();
 	this.normalScreen = new THREE.Vector3();
 
 
+	this.tangent = new THREE.Vector4();
+	
 	this.__visible = true;
 	this.__visible = true;
 
 
 }
 }

+ 195 - 0
src/extras/ShaderUtils.js

@@ -62,6 +62,201 @@ var ShaderUtils = {
 			"}"	
 			"}"	
 			].join("\n")
 			].join("\n")
 			
 			
+		},
+		
+		'normal' : {
+			
+		uniforms: {
+		
+		"tNormal":			{ type: "t", value: 2, texture: null },
+		"tAO":				{ type: "t", value: 3, texture: null },
+		
+		"tDisplacement":	 { type: "t", value: 4, texture: null },
+		"uDisplacementBias": { type: "f", value: -0.5 },
+		"uDisplacementScale":{ type: "f", value: 2.5 },
+		
+		"uPointLightPos":	{ type: "v3", value: new THREE.Vector3() },
+		"uPointLightColor":	{ type: "c", value: new THREE.Color( 0xeeeeee ) },
+		
+		"uDirLightPos":		{ type: "v3", value: new THREE.Vector3() },
+		"uDirLightColor":	{ type: "c", value: new THREE.Color( 0xeeeeee ) },
+		
+		"uAmbientLightColor":{ type: "c", value: new THREE.Color( 0x050505 ) },
+		
+		"uDiffuseColor":	{ type: "c", value: new THREE.Color( 0xeeeeee ) },
+		"uSpecularColor":	{ type: "c", value: new THREE.Color( 0x111111 ) },
+		"uAmbientColor":	{ type: "c", value: new THREE.Color( 0x050505 ) },
+		"uShininess":		{ type: "f", value: 30 }
+		
+		},
+		
+		fragment_shader: [
+		
+		"uniform vec3 uDirLightPos;",
+		"uniform vec3 uDirLightColor;",
+
+		"uniform vec3 uPointLightPos;",
+		"uniform vec3 uPointLightColor;",
+
+		"uniform vec3 uAmbientColor;",
+		"uniform vec3 uDiffuseColor;",
+		"uniform vec3 uSpecularColor;",
+		"uniform float uShininess;",
+		
+		"uniform sampler2D tNormal;",
+		"uniform sampler2D tAO;",
+		
+		"varying vec3 vTangent;",
+		"varying vec3 vBinormal;",
+		"varying vec3 vNormal;",
+		"varying vec2 vUv;",
+		
+		"varying vec3 vLightWeighting;",
+		"varying vec3 vPointLightVector;",
+		"varying vec3 vViewPosition;",
+		
+		"void main() {",
+			
+			"vec3 normalTex = normalize( texture2D( tNormal, vUv ).xyz * 2.0 - 1.0 );",
+			"vec3 aoTex = texture2D( tAO, vUv ).xyz;",
+			
+			"mat3 tsb = mat3( vTangent, vBinormal, vNormal );",
+			"vec3 finalNormal = tsb * normalTex;",
+			
+			"vec3 normal = normalize( finalNormal );",
+			"vec3 viewPosition = normalize( vViewPosition );",
+
+			// point light
+
+			"vec4 pointDiffuse  = vec4( 0.0, 0.0, 0.0, 0.0 );",
+			"vec4 pointSpecular = vec4( 0.0, 0.0, 0.0, 0.0 );",
+
+			"vec3 pointVector = normalize( vPointLightVector );",
+			"vec3 pointHalfVector = normalize( vPointLightVector + vViewPosition );",
+
+			"float pointDotNormalHalf = dot( normal, pointHalfVector );",
+			"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
+
+			"float pointSpecularWeight = 0.0;",
+			"if ( pointDotNormalHalf >= 0.0 )",
+				"pointSpecularWeight = pow( pointDotNormalHalf, uShininess );",
+
+			"pointDiffuse  += vec4( uDiffuseColor, 1.0 ) * pointDiffuseWeight;",
+			"pointSpecular += vec4( uSpecularColor, 1.0 ) * pointSpecularWeight;",
+
+			// directional light
+
+			"vec4 dirDiffuse  = vec4( 0.0, 0.0, 0.0, 0.0 );",
+			"vec4 dirSpecular = vec4( 0.0, 0.0, 0.0, 0.0 );",
+
+			"vec4 lDirection = viewMatrix * vec4( uDirLightPos, 0.0 );",
+
+			"vec3 dirVector = normalize( lDirection.xyz );",
+			"vec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );",
+
+			"float dirDotNormalHalf = dot( normal, dirHalfVector );",
+			"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
+
+			"float dirSpecularWeight = 0.0;",
+			"if ( dirDotNormalHalf >= 0.0 )",
+				"dirSpecularWeight = pow( dirDotNormalHalf, uShininess );",
+
+			"dirDiffuse  += vec4( uDiffuseColor, 1.0 ) * dirDiffuseWeight;",
+			"dirSpecular += vec4( uSpecularColor, 1.0 ) * dirSpecularWeight;",
+
+			// all lights contribution summation
+
+			"vec4 totalLight = vec4( uAmbientColor, 1.0 );",
+			"totalLight += dirDiffuse + dirSpecular;",
+			"totalLight += pointDiffuse + pointSpecular;",
+
+			"gl_FragColor = vec4( totalLight.xyz * vLightWeighting * aoTex, 1.0 );",
+			
+		"}"	
+		].join("\n"),
+				
+		vertex_shader: [
+
+		"attribute vec4 tangent;",
+
+		"uniform vec3 uDirLightPos;",
+		"uniform vec3 uDirLightColor;",
+
+		"uniform vec3 uPointLightPos;",
+		"uniform vec3 uPointLightColor;",
+		
+		"uniform vec3 uAmbientLightColor;",
+		
+		"#ifdef VERTEX_TEXTURES",
+		
+		"uniform sampler2D tDisplacement;",
+		"uniform float uDisplacementScale;",
+		"uniform float uDisplacementBias;",
+		
+		"#endif",
+		
+		"varying vec3 vTangent;",
+		"varying vec3 vBinormal;",
+		"varying vec3 vNormal;",
+		"varying vec2 vUv;",
+		
+		"varying vec3 vLightWeighting;",
+		"varying vec3 vPointLightVector;",
+		"varying vec3 vViewPosition;",
+		
+		"void main() {",
+		
+			"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
+			"vViewPosition = cameraPosition - mPosition.xyz;",
+		
+			"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+			"vNormal = normalize( normalMatrix * normal );",
+			
+			// tangent and binormal vectors
+			
+			"vTangent = normalize( normalMatrix * tangent.xyz );",
+
+			"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
+			"vBinormal = normalize( vBinormal );",
+			
+			"vUv = uv;",
+			
+			// ambient light
+			
+			"vLightWeighting = uAmbientLightColor;",
+			
+			// point light
+			
+			"vec4 lPosition = viewMatrix * vec4( uPointLightPos, 1.0 );",
+			"vPointLightVector = normalize( lPosition.xyz - mvPosition.xyz );",
+			"float pointLightWeighting = max( dot( vNormal, vPointLightVector ), 0.0 );",
+			"vLightWeighting += uPointLightColor * pointLightWeighting;",
+			
+			// directional light
+			
+			"vec4 lDirection = viewMatrix * vec4( uDirLightPos, 0.0 );",
+			"float directionalLightWeighting = max( dot( vNormal, normalize( lDirection.xyz ) ), 0.0 );",
+			"vLightWeighting += uDirLightColor * directionalLightWeighting;",
+			
+			// displacement mapping
+			
+			"#ifdef VERTEX_TEXTURES",
+			
+			"vec3 dv = texture2D( tDisplacement, uv ).xyz;",
+			"float df = uDisplacementScale * dv.x + uDisplacementBias;",
+			"vec4 displacedPosition = vec4( vNormal.xyz * df, 0.0 ) + mvPosition;",
+			"gl_Position = projectionMatrix * displacedPosition;",
+			
+			"#else",
+			
+			"gl_Position = projectionMatrix * mvPosition;",
+			
+			"#endif",
+			
+		"}"	
+		
+		].join("\n")
+
 		}
 		}
 	}
 	}
 
 

+ 2 - 1
src/materials/MeshShaderMaterial.js

@@ -21,9 +21,10 @@ THREE.MeshShaderMaterial = function ( parameters ) {
 	this.vertex_shader = "void main() {}";
 	this.vertex_shader = "void main() {}";
 	this.uniforms = {};
 	this.uniforms = {};
 
 
+	this.opacity = 1;
 	this.shading = THREE.SmoothShading;
 	this.shading = THREE.SmoothShading;
 	this.blending = THREE.NormalBlending;
 	this.blending = THREE.NormalBlending;
-
+		
 	this.wireframe = false;
 	this.wireframe = false;
 	this.wireframe_linewidth = 1;
 	this.wireframe_linewidth = 1;
 	this.wireframe_linecap = 'round';
 	this.wireframe_linecap = 'round';

+ 80 - 12
src/renderers/WebGLRenderer.js

@@ -159,13 +159,14 @@ THREE.WebGLRenderer = function ( scene ) {
 
 
 	this.createBuffers = function ( object, g ) {
 	this.createBuffers = function ( object, g ) {
 
 
-		var f, fl, fi, face, vertexNormals, normal, uv, v1, v2, v3, v4, m, ml, i,
+		var f, fl, fi, face, vertexNormals, normal, uv, v1, v2, v3, v4, t1, t2, t3, t4, m, ml, i,
 
 
 		faceArray = [],
 		faceArray = [],
 		lineArray = [],
 		lineArray = [],
 
 
 		vertexArray = [],
 		vertexArray = [],
 		normalArray = [],
 		normalArray = [],
+		tangentArray = [],
 		uvArray = [],
 		uvArray = [],
 
 
 		vertexIndex = 0,
 		vertexIndex = 0,
@@ -193,8 +194,21 @@ THREE.WebGLRenderer = function ( scene ) {
 				vertexArray.push( v2.x, v2.y, v2.z );
 				vertexArray.push( v2.x, v2.y, v2.z );
 				vertexArray.push( v3.x, v3.y, v3.z );
 				vertexArray.push( v3.x, v3.y, v3.z );
 
 
+				if ( object.geometry.hasTangents ) {
+					
+					t1 = object.geometry.vertices[ face.a ].tangent;
+					t2 = object.geometry.vertices[ face.b ].tangent;
+					t3 = object.geometry.vertices[ face.c ].tangent;
+
+					tangentArray.push( t1.x, t1.y, t1.z, t1.w );
+					tangentArray.push( t2.x, t2.y, t2.z, t2.w );
+					tangentArray.push( t3.x, t3.y, t3.z, t3.w );
+					
+				}
+
 				if ( vertexNormals.length == 3 && needsSmoothNormals ) {
 				if ( vertexNormals.length == 3 && needsSmoothNormals ) {
 
 
+					
 					for ( i = 0; i < 3; i ++ ) {
 					for ( i = 0; i < 3; i ++ ) {
 
 
 						normalArray.push( vertexNormals[ i ].x, vertexNormals[ i ].y, vertexNormals[ i ].z );
 						normalArray.push( vertexNormals[ i ].x, vertexNormals[ i ].y, vertexNormals[ i ].z );
@@ -242,15 +256,29 @@ THREE.WebGLRenderer = function ( scene ) {
 				vertexArray.push( v2.x, v2.y, v2.z );
 				vertexArray.push( v2.x, v2.y, v2.z );
 				vertexArray.push( v3.x, v3.y, v3.z );
 				vertexArray.push( v3.x, v3.y, v3.z );
 				vertexArray.push( v4.x, v4.y, v4.z );
 				vertexArray.push( v4.x, v4.y, v4.z );
+				
+				if ( object.geometry.hasTangents ) {
+					
+					t1 = object.geometry.vertices[ face.a ].tangent;
+					t2 = object.geometry.vertices[ face.b ].tangent;
+					t3 = object.geometry.vertices[ face.c ].tangent;
+					t4 = object.geometry.vertices[ face.d ].tangent;
+
+					tangentArray.push( t1.x, t1.y, t1.z, t1.w );
+					tangentArray.push( t2.x, t2.y, t2.z, t2.w );
+					tangentArray.push( t3.x, t3.y, t3.z, t3.w );
+					tangentArray.push( t4.x, t4.y, t4.z, t4.w );
+					
+				}
 
 
 				if ( vertexNormals.length == 4 && needsSmoothNormals ) {
 				if ( vertexNormals.length == 4 && needsSmoothNormals ) {
-
+					
 					for ( i = 0; i < 4; i ++ ) {
 					for ( i = 0; i < 4; i ++ ) {
 
 
 						normalArray.push( vertexNormals[ i ].x, vertexNormals[ i ].y, vertexNormals[ i ].z );
 						normalArray.push( vertexNormals[ i ].x, vertexNormals[ i ].y, vertexNormals[ i ].z );
 
 
 					}
 					}
-
+					
 				} else {
 				} else {
 
 
 					for ( i = 0; i < 4; i ++ ) {
 					for ( i = 0; i < 4; i ++ ) {
@@ -302,6 +330,14 @@ THREE.WebGLRenderer = function ( scene ) {
 		_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLNormalBuffer );
 		_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLNormalBuffer );
 		_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( normalArray ), _gl.STATIC_DRAW );
 		_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( normalArray ), _gl.STATIC_DRAW );
 
 
+		if ( object.geometry.hasTangents ) {
+			
+			geometryChunk.__webGLTangentBuffer = _gl.createBuffer();
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLTangentBuffer );
+			_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( tangentArray ), _gl.STATIC_DRAW );
+			
+		}
+		
 		if ( uvArray.length > 0 ) {
 		if ( uvArray.length > 0 ) {
 
 
 			geometryChunk.__webGLUVBuffer = _gl.createBuffer();
 			geometryChunk.__webGLUVBuffer = _gl.createBuffer();
@@ -346,7 +382,7 @@ THREE.WebGLRenderer = function ( scene ) {
 
 
 				}
 				}
 				cacheUniformLocations( material.program, identifiers );
 				cacheUniformLocations( material.program, identifiers );
-				cacheAttributeLocations( material.program, [ "position", "normal", "uv" ] );
+				cacheAttributeLocations( material.program, [ "position", "normal", "uv", "tangent" ] );
 
 
 			}
 			}
 
 
@@ -374,12 +410,13 @@ THREE.WebGLRenderer = function ( scene ) {
 		this.loadCamera( program, camera );
 		this.loadCamera( program, camera );
 		this.loadMatrices( program );
 		this.loadMatrices( program );
 
 
-
 		if ( material instanceof THREE.MeshShaderMaterial ) {
 		if ( material instanceof THREE.MeshShaderMaterial ) {
 
 
 			mWireframe = material.wireframe;
 			mWireframe = material.wireframe;
 			mLineWidth = material.wireframe_linewidth;
 			mLineWidth = material.wireframe_linewidth;
-
+			
+			mBlending = material.blending;
+			
 			setUniforms( program, material.uniforms );
 			setUniforms( program, material.uniforms );
 
 
 		}
 		}
@@ -505,6 +542,15 @@ THREE.WebGLRenderer = function ( scene ) {
 		_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLNormalBuffer );
 		_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLNormalBuffer );
 		_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
 		_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
 
 
+		// tangents
+
+		if ( attributes.tangent >= 0 ) {
+			
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLTangentBuffer );
+			_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
+			
+		}
+		
 		// uvs
 		// uvs
 
 
 		if ( attributes.uv >= 0 ) {
 		if ( attributes.uv >= 0 ) {
@@ -826,6 +872,19 @@ THREE.WebGLRenderer = function ( scene ) {
 
 
 	};
 	};
 
 
+	this.supportsVertexTextures = function() {
+		
+		return maxVertexTextures() > 0;
+		
+	};
+	
+	function maxVertexTextures() {
+		
+		return _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
+
+	};
+	
+	
 	function initGL() {
 	function initGL() {
 
 
 		try {
 		try {
@@ -888,7 +947,6 @@ THREE.WebGLRenderer = function ( scene ) {
 			"uniform int pointLightNumber;",
 			"uniform int pointLightNumber;",
 			"uniform int directionalLightNumber;",
 			"uniform int directionalLightNumber;",
 
 
-			maxDirLights ? "uniform mat4 viewMatrix;" : "",
 			maxDirLights ? "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];" : "",
 			maxDirLights ? "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];" : "",
 
 
 			"varying vec3 vNormal;",
 			"varying vec3 vNormal;",
@@ -939,7 +997,7 @@ THREE.WebGLRenderer = function ( scene ) {
 
 
 				"} else if ( material == 4 ) { ",
 				"} else if ( material == 4 ) { ",
 
 
-					"gl_FragColor = vec4( 0.5*normalize( vNormal ) + vec3(0.5, 0.5, 0.5), mOpacity );",
+					"gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, mOpacity );",
 
 
 				// Depth
 				// Depth
 
 
@@ -1094,9 +1152,6 @@ THREE.WebGLRenderer = function ( scene ) {
 			maxPointLights ? "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];"    : "",
 			maxPointLights ? "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];"    : "",
 			maxPointLights ? "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];" : "",
 			maxPointLights ? "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];" : "",
 
 
-			"uniform mat4 viewMatrix;",
-			"uniform mat3 normalMatrix;",
-
 			"varying vec3 vNormal;",
 			"varying vec3 vNormal;",
 			"varying vec2 vUv;",
 			"varying vec2 vUv;",
 
 
@@ -1137,7 +1192,7 @@ THREE.WebGLRenderer = function ( scene ) {
 
 
 					maxDirLights ? "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {" : "",
 					maxDirLights ? "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {" : "",
 					maxDirLights ?		"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );" : "",
 					maxDirLights ?		"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );" : "",
-					maxDirLights ?		"float directionalLightWeighting = max( dot( transformedNormal, normalize(lDirection.xyz ) ), 0.0 );" : "",
+					maxDirLights ?		"float directionalLightWeighting = max( dot( transformedNormal, normalize( lDirection.xyz ) ), 0.0 );" : "",
 					maxDirLights ?		"vLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;" : "",
 					maxDirLights ?		"vLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;" : "",
 					maxDirLights ? "}" : "",
 					maxDirLights ? "}" : "",
 
 
@@ -1181,13 +1236,18 @@ THREE.WebGLRenderer = function ( scene ) {
 			"#ifdef GL_ES",
 			"#ifdef GL_ES",
 			"precision highp float;",
 			"precision highp float;",
 			"#endif",
 			"#endif",
+			"uniform mat4 viewMatrix;",
 			""
 			""
 		].join("\n"),
 		].join("\n"),
 
 
 		prefix_vertex = [
 		prefix_vertex = [
+			maxVertexTextures() > 0 ? "#define VERTEX_TEXTURES" : "",
+		
 			"uniform mat4 objectMatrix;",
 			"uniform mat4 objectMatrix;",
 			"uniform mat4 modelViewMatrix;",
 			"uniform mat4 modelViewMatrix;",
 			"uniform mat4 projectionMatrix;",
 			"uniform mat4 projectionMatrix;",
+			"uniform mat4 viewMatrix;",
+			"uniform mat3 normalMatrix;",
 			"uniform vec3 cameraPosition;",
 			"uniform vec3 cameraPosition;",
 			"attribute vec3 position;",
 			"attribute vec3 position;",
 			"attribute vec3 normal;",
 			"attribute vec3 normal;",
@@ -1231,6 +1291,14 @@ THREE.WebGLRenderer = function ( scene ) {
 			} else if( type == "f" ) {
 			} else if( type == "f" ) {
 
 
 				_gl.uniform1f( location, value );
 				_gl.uniform1f( location, value );
+				
+			} else if( type == "v3" ) {
+
+				_gl.uniform3f( location, value.x, value.y, value.z );
+				
+			} else if( type == "c" ) {
+
+				_gl.uniform3f( location, value.r, value.g, value.b );
 
 
 			} else if( type == "t" ) {
 			} else if( type == "t" ) {