Jelajahi Sumber

Transplanted @WestLangley's normal matrix fix from Geometry.applyMatrix to BufferGeometry.

See #2610
alteredq 12 tahun lalu
induk
melakukan
748159e4f1
4 mengubah file dengan 132 tambahan dan 63 penghapusan
  1. 56 22
      build/three.js
  2. 20 20
      build/three.min.js
  3. 28 17
      src/core/BufferGeometry.js
  4. 28 4
      src/core/Matrix3.js

+ 56 - 22
build/three.js

@@ -1565,13 +1565,35 @@ THREE.Matrix3.prototype = {
 
 	},
 
+	multiplyVector3Array: function ( a ) {
+
+		var tmp = THREE.Matrix3.__v1;
+
+		for ( var i = 0, il = a.length; i < il; i += 3 ) {
+
+			tmp.x = a[ i ];
+			tmp.y = a[ i + 1 ];
+			tmp.z = a[ i + 2 ];
+
+			this.multiplyVector3( tmp );
+
+			a[ i ]     = tmp.x;
+			a[ i + 1 ] = tmp.y;
+			a[ i + 2 ] = tmp.z;
+
+		}
+
+		return a;
+
+	},
+
 	getInverse: function ( matrix ) {
 
 		// input: THREE.Matrix4
 		// ( based on http://code.google.com/p/webgl-mjs/ )
 
-        var me = matrix.elements;
-        
+		var me = matrix.elements;
+
 		var a11 =   me[10] * me[5] - me[6] * me[9];
 		var a21 = - me[10] * me[1] + me[2] * me[9];
 		var a31 =   me[6] * me[1] - me[2] * me[5];
@@ -1604,7 +1626,7 @@ THREE.Matrix3.prototype = {
 
 	},
 
-	
+
 	transpose: function () {
 
 		var tmp, m = this.elements;
@@ -1616,7 +1638,7 @@ THREE.Matrix3.prototype = {
 		return this;
 
 	},
-	
+
 
 	transposeIntoArray: function ( r ) {
 
@@ -1637,7 +1659,8 @@ THREE.Matrix3.prototype = {
 	}
 
 };
-/**
+
+THREE.Matrix3.__v1 = new THREE.Vector3();/**
  * @author mrdoob / http://mrdoob.com/
  * @author supereggbert / http://www.paulbrunt.co.uk/
  * @author philogb / http://blog.thejit.org/
@@ -5714,10 +5737,13 @@ THREE.BufferGeometry.prototype = {
 
 		if ( normalArray !== undefined ) {
 
-			var matrixRotation = new THREE.Matrix4();
-			matrixRotation.extractRotation( matrix );
+			var normalMatrix = new THREE.Matrix3();
+			normalMatrix.getInverse( matrix ).transpose();
+
+			normalMatrix.multiplyVector3Array( normalArray );
+
+			this.normalizeNormals();
 
-			matrixRotation.multiplyVector3Array( normalArray );
 			this.normalsNeedUpdate = true;
 
 		}
@@ -5900,15 +5926,15 @@ THREE.BufferGeometry.prototype = {
 					ab.sub( pA, pB );
 					cb.crossSelf( ab );
 
-					normals[ vA * 3 ] += cb.x;
+					normals[ vA * 3 ] 	  += cb.x;
 					normals[ vA * 3 + 1 ] += cb.y;
 					normals[ vA * 3 + 2 ] += cb.z;
 
-					normals[ vB * 3 ] += cb.x;
+					normals[ vB * 3 ] 	  += cb.x;
 					normals[ vB * 3 + 1 ] += cb.y;
 					normals[ vB * 3 + 2 ] += cb.z;
 
-					normals[ vC * 3 ] += cb.x;
+					normals[ vC * 3 ] 	  += cb.x;
 					normals[ vC * 3 + 1 ] += cb.y;
 					normals[ vC * 3 + 2 ] += cb.z;
 
@@ -5916,23 +5942,31 @@ THREE.BufferGeometry.prototype = {
 
 			}
 
-			// normalize normals
+			this.normalizeNormals();
 
-			for ( i = 0, il = normals.length; i < il; i += 3 ) {
+			this.normalsNeedUpdate = true;
 
-				x = normals[ i ];
-				y = normals[ i + 1 ];
-				z = normals[ i + 2 ];
+		}
 
-				var n = 1.0 / Math.sqrt( x * x + y * y + z * z );
+	},
 
-				normals[ i ] *= n;
-				normals[ i + 1 ] *= n;
-				normals[ i + 2 ] *= n;
+	normalizeNormals: function () {
 
-			}
+		var normals = this.attributes[ "normal" ].array;
 
-			this.normalsNeedUpdate = true;
+		var x, y, z, n;
+
+		for ( var i = 0, il = normals.length; i < il; i += 3 ) {
+
+			x = normals[ i ];
+			y = normals[ i + 1 ];
+			z = normals[ i + 2 ];
+
+			n = 1.0 / Math.sqrt( x * x + y * y + z * z );
+
+			normals[ i ] 	 *= n;
+			normals[ i + 1 ] *= n;
+			normals[ i + 2 ] *= n;
 
 		}
 

+ 20 - 20
build/three.min.js

@@ -30,9 +30,9 @@ a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},multiplyScalar:function(a){
 Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):
 (this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){var b,c,d,a=a.elements,e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],i=a[9];c=a[2];b=a[6];var j=a[10];if(0.01>Math.abs(d-g)&&0.01>Math.abs(f-c)&&0.01>Math.abs(i-b)){if(0.1>Math.abs(d+g)&&0.1>Math.abs(f+c)&&0.1>Math.abs(i+b)&&0.1>Math.abs(e+h+j-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;j=(j+1)/2;d=(d+g)/4;f=(f+c)/4;i=(i+b)/4;e>h&&e>j?0.01>e?(b=0,d=c=0.707106781):(b=Math.sqrt(e),c=d/b,d=f/
 b):h>j?0.01>h?(b=0.707106781,c=0,d=0.707106781):(c=Math.sqrt(h),b=d/c,d=i/c):0.01>j?(c=b=0.707106781,d=0):(d=Math.sqrt(j),b=f/d,c=i/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-i)*(b-i)+(f-c)*(f-c)+(g-d)*(g-d));0.001>Math.abs(a)&&(a=1);this.x=(b-i)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+j-1)/2);return this}};THREE.Matrix3=function(){this.elements=new Float32Array(9)};
-THREE.Matrix3.prototype={constructor:THREE.Matrix3,multiplyVector3:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z;a.x=b[0]*c+b[3]*d+b[6]*e;a.y=b[1]*c+b[4]*d+b[7]*e;a.z=b[2]*c+b[5]*d+b[8]*e;return a},getInverse:function(a){var b=a.elements,a=b[10]*b[5]-b[6]*b[9],c=-b[10]*b[1]+b[2]*b[9],d=b[6]*b[1]-b[2]*b[5],e=-b[10]*b[4]+b[6]*b[8],f=b[10]*b[0]-b[2]*b[8],g=-b[6]*b[0]+b[2]*b[4],h=b[9]*b[4]-b[5]*b[8],i=-b[9]*b[0]+b[1]*b[8],j=b[5]*b[0]-b[1]*b[4],b=b[0]*a+b[1]*e+b[2]*h;0===b&&console.warn("Matrix3.getInverse(): determinant == 0");
-var b=1/b,m=this.elements;m[0]=b*a;m[1]=b*c;m[2]=b*d;m[3]=b*e;m[4]=b*f;m[5]=b*g;m[6]=b*h;m[7]=b*i;m[8]=b*j;return this},transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},transposeIntoArray:function(a){var b=this.m;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this}};
-THREE.Matrix4=function(a,b,c,d,e,f,g,h,i,j,m,n,l,o,p,q){this.elements=new Float32Array(16);this.set(void 0!==a?a:1,b||0,c||0,d||0,e||0,void 0!==f?f:1,g||0,h||0,i||0,j||0,void 0!==m?m:1,n||0,l||0,o||0,p||0,void 0!==q?q:1)};
+THREE.Matrix3.prototype={constructor:THREE.Matrix3,multiplyVector3:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z;a.x=b[0]*c+b[3]*d+b[6]*e;a.y=b[1]*c+b[4]*d+b[7]*e;a.z=b[2]*c+b[5]*d+b[8]*e;return a},multiplyVector3Array:function(a){for(var b=THREE.Matrix3.__v1,c=0,d=a.length;c<d;c+=3)b.x=a[c],b.y=a[c+1],b.z=a[c+2],this.multiplyVector3(b),a[c]=b.x,a[c+1]=b.y,a[c+2]=b.z;return a},getInverse:function(a){var b=a.elements,a=b[10]*b[5]-b[6]*b[9],c=-b[10]*b[1]+b[2]*b[9],d=b[6]*b[1]-b[2]*b[5],e=-b[10]*
+b[4]+b[6]*b[8],f=b[10]*b[0]-b[2]*b[8],g=-b[6]*b[0]+b[2]*b[4],h=b[9]*b[4]-b[5]*b[8],i=-b[9]*b[0]+b[1]*b[8],j=b[5]*b[0]-b[1]*b[4],b=b[0]*a+b[1]*e+b[2]*h;0===b&&console.warn("Matrix3.getInverse(): determinant == 0");var b=1/b,m=this.elements;m[0]=b*a;m[1]=b*c;m[2]=b*d;m[3]=b*e;m[4]=b*f;m[5]=b*g;m[6]=b*h;m[7]=b*i;m[8]=b*j;return this},transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},transposeIntoArray:function(a){var b=this.m;
+a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this}};THREE.Matrix3.__v1=new THREE.Vector3;THREE.Matrix4=function(a,b,c,d,e,f,g,h,i,j,m,n,l,o,p,q){this.elements=new Float32Array(16);this.set(void 0!==a?a:1,b||0,c||0,d||0,e||0,void 0!==f?f:1,g||0,h||0,i||0,j||0,void 0!==m?m:1,n||0,l||0,o||0,p||0,void 0!==q?q:1)};
 THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,f,g,h,i,j,m,n,l,o,p,q){var t=this.elements;t[0]=a;t[4]=b;t[8]=c;t[12]=d;t[1]=e;t[5]=f;t[9]=g;t[13]=h;t[2]=i;t[6]=j;t[10]=m;t[14]=n;t[3]=l;t[7]=o;t[11]=p;t[15]=q;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15]);return this},lookAt:function(a,b,c){var d=this.elements,
 e=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,g=THREE.Matrix4.__v3;g.sub(a,b).normalize();0===g.length()&&(g.z=1);e.cross(c,g).normalize();0===e.length()&&(g.x+=1E-4,e.cross(c,g).normalize());f.cross(g,e);d[0]=e.x;d[4]=f.x;d[8]=g.x;d[1]=e.y;d[5]=f.y;d[9]=g.y;d[2]=e.z;d[6]=f.z;d[10]=g.z;return this},multiply:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],g=c[4],h=c[8],i=c[12],j=c[1],m=c[5],n=c[9],l=c[13],o=c[2],p=c[6],q=c[10],t=c[14],r=c[3],A=c[7],u=c[11],c=c[15],s=d[0],D=d[4],z=d[8],
 w=d[12],v=d[1],C=d[5],E=d[9],G=d[13],L=d[2],B=d[6],J=d[10],H=d[14],I=d[3],O=d[7],N=d[11],d=d[15];e[0]=f*s+g*v+h*L+i*I;e[4]=f*D+g*C+h*B+i*O;e[8]=f*z+g*E+h*J+i*N;e[12]=f*w+g*G+h*H+i*d;e[1]=j*s+m*v+n*L+l*I;e[5]=j*D+m*C+n*B+l*O;e[9]=j*z+m*E+n*J+l*N;e[13]=j*w+m*G+n*H+l*d;e[2]=o*s+p*v+q*L+t*I;e[6]=o*D+p*C+q*B+t*O;e[10]=o*z+p*E+q*J+t*N;e[14]=o*w+p*G+q*H+t*d;e[3]=r*s+A*v+u*L+c*I;e[7]=r*D+A*C+u*B+c*O;e[11]=r*z+A*E+u*J+c*N;e[15]=r*w+A*G+u*H+c*d;return this},multiplySelf:function(a){return this.multiply(this,
@@ -120,15 +120,15 @@ this.boundingBox.min,c=this.boundingBox.max,d=1,e=this.vertices.length;d<e;d++)(
 mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,4),f,g,h,i;f=0;for(g=this.vertices.length;f<g;f++)d=this.vertices[f],d=[Math.round(d.x*e),Math.round(d.y*e),Math.round(d.z*e)].join("_"),void 0===a[d]?(a[d]=f,b.push(this.vertices[f]),c[f]=b.length-1):c[f]=c[a[d]];f=0;for(g=this.faces.length;f<g;f++)if(a=this.faces[f],a instanceof THREE.Face3)a.a=c[a.a],a.b=c[a.b],a.c=c[a.c];else if(a instanceof THREE.Face4){a.a=c[a.a];a.b=c[a.b];a.c=c[a.c];a.d=c[a.d];d=[a.a,a.b,a.c,a.d];for(e=3;0<e;e--)if(d.indexOf(a["abcd"[e]])!==
 e){d.splice(e,1);this.faces[f]=new THREE.Face3(d[0],d[1],d[2],a.normal,a.color,a.materialIndex);d=0;for(h=this.faceVertexUvs.length;d<h;d++)(i=this.faceVertexUvs[d][f])&&i.splice(e,1);this.faces[f].vertexColors=a.vertexColors;break}}c=this.vertices.length-b.length;this.vertices=b;return c},clone:function(){},deallocate:function(){var a=THREE.GeometryLibrary.indexOf(this);-1!==a&&THREE.GeometryLibrary.splice(a,1)}};THREE.GeometryIdCount=0;THREE.GeometryLibrary=[];
 THREE.BufferGeometry=function(){THREE.GeometryLibrary.push(this);this.id=THREE.GeometryIdCount++;this.attributes={};this.dynamic=!1;this.boundingSphere=this.boundingBox=null;this.hasTangents=!1;this.morphTargets=[]};
-THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,applyMatrix:function(a){var b,c;this.attributes.position&&(b=this.attributes.position.array);this.attributes.normal&&(c=this.attributes.normal.array);void 0!==b&&(a.multiplyVector3Array(b),this.verticesNeedUpdate=!0);void 0!==c&&(b=new THREE.Matrix4,b.extractRotation(a),b.multiplyVector3Array(c),this.normalsNeedUpdate=!0)},computeBoundingBox:function(){this.boundingBox||(this.boundingBox={min:new THREE.Vector3(Infinity,Infinity,Infinity),
-max:new THREE.Vector3(-Infinity,-Infinity,-Infinity)});var a=this.attributes.position.array;if(a)for(var b=this.boundingBox,c,d,e,f=0,g=a.length;f<g;f+=3)(c=a[f],d=a[f+1],e=a[f+2],c<b.min.x?b.min.x=c:c>b.max.x&&(b.max.x=c),d<b.min.y?b.min.y=d:d>b.max.y&&(b.max.y=d),e<b.min.z)?b.min.z=e:e>b.max.z&&(b.max.z=e);if(void 0===a||0===a.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){this.boundingSphere||(this.boundingSphere={radius:0});var a=this.attributes.position.array;
-if(a){for(var b,c=0,d,e,f=0,g=a.length;f<g;f+=3)b=a[f],d=a[f+1],e=a[f+2],b=b*b+d*d+e*e,b>c&&(c=b);this.boundingSphere.radius=Math.sqrt(c)}},computeVertexNormals:function(){if(this.attributes.position&&this.attributes.index){var a,b,c,d;a=this.attributes.position.array.length;if(void 0===this.attributes.normal)this.attributes.normal={itemSize:3,array:new Float32Array(a),numItems:a};else{a=0;for(b=this.attributes.normal.array.length;a<b;a++)this.attributes.normal.array[a]=0}var e=this.offsets,f=this.attributes.index.array,
-g=this.attributes.position.array,h=this.attributes.normal.array,i,j,m,n,l,o,p=new THREE.Vector3,q=new THREE.Vector3,t=new THREE.Vector3,r=new THREE.Vector3,A=new THREE.Vector3;c=0;for(d=e.length;c<d;++c){b=e[c].start;i=e[c].count;var u=e[c].index;a=b;for(b+=i;a<b;a+=3)i=u+f[a],j=u+f[a+1],m=u+f[a+2],n=g[3*i],l=g[3*i+1],o=g[3*i+2],p.set(n,l,o),n=g[3*j],l=g[3*j+1],o=g[3*j+2],q.set(n,l,o),n=g[3*m],l=g[3*m+1],o=g[3*m+2],t.set(n,l,o),r.sub(t,q),A.sub(p,q),r.crossSelf(A),h[3*i]+=r.x,h[3*i+1]+=r.y,h[3*i+
-2]+=r.z,h[3*j]+=r.x,h[3*j+1]+=r.y,h[3*j+2]+=r.z,h[3*m]+=r.x,h[3*m+1]+=r.y,h[3*m+2]+=r.z}a=0;for(b=h.length;a<b;a+=3)n=h[a],l=h[a+1],o=h[a+2],c=1/Math.sqrt(n*n+l*l+o*o),h[a]*=c,h[a+1]*=c,h[a+2]*=c;this.normalsNeedUpdate=!0}},computeTangents:function(){function a(a){T.x=d[3*a];T.y=d[3*a+1];T.z=d[3*a+2];R.copy(T);S=i[a];N.copy(S);N.subSelf(T.multiplyScalar(T.dot(S))).normalize();M.cross(R,S);$=M.dot(j[a]);P=0>$?-1:1;h[4*a]=N.x;h[4*a+1]=N.y;h[4*a+2]=N.z;h[4*a+3]=P}if(void 0===this.attributes.index||void 0===
-this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var b=this.attributes.index.array,c=this.attributes.position.array,d=this.attributes.normal.array,e=this.attributes.uv.array,f=c.length/3;if(void 0===this.attributes.tangent){var g=4*f;this.attributes.tangent={itemSize:4,array:new Float32Array(g),numItems:g}}for(var h=this.attributes.tangent.array,
-i=[],j=[],g=0;g<f;g++)i[g]=new THREE.Vector3,j[g]=new THREE.Vector3;var m,n,l,o,p,q,t,r,A,u,s,D,z,w,v,f=new THREE.Vector3,g=new THREE.Vector3,C,E,G,L,B,J,H,I=this.offsets;G=0;for(L=I.length;G<L;++G){E=I[G].start;B=I[G].count;var O=I[G].index;C=E;for(E+=B;C<E;C+=3)B=O+b[C],J=O+b[C+1],H=O+b[C+2],m=c[3*B],n=c[3*B+1],l=c[3*B+2],o=c[3*J],p=c[3*J+1],q=c[3*J+2],t=c[3*H],r=c[3*H+1],A=c[3*H+2],u=e[2*B],s=e[2*B+1],D=e[2*J],z=e[2*J+1],w=e[2*H],v=e[2*H+1],o-=m,m=t-m,p-=n,n=r-n,q-=l,l=A-l,D-=u,u=w-u,z-=s,s=v-
-s,v=1/(D*s-u*z),f.set((s*o-z*m)*v,(s*p-z*n)*v,(s*q-z*l)*v),g.set((D*m-u*o)*v,(D*n-u*p)*v,(D*l-u*q)*v),i[B].addSelf(f),i[J].addSelf(f),i[H].addSelf(f),j[B].addSelf(g),j[J].addSelf(g),j[H].addSelf(g)}var N=new THREE.Vector3,M=new THREE.Vector3,T=new THREE.Vector3,R=new THREE.Vector3,P,S,$;G=0;for(L=I.length;G<L;++G){E=I[G].start;B=I[G].count;O=I[G].index;C=E;for(E+=B;C<E;C+=3)B=O+b[C],J=O+b[C+1],H=O+b[C+2],a(B),a(J),a(H)}this.tangentsNeedUpdate=this.hasTangents=!0}},deallocate:function(){var a=THREE.GeometryLibrary.indexOf(this);
--1!==a&&THREE.GeometryLibrary.splice(a,1)}};
+THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,applyMatrix:function(a){var b,c;this.attributes.position&&(b=this.attributes.position.array);this.attributes.normal&&(c=this.attributes.normal.array);void 0!==b&&(a.multiplyVector3Array(b),this.verticesNeedUpdate=!0);void 0!==c&&(b=new THREE.Matrix3,b.getInverse(a).transpose(),b.multiplyVector3Array(c),this.normalizeNormals(),this.normalsNeedUpdate=!0)},computeBoundingBox:function(){this.boundingBox||(this.boundingBox={min:new THREE.Vector3(Infinity,
+Infinity,Infinity),max:new THREE.Vector3(-Infinity,-Infinity,-Infinity)});var a=this.attributes.position.array;if(a)for(var b=this.boundingBox,c,d,e,f=0,g=a.length;f<g;f+=3)(c=a[f],d=a[f+1],e=a[f+2],c<b.min.x?b.min.x=c:c>b.max.x&&(b.max.x=c),d<b.min.y?b.min.y=d:d>b.max.y&&(b.max.y=d),e<b.min.z)?b.min.z=e:e>b.max.z&&(b.max.z=e);if(void 0===a||0===a.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){this.boundingSphere||(this.boundingSphere={radius:0});
+var a=this.attributes.position.array;if(a){for(var b,c=0,d,e,f=0,g=a.length;f<g;f+=3)b=a[f],d=a[f+1],e=a[f+2],b=b*b+d*d+e*e,b>c&&(c=b);this.boundingSphere.radius=Math.sqrt(c)}},computeVertexNormals:function(){if(this.attributes.position&&this.attributes.index){var a,b,c,d;a=this.attributes.position.array.length;if(void 0===this.attributes.normal)this.attributes.normal={itemSize:3,array:new Float32Array(a),numItems:a};else{a=0;for(b=this.attributes.normal.array.length;a<b;a++)this.attributes.normal.array[a]=
+0}var e=this.offsets,f=this.attributes.index.array,g=this.attributes.position.array,h=this.attributes.normal.array,i,j,m,n,l,o,p=new THREE.Vector3,q=new THREE.Vector3,t=new THREE.Vector3,r=new THREE.Vector3,A=new THREE.Vector3;c=0;for(d=e.length;c<d;++c){b=e[c].start;i=e[c].count;var u=e[c].index;a=b;for(b+=i;a<b;a+=3)i=u+f[a],j=u+f[a+1],m=u+f[a+2],n=g[3*i],l=g[3*i+1],o=g[3*i+2],p.set(n,l,o),n=g[3*j],l=g[3*j+1],o=g[3*j+2],q.set(n,l,o),n=g[3*m],l=g[3*m+1],o=g[3*m+2],t.set(n,l,o),r.sub(t,q),A.sub(p,
+q),r.crossSelf(A),h[3*i]+=r.x,h[3*i+1]+=r.y,h[3*i+2]+=r.z,h[3*j]+=r.x,h[3*j+1]+=r.y,h[3*j+2]+=r.z,h[3*m]+=r.x,h[3*m+1]+=r.y,h[3*m+2]+=r.z}this.normalizeNormals();this.normalsNeedUpdate=!0}},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,c,d,e=0,f=a.length;e<f;e+=3)b=a[e],c=a[e+1],d=a[e+2],b=1/Math.sqrt(b*b+c*c+d*d),a[e]*=b,a[e+1]*=b,a[e+2]*=b},computeTangents:function(){function a(a){T.x=d[3*a];T.y=d[3*a+1];T.z=d[3*a+2];R.copy(T);S=i[a];N.copy(S);N.subSelf(T.multiplyScalar(T.dot(S))).normalize();
+M.cross(R,S);$=M.dot(j[a]);P=0>$?-1:1;h[4*a]=N.x;h[4*a+1]=N.y;h[4*a+2]=N.z;h[4*a+3]=P}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var b=this.attributes.index.array,c=this.attributes.position.array,d=this.attributes.normal.array,e=this.attributes.uv.array,f=c.length/3;if(void 0===this.attributes.tangent){var g=
+4*f;this.attributes.tangent={itemSize:4,array:new Float32Array(g),numItems:g}}for(var h=this.attributes.tangent.array,i=[],j=[],g=0;g<f;g++)i[g]=new THREE.Vector3,j[g]=new THREE.Vector3;var m,n,l,o,p,q,t,r,A,u,s,D,z,w,v,f=new THREE.Vector3,g=new THREE.Vector3,C,E,G,L,B,J,H,I=this.offsets;G=0;for(L=I.length;G<L;++G){E=I[G].start;B=I[G].count;var O=I[G].index;C=E;for(E+=B;C<E;C+=3)B=O+b[C],J=O+b[C+1],H=O+b[C+2],m=c[3*B],n=c[3*B+1],l=c[3*B+2],o=c[3*J],p=c[3*J+1],q=c[3*J+2],t=c[3*H],r=c[3*H+1],A=c[3*
+H+2],u=e[2*B],s=e[2*B+1],D=e[2*J],z=e[2*J+1],w=e[2*H],v=e[2*H+1],o-=m,m=t-m,p-=n,n=r-n,q-=l,l=A-l,D-=u,u=w-u,z-=s,s=v-s,v=1/(D*s-u*z),f.set((s*o-z*m)*v,(s*p-z*n)*v,(s*q-z*l)*v),g.set((D*m-u*o)*v,(D*n-u*p)*v,(D*l-u*q)*v),i[B].addSelf(f),i[J].addSelf(f),i[H].addSelf(f),j[B].addSelf(g),j[J].addSelf(g),j[H].addSelf(g)}var N=new THREE.Vector3,M=new THREE.Vector3,T=new THREE.Vector3,R=new THREE.Vector3,P,S,$;G=0;for(L=I.length;G<L;++G){E=I[G].start;B=I[G].count;O=I[G].index;C=E;for(E+=B;C<E;C+=3)B=O+b[C],
+J=O+b[C+1],H=O+b[C+2],a(B),a(J),a(H)}this.tangentsNeedUpdate=this.hasTangents=!0}},deallocate:function(){var a=THREE.GeometryLibrary.indexOf(this);-1!==a&&THREE.GeometryLibrary.splice(a,1)}};
 THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,i,j,m,n,l;this.initFromArray=function(a){this.points=[];for(var b=0;b<a.length;b++)this.points[b]={x:a[b][0],y:a[b][1],z:a[b][2]}};this.getPoint=function(a){e=(this.points.length-1)*a;f=Math.floor(e);g=e-f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1:
 f+2;j=this.points[c[0]];m=this.points[c[1]];n=this.points[c[2]];l=this.points[c[3]];h=g*g;i=g*h;d.x=b(j.x,m.x,n.x,l.x,g,h,i);d.y=b(j.y,m.y,n.y,l.y,g,h,i);d.z=b(j.z,m.z,n.z,l.z,g,h,i);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<c;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d};this.getLength=function(a){var b,c,d,e=b=b=0,f=new THREE.Vector3,g=new THREE.Vector3,h=[],i=0;h[0]=0;a||(a=100);c=this.points.length*a;f.copy(this.points[0]);for(a=1;a<c;a++)b=
 a/c,d=this.getPoint(b),g.copy(d),i+=g.distanceTo(f),f.copy(d),b*=this.points.length-1,b=Math.floor(b),b!=e&&(h[b]=i,e=b);h[h.length]=i;return{chunks:h,total:i}};this.reparametrizeByArcLength=function(a){var b,c,d,e,f,g,h=[],i=new THREE.Vector3,j=this.getLength();h.push(i.copy(this.points[0]).clone());for(b=1;b<this.points.length;b++){c=j.chunks[b]-j.chunks[b-1];g=Math.ceil(a*c/j.total);e=(b-1)/(this.points.length-1);f=b/(this.points.length-1);for(c=1;c<g-1;c++)d=e+c*(1/g)*(f-e),d=this.getPoint(d),
@@ -177,8 +177,8 @@ s,0,0))}d.bones=a.bones;d.animation=a.animation;if(void 0!==a.morphTargets){c=0;
 THREE.GeometryLoader=function(){THREE.EventTarget.call(this);this.path=this.crossOrigin=null};
 THREE.GeometryLoader.prototype={constructor:THREE.GeometryLoader,load:function(a){var b=this,c=null;if(null===b.path){var d=a.split("/");d.pop();b.path=1>d.length?".":d.join("/")}d=new XMLHttpRequest;d.addEventListener("load",function(d){d.target.responseText?c=b.parse(JSON.parse(d.target.responseText),e):b.dispatchEvent({type:"error",message:"Invalid file ["+a+"]"})},!1);d.addEventListener("error",function(){b.dispatchEvent({type:"error",message:"Couldn't load URL ["+a+"]"})},!1);d.open("GET",a,
 !0);d.send(null);var e=new THREE.LoadingMonitor;e.addEventListener("load",function(){b.dispatchEvent({type:"load",content:c})});e.add(d)},parse:function(a,b){var c=this,d=new THREE.Geometry,e=void 0!==a.scale?1/a.scale:1;if(a.materials){d.materials=[];for(var f=0;f<a.materials.length;++f){var g=a.materials[f],h=function(a){a=Math.log(a)/Math.LN2;return Math.floor(a)==a},i=function(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))},j=function(a,d,e,f,g,j){a[d]=new THREE.Texture;a[d].sourceFile=
-e;if(f&&(a[d].repeat.set(f[0],f[1]),1!==f[0]&&(a[d].wrapS=THREE.RepeatWrapping),1!==f[1]))a[d].wrapT=THREE.RepeatWrapping;g&&a[d].offset.set(g[0],g[1]);if(j&&(f={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping},void 0!==f[j[0]]&&(a[d].wrapS=f[j[0]]),void 0!==f[j[1]]))a[d].wrapT=f[j[1]];var l=a[d],a=new THREE.ImageLoader;a.addEventListener("load",function(a){a=a.content;if(!h(a.width)||!h(a.height)){var b=i(a.width),c=i(a.height);l.image=document.createElement("canvas");l.image.width=
-b;l.image.height=c;l.image.getContext("2d").drawImage(a,0,0,b,c)}else l.image=a;l.needsUpdate=!0});a.crossOrigin=c.crossOrigin;a.load(c.path+"/"+e);b&&b.add(a)},m=function(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]},n="MeshLambertMaterial",l={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(g.shading){var o=g.shading.toLowerCase();"phong"===o?n="MeshPhongMaterial":"basic"===o&&(n="MeshBasicMaterial")}void 0!==g.blending&&void 0!==THREE[g.blending]&&
+e;if(f&&(a[d].repeat.set(f[0],f[1]),1!==f[0]&&(a[d].wrapS=THREE.RepeatWrapping),1!==f[1]))a[d].wrapT=THREE.RepeatWrapping;g&&a[d].offset.set(g[0],g[1]);if(j&&(f={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping},void 0!==f[j[0]]&&(a[d].wrapS=f[j[0]]),void 0!==f[j[1]]))a[d].wrapT=f[j[1]];var m=a[d],a=new THREE.ImageLoader;a.addEventListener("load",function(a){a=a.content;if(!h(a.width)||!h(a.height)){var b=i(a.width),c=i(a.height);m.image=document.createElement("canvas");m.image.width=
+b;m.image.height=c;m.image.getContext("2d").drawImage(a,0,0,b,c)}else m.image=a;m.needsUpdate=!0});a.crossOrigin=c.crossOrigin;a.load(c.path+"/"+e);b&&b.add(a)},m=function(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]},n="MeshLambertMaterial",l={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(g.shading){var o=g.shading.toLowerCase();"phong"===o?n="MeshPhongMaterial":"basic"===o&&(n="MeshBasicMaterial")}void 0!==g.blending&&void 0!==THREE[g.blending]&&
 (l.blending=THREE[g.blending]);if(void 0!==g.transparent||1>g.opacity)l.transparent=g.transparent;void 0!==g.depthTest&&(l.depthTest=g.depthTest);void 0!==g.depthWrite&&(l.depthWrite=g.depthWrite);void 0!==g.vertexColors&&("face"==g.vertexColors?l.vertexColors=THREE.FaceColors:g.vertexColors&&(l.vertexColors=THREE.VertexColors));g.colorDiffuse?l.color=m(g.colorDiffuse):g.DbgColor&&(l.color=g.DbgColor);g.colorSpecular&&(l.specular=m(g.colorSpecular));g.colorAmbient&&(l.ambient=m(g.colorAmbient));g.transparency&&
 (l.opacity=g.transparency);g.specularCoef&&(l.shininess=g.specularCoef);void 0!==g.visible&&(l.visible=g.visible);void 0!==g.flipSided&&(l.side=THREE.BackSide);void 0!==g.doubleSided&&(l.side=THREE.DoubleSide);void 0!==g.wireframe&&(l.wireframe=g.wireframe);g.mapDiffuse&&j(l,"map",g.mapDiffuse,g.mapDiffuseRepeat,g.mapDiffuseOffset,g.mapDiffuseWrap);g.mapLight&&j(l,"lightMap",g.mapLight,g.mapLightRepeat,g.mapLightOffset,g.mapLightWrap);g.mapBump&&j(l,"bumpMap",g.mapBump,g.mapBumpRepeat,g.mapBumpOffset,
 g.mapBumpWrap);g.mapNormal&&j(l,"normalMap",g.mapNormal,g.mapNormalRepeat,g.mapNormalOffset,g.mapNormalWrap);g.mapSpecular&&j(l,"specularMap",g.mapSpecular,g.mapSpecularRepeat,g.mapSpecularOffset,g.mapSpecularWrap);g.mapNormal?(j=THREE.ShaderUtils.lib.normal,m=THREE.UniformsUtils.clone(j.uniforms),m.tNormal.value=l.normalMap,g.mapNormalFactor&&m.uNormalScale.value.set(g.mapNormalFactor,g.mapNormalFactor),l.map&&(m.tDiffuse.value=l.map,m.enableDiffuse.value=!0),l.specularMap&&(m.tSpecular.value=l.specularMap,
@@ -474,12 +474,12 @@ ca.colorsNeedUpdate||ca.lineDistancesNeedUpdate||za){var wb=ca,Hc=k.DYNAMIC_DRAW
 sc,Kc[Ha]=Ic.x,Kc[Ha+1]=Ic.y,Kc[Ha+2]=Ic.z;k.bindBuffer(k.ARRAY_BUFFER,wb.__webglVertexBuffer);k.bufferData(k.ARRAY_BUFFER,Kc,Hc)}if(pd){for(tc=0;tc<nd;tc++)Jc=bd[tc],Ha=3*tc,Lc[Ha]=Jc.r,Lc[Ha+1]=Jc.g,Lc[Ha+2]=Jc.b;k.bindBuffer(k.ARRAY_BUFFER,wb.__webglColorBuffer);k.bufferData(k.ARRAY_BUFFER,Lc,Hc)}if(qd){for(uc=0;uc<od;uc++)dd[uc]=cd[uc];k.bindBuffer(k.ARRAY_BUFFER,wb.__webglLineDistanceBuffer);k.bufferData(k.ARRAY_BUFFER,dd,Hc)}if(Wc){Mc=0;for(ed=Wc.length;Mc<ed;Mc++)if(Da=Wc[Mc],Da.needsUpdate&&
 (void 0===Da.boundTo||"vertices"===Da.boundTo)){Ha=0;lc=Da.value.length;if(1===Da.size)for(Xa=0;Xa<lc;Xa++)Da.array[Xa]=Da.value[Xa];else if(2===Da.size)for(Xa=0;Xa<lc;Xa++)jb=Da.value[Xa],Da.array[Ha]=jb.x,Da.array[Ha+1]=jb.y,Ha+=2;else if(3===Da.size)if("c"===Da.type)for(Xa=0;Xa<lc;Xa++)jb=Da.value[Xa],Da.array[Ha]=jb.r,Da.array[Ha+1]=jb.g,Da.array[Ha+2]=jb.b,Ha+=3;else for(Xa=0;Xa<lc;Xa++)jb=Da.value[Xa],Da.array[Ha]=jb.x,Da.array[Ha+1]=jb.y,Da.array[Ha+2]=jb.z,Ha+=3;else if(4===Da.size)for(Xa=
 0;Xa<lc;Xa++)jb=Da.value[Xa],Da.array[Ha]=jb.x,Da.array[Ha+1]=jb.y,Da.array[Ha+2]=jb.z,Da.array[Ha+3]=jb.w,Ha+=4;k.bindBuffer(k.ARRAY_BUFFER,Da.buffer);k.bufferData(k.ARRAY_BUFFER,Da.array,Hc)}}}ca.verticesNeedUpdate=!1;ca.colorsNeedUpdate=!1;ca.lineDistancesNeedUpdate=!1;ka.attributes&&r(ka)}else pa instanceof THREE.ParticleSystem&&(ca instanceof THREE.BufferGeometry?((ca.verticesNeedUpdate||ca.colorsNeedUpdate)&&j(ca,k.DYNAMIC_DRAW,!ca.dynamic),ca.verticesNeedUpdate=!1,ca.colorsNeedUpdate=!1):(ka=
-e(pa,ca),za=ka.attributes&&t(ka),(ca.verticesNeedUpdate||ca.colorsNeedUpdate||pa.sortParticles||za)&&i(ca,k.DYNAMIC_DRAW,pa),ca.verticesNeedUpdate=!1,ca.colorsNeedUpdate=!1,ka.attributes&&r(ka)))}};this.initMaterial=function(a,b,c,d){var e,f,g,h,i,j,l,n,m;a instanceof THREE.MeshDepthMaterial?m="depth":a instanceof THREE.MeshNormalMaterial?m="normal":a instanceof THREE.MeshBasicMaterial?m="basic":a instanceof THREE.MeshLambertMaterial?m="lambert":a instanceof THREE.MeshPhongMaterial?m="phong":a instanceof
-THREE.LineBasicMaterial?m="basic":a instanceof THREE.LineDashedMaterial?m="dashed":a instanceof THREE.ParticleBasicMaterial&&(m="particle_basic");if(m){var o=THREE.ShaderLib[m];a.uniforms=THREE.UniformsUtils.clone(o.uniforms);a.vertexShader=o.vertexShader;a.fragmentShader=o.fragmentShader}var p,q,r;e=p=q=r=o=0;for(f=b.length;e<f;e++)g=b[e],g.onlyShadow||(g instanceof THREE.DirectionalLight&&p++,g instanceof THREE.PointLight&&q++,g instanceof THREE.SpotLight&&r++,g instanceof THREE.HemisphereLight&&
-o++);e=p;f=q;g=r;h=o;o=p=0;for(r=b.length;o<r;o++)q=b[o],q.castShadow&&(q instanceof THREE.SpotLight&&p++,q instanceof THREE.DirectionalLight&&!q.shadowCascade&&p++);n=p;fc&&d&&d.useVertexTexture?l=1024:(b=k.getParameter(k.MAX_VERTEX_UNIFORM_VECTORS),b=Math.floor((b-20)/4),void 0!==d&&d instanceof THREE.SkinnedMesh&&(b=Math.min(d.bones.length,b),b<d.bones.length&&console.warn("WebGLRenderer: too many bones - "+d.bones.length+", this GPU supports just "+b+" (try OpenGL instead of ANGLE)")),l=b);var s;
+e(pa,ca),za=ka.attributes&&t(ka),(ca.verticesNeedUpdate||ca.colorsNeedUpdate||pa.sortParticles||za)&&i(ca,k.DYNAMIC_DRAW,pa),ca.verticesNeedUpdate=!1,ca.colorsNeedUpdate=!1,ka.attributes&&r(ka)))}};this.initMaterial=function(a,b,c,d){var e,f,g,h,i,j,l,m,n;a instanceof THREE.MeshDepthMaterial?n="depth":a instanceof THREE.MeshNormalMaterial?n="normal":a instanceof THREE.MeshBasicMaterial?n="basic":a instanceof THREE.MeshLambertMaterial?n="lambert":a instanceof THREE.MeshPhongMaterial?n="phong":a instanceof
+THREE.LineBasicMaterial?n="basic":a instanceof THREE.LineDashedMaterial?n="dashed":a instanceof THREE.ParticleBasicMaterial&&(n="particle_basic");if(n){var o=THREE.ShaderLib[n];a.uniforms=THREE.UniformsUtils.clone(o.uniforms);a.vertexShader=o.vertexShader;a.fragmentShader=o.fragmentShader}var p,q,r;e=p=q=r=o=0;for(f=b.length;e<f;e++)g=b[e],g.onlyShadow||(g instanceof THREE.DirectionalLight&&p++,g instanceof THREE.PointLight&&q++,g instanceof THREE.SpotLight&&r++,g instanceof THREE.HemisphereLight&&
+o++);e=p;f=q;g=r;h=o;o=p=0;for(r=b.length;o<r;o++)q=b[o],q.castShadow&&(q instanceof THREE.SpotLight&&p++,q instanceof THREE.DirectionalLight&&!q.shadowCascade&&p++);m=p;fc&&d&&d.useVertexTexture?l=1024:(b=k.getParameter(k.MAX_VERTEX_UNIFORM_VECTORS),b=Math.floor((b-20)/4),void 0!==d&&d instanceof THREE.SkinnedMesh&&(b=Math.min(d.bones.length,b),b<d.bones.length&&console.warn("WebGLRenderer: too many bones - "+d.bones.length+", this GPU supports just "+b+" (try OpenGL instead of ANGLE)")),l=b);var s;
 a:{q=a.fragmentShader;r=a.vertexShader;o=a.uniforms;b=a.attributes;p=a.defines;var c={map:!!a.map,envMap:!!a.envMap,lightMap:!!a.lightMap,bumpMap:!!a.bumpMap,normalMap:!!a.normalMap,specularMap:!!a.specularMap,vertexColors:a.vertexColors,fog:c,useFog:a.fog,fogExp:c instanceof THREE.FogExp2,sizeAttenuation:a.sizeAttenuation,skinning:a.skinning,maxBones:l,useVertexTexture:fc&&d&&d.useVertexTexture,boneTextureWidth:d&&d.boneTextureWidth,boneTextureHeight:d&&d.boneTextureHeight,morphTargets:a.morphTargets,
-morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:e,maxPointLights:f,maxSpotLights:g,maxHemiLights:h,maxShadows:n,shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,alphaTest:a.alphaTest,metal:a.metal,perPixel:a.perPixel,wrapAround:a.wrapAround,doubleSided:a.side===THREE.DoubleSide,flipSided:a.side===THREE.BackSide},t,u,v,
-d=[];m?d.push(m):(d.push(q),d.push(r));for(u in p)d.push(u),d.push(p[u]);for(t in c)d.push(t),d.push(c[t]);m=d.join();t=0;for(u=ja.length;t<u;t++)if(d=ja[t],d.code===m){d.usedTimes++;s=d.program;break a}t=[];for(v in p)u=p[v],!1!==u&&(u="#define "+v+" "+u,t.push(u));u=t.join("\n");v=k.createProgram();t=["precision "+O+" float;",u,ec?"#define VERTEX_TEXTURES":"",K.gammaInput?"#define GAMMA_INPUT":"",K.gammaOutput?"#define GAMMA_OUTPUT":"",K.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":
+morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:e,maxPointLights:f,maxSpotLights:g,maxHemiLights:h,maxShadows:m,shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,alphaTest:a.alphaTest,metal:a.metal,perPixel:a.perPixel,wrapAround:a.wrapAround,doubleSided:a.side===THREE.DoubleSide,flipSided:a.side===THREE.BackSide},t,u,v,
+d=[];n?d.push(n):(d.push(q),d.push(r));for(u in p)d.push(u),d.push(p[u]);for(t in c)d.push(t),d.push(c[t]);n=d.join();t=0;for(u=ja.length;t<u;t++)if(d=ja[t],d.code===n){d.usedTimes++;s=d.program;break a}t=[];for(v in p)u=p[v],!1!==u&&(u="#define "+v+" "+u,t.push(u));u=t.join("\n");v=k.createProgram();t=["precision "+O+" float;",u,ec?"#define VERTEX_TEXTURES":"",K.gammaInput?"#define GAMMA_INPUT":"",K.gammaOutput?"#define GAMMA_OUTPUT":"",K.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":
 "","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_HEMI_LIGHTS "+c.maxHemiLights,"#define MAX_SHADOWS "+c.maxShadows,"#define MAX_BONES "+c.maxBones,c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.bumpMap?"#define USE_BUMPMAP":"",c.normalMap?"#define USE_NORMALMAP":"",c.specularMap?"#define USE_SPECULARMAP":"",c.vertexColors?"#define USE_COLOR":"",c.skinning?
 "#define USE_SKINNING":"",c.useVertexTexture?"#define BONE_TEXTURE":"",c.boneTextureWidth?"#define N_BONE_PIXEL_X "+c.boneTextureWidth.toFixed(1):"",c.boneTextureHeight?"#define N_BONE_PIXEL_Y "+c.boneTextureHeight.toFixed(1):"",c.morphTargets?"#define USE_MORPHTARGETS":"",c.morphNormals?"#define USE_MORPHNORMALS":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.flipSided?"#define FLIP_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":
 "",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 modelMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\nattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\nattribute vec3 morphTarget0;\nattribute vec3 morphTarget1;\nattribute vec3 morphTarget2;\nattribute vec3 morphTarget3;\n#ifdef USE_MORPHNORMALS\nattribute vec3 morphNormal0;\nattribute vec3 morphNormal1;\nattribute vec3 morphNormal2;\nattribute vec3 morphNormal3;\n#else\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
@@ -487,7 +487,7 @@ u=["precision "+O+" float;",c.bumpMap||c.normalMap?"#extension GL_OES_standard_d
 c.useFog&&c.fog?"#define USE_FOG":"",c.useFog&&c.fogExp?"#define FOG_EXP2":"",c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.bumpMap?"#define USE_BUMPMAP":"",c.normalMap?"#define USE_NORMALMAP":"",c.specularMap?"#define USE_SPECULARMAP":"",c.vertexColors?"#define USE_COLOR":"",c.metal?"#define METAL":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.flipSided?"#define FLIP_SIDED":
 "",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n");u=G("fragment",u+q);t=G("vertex",t+r);k.attachShader(v,t);k.attachShader(v,u);k.linkProgram(v);k.getProgramParameter(v,k.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+k.getProgramParameter(v,k.VALIDATE_STATUS)+
 ", gl error ["+k.getError()+"]");k.deleteShader(u);k.deleteShader(t);v.uniforms={};v.attributes={};var w;t="viewMatrix modelViewMatrix projectionMatrix normalMatrix modelMatrix cameraPosition morphTargetInfluences".split(" ");c.useVertexTexture?t.push("boneTexture"):t.push("boneGlobalMatrices");for(w in o)t.push(w);w=t;t=0;for(u=w.length;t<u;t++)d=w[t],v.uniforms[d]=k.getUniformLocation(v,d);t="position normal uv uv2 tangent color skinIndex skinWeight lineDistance".split(" ");for(w=0;w<c.maxMorphTargets;w++)t.push("morphTarget"+
-w);for(w=0;w<c.maxMorphNormals;w++)t.push("morphNormal"+w);for(s in b)t.push(s);s=t;w=0;for(b=s.length;w<b;w++)t=s[w],v.attributes[t]=k.getAttribLocation(v,t);v.id=Q++;ja.push({program:v,code:m,usedTimes:1});K.info.memory.programs=ja.length;s=v}a.program=s;s=a.program.attributes;0<=s.position&&k.enableVertexAttribArray(s.position);0<=s.color&&k.enableVertexAttribArray(s.color);0<=s.normal&&k.enableVertexAttribArray(s.normal);0<=s.tangent&&k.enableVertexAttribArray(s.tangent);0<=s.lineDistance&&k.enableVertexAttribArray(s.lineDistance);
+w);for(w=0;w<c.maxMorphNormals;w++)t.push("morphNormal"+w);for(s in b)t.push(s);s=t;w=0;for(b=s.length;w<b;w++)t=s[w],v.attributes[t]=k.getAttribLocation(v,t);v.id=Q++;ja.push({program:v,code:n,usedTimes:1});K.info.memory.programs=ja.length;s=v}a.program=s;s=a.program.attributes;0<=s.position&&k.enableVertexAttribArray(s.position);0<=s.color&&k.enableVertexAttribArray(s.color);0<=s.normal&&k.enableVertexAttribArray(s.normal);0<=s.tangent&&k.enableVertexAttribArray(s.tangent);0<=s.lineDistance&&k.enableVertexAttribArray(s.lineDistance);
 a.skinning&&(0<=s.skinIndex&&0<=s.skinWeight)&&(k.enableVertexAttribArray(s.skinIndex),k.enableVertexAttribArray(s.skinWeight));if(a.attributes)for(j in a.attributes)void 0!==s[j]&&0<=s[j]&&k.enableVertexAttribArray(s[j]);if(a.morphTargets){a.numSupportedMorphTargets=0;v="morphTarget";for(j=0;j<this.maxMorphTargets;j++)w=v+j,0<=s[w]&&(k.enableVertexAttribArray(s[w]),a.numSupportedMorphTargets++)}if(a.morphNormals){a.numSupportedMorphNormals=0;v="morphNormal";for(j=0;j<this.maxMorphNormals;j++)w=v+
 j,0<=s[w]&&(k.enableVertexAttribArray(s[w]),a.numSupportedMorphNormals++)}a.uniformsList=[];for(i in a.uniforms)a.uniformsList.push([a.uniforms[i],i])};this.setFaceCulling=function(a,b){a?(!b||"ccw"===b?k.frontFace(k.CCW):k.frontFace(k.CW),"back"===a?k.cullFace(k.BACK):"front"===a?k.cullFace(k.FRONT):k.cullFace(k.FRONT_AND_BACK),k.enable(k.CULL_FACE)):k.disable(k.CULL_FACE)};this.setMaterialFaces=function(a){var b=a.side===THREE.DoubleSide,a=a.side===THREE.BackSide;Na!==b&&(b?k.disable(k.CULL_FACE):
 k.enable(k.CULL_FACE),Na=b);za!==a&&(a?k.frontFace(k.CW):k.frontFace(k.CCW),za=a)};this.setDepthTest=function(a){Va!==a&&(a?k.enable(k.DEPTH_TEST):k.disable(k.DEPTH_TEST),Va=a)};this.setDepthWrite=function(a){fb!==a&&(k.depthMask(a),fb=a)};this.setBlending=function(a,b,c,d){a!==Oa&&(a===THREE.NoBlending?k.disable(k.BLEND):a===THREE.AdditiveBlending?(k.enable(k.BLEND),k.blendEquation(k.FUNC_ADD),k.blendFunc(k.SRC_ALPHA,k.ONE)):a===THREE.SubtractiveBlending?(k.enable(k.BLEND),k.blendEquation(k.FUNC_ADD),

+ 28 - 17
src/core/BufferGeometry.js

@@ -50,10 +50,13 @@ THREE.BufferGeometry.prototype = {
 
 		if ( normalArray !== undefined ) {
 
-			var matrixRotation = new THREE.Matrix4();
-			matrixRotation.extractRotation( matrix );
+			var normalMatrix = new THREE.Matrix3();
+			normalMatrix.getInverse( matrix ).transpose();
+
+			normalMatrix.multiplyVector3Array( normalArray );
+
+			this.normalizeNormals();
 
-			matrixRotation.multiplyVector3Array( normalArray );
 			this.normalsNeedUpdate = true;
 
 		}
@@ -236,15 +239,15 @@ THREE.BufferGeometry.prototype = {
 					ab.sub( pA, pB );
 					cb.crossSelf( ab );
 
-					normals[ vA * 3 ] += cb.x;
+					normals[ vA * 3 ] 	  += cb.x;
 					normals[ vA * 3 + 1 ] += cb.y;
 					normals[ vA * 3 + 2 ] += cb.z;
 
-					normals[ vB * 3 ] += cb.x;
+					normals[ vB * 3 ] 	  += cb.x;
 					normals[ vB * 3 + 1 ] += cb.y;
 					normals[ vB * 3 + 2 ] += cb.z;
 
-					normals[ vC * 3 ] += cb.x;
+					normals[ vC * 3 ] 	  += cb.x;
 					normals[ vC * 3 + 1 ] += cb.y;
 					normals[ vC * 3 + 2 ] += cb.z;
 
@@ -252,23 +255,31 @@ THREE.BufferGeometry.prototype = {
 
 			}
 
-			// normalize normals
+			this.normalizeNormals();
 
-			for ( i = 0, il = normals.length; i < il; i += 3 ) {
+			this.normalsNeedUpdate = true;
 
-				x = normals[ i ];
-				y = normals[ i + 1 ];
-				z = normals[ i + 2 ];
+		}
 
-				var n = 1.0 / Math.sqrt( x * x + y * y + z * z );
+	},
 
-				normals[ i ] *= n;
-				normals[ i + 1 ] *= n;
-				normals[ i + 2 ] *= n;
+	normalizeNormals: function () {
 
-			}
+		var normals = this.attributes[ "normal" ].array;
 
-			this.normalsNeedUpdate = true;
+		var x, y, z, n;
+
+		for ( var i = 0, il = normals.length; i < il; i += 3 ) {
+
+			x = normals[ i ];
+			y = normals[ i + 1 ];
+			z = normals[ i + 2 ];
+
+			n = 1.0 / Math.sqrt( x * x + y * y + z * z );
+
+			normals[ i ] 	 *= n;
+			normals[ i + 1 ] *= n;
+			normals[ i + 2 ] *= n;
 
 		}
 

+ 28 - 4
src/core/Matrix3.js

@@ -27,13 +27,35 @@ THREE.Matrix3.prototype = {
 
 	},
 
+	multiplyVector3Array: function ( a ) {
+
+		var tmp = THREE.Matrix3.__v1;
+
+		for ( var i = 0, il = a.length; i < il; i += 3 ) {
+
+			tmp.x = a[ i ];
+			tmp.y = a[ i + 1 ];
+			tmp.z = a[ i + 2 ];
+
+			this.multiplyVector3( tmp );
+
+			a[ i ]     = tmp.x;
+			a[ i + 1 ] = tmp.y;
+			a[ i + 2 ] = tmp.z;
+
+		}
+
+		return a;
+
+	},
+
 	getInverse: function ( matrix ) {
 
 		// input: THREE.Matrix4
 		// ( based on http://code.google.com/p/webgl-mjs/ )
 
-        var me = matrix.elements;
-        
+		var me = matrix.elements;
+
 		var a11 =   me[10] * me[5] - me[6] * me[9];
 		var a21 = - me[10] * me[1] + me[2] * me[9];
 		var a31 =   me[6] * me[1] - me[2] * me[5];
@@ -66,7 +88,7 @@ THREE.Matrix3.prototype = {
 
 	},
 
-	
+
 	transpose: function () {
 
 		var tmp, m = this.elements;
@@ -78,7 +100,7 @@ THREE.Matrix3.prototype = {
 		return this;
 
 	},
-	
+
 
 	transposeIntoArray: function ( r ) {
 
@@ -99,3 +121,5 @@ THREE.Matrix3.prototype = {
 	}
 
 };
+
+THREE.Matrix3.__v1 = new THREE.Vector3();