Forráskód Böngészése

Added area weighted vertex normals computation to Geometry.

See discussion in #2613

Finally I just left it behind a flag. I was not able to get as good results for TextGeometry as with unweighted method and split materials for side and front faces.

I wonder how I got that nice look as in screenshot I posted in the issue. It still does look better with weighted than unweighted but nowhere so close as in that screenshot. Either I did some mistake when testing before or there is some bug in implementation now.
alteredq 12 éve
szülő
commit
b5390e9395
3 módosított fájl, 179 hozzáadás és 54 törlés
  1. 74 12
      build/three.js
  2. 31 30
      build/three.min.js
  3. 74 12
      src/core/Geometry.js

+ 74 - 12
build/three.js

@@ -5123,7 +5123,7 @@ THREE.Geometry.prototype = {
 
 	},
 
-	computeVertexNormals: function () {
+	computeVertexNormals: function ( areaWeighted ) {
 
 		var v, vl, f, fl, face, vertices;
 
@@ -5169,22 +5169,84 @@ THREE.Geometry.prototype = {
 
 		}
 
-		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+		if ( areaWeighted ) {
 
-			face = this.faces[ f ];
+			// vertex normals weighted by triangle areas
+			// http://www.iquilezles.org/www/articles/normals/normals.htm
 
-			if ( face instanceof THREE.Face3 ) {
+			var vA, vB, vC, vD;
+			var cb = new THREE.Vector3(), ab = new THREE.Vector3(),
+				db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3();
+
+			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 
-				vertices[ face.a ].addSelf( face.normal );
-				vertices[ face.b ].addSelf( face.normal );
-				vertices[ face.c ].addSelf( face.normal );
+				face = this.faces[ f ];
 
-			} else if ( face instanceof THREE.Face4 ) {
+				if ( face instanceof THREE.Face3 ) {
+
+					vA = this.vertices[ face.a ];
+					vB = this.vertices[ face.b ];
+					vC = this.vertices[ face.c ];
+
+					cb.sub( vC, vB );
+					ab.sub( vA, vB );
+					cb.crossSelf( ab );
+
+					vertices[ face.a ].addSelf( cb );
+					vertices[ face.b ].addSelf( cb );
+					vertices[ face.c ].addSelf( cb );
+
+				} else if ( face instanceof THREE.Face4 ) {
+
+					vA = this.vertices[ face.a ];
+					vB = this.vertices[ face.b ];
+					vC = this.vertices[ face.c ];
+					vD = this.vertices[ face.d ];
+
+					// abd
+
+					db.sub( vD, vB );
+					ab.sub( vA, vB );
+					db.crossSelf( ab );
+
+					vertices[ face.a ].addSelf( db );
+					vertices[ face.b ].addSelf( db );
+					vertices[ face.d ].addSelf( db );
+
+					// bcd
 
-				vertices[ face.a ].addSelf( face.normal );
-				vertices[ face.b ].addSelf( face.normal );
-				vertices[ face.c ].addSelf( face.normal );
-				vertices[ face.d ].addSelf( face.normal );
+					dc.sub( vD, vC );
+					bc.sub( vB, vC );
+					dc.crossSelf( bc );
+
+					vertices[ face.b ].addSelf( dc );
+					vertices[ face.c ].addSelf( dc );
+					vertices[ face.d ].addSelf( dc );
+
+				}
+
+			}
+
+		} else {
+
+			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+
+				face = this.faces[ f ];
+
+				if ( face instanceof THREE.Face3 ) {
+
+					vertices[ face.a ].addSelf( face.normal );
+					vertices[ face.b ].addSelf( face.normal );
+					vertices[ face.c ].addSelf( face.normal );
+
+				} else if ( face instanceof THREE.Face4 ) {
+
+					vertices[ face.a ].addSelf( face.normal );
+					vertices[ face.b ].addSelf( face.normal );
+					vertices[ face.c ].addSelf( face.normal );
+					vertices[ face.d ].addSelf( face.normal );
+
+				}
 
 			}
 

+ 31 - 30
build/three.min.js

@@ -107,19 +107,20 @@ THREE.Geometry=function(){THREE.GeometryLibrary.push(this);this.id=THREE.Geometr
 this.tangentsNeedUpdate=this.normalsNeedUpdate=this.uvsNeedUpdate=this.elementsNeedUpdate=this.verticesNeedUpdate=!1};
 THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){var b=new THREE.Matrix3;b.getInverse(a).transpose();for(var c=0,d=this.vertices.length;c<d;c++)a.multiplyVector3(this.vertices[c]);c=0;for(d=this.faces.length;c<d;c++){var e=this.faces[c];b.multiplyVector3(e.normal).normalize();for(var f=0,g=e.vertexNormals.length;f<g;f++)b.multiplyVector3(e.vertexNormals[f]).normalize();a.multiplyVector3(e.centroid)}},computeCentroids:function(){var a,b,c;a=0;for(b=this.faces.length;a<b;a++)c=
 this.faces[a],c.centroid.set(0,0,0),c instanceof THREE.Face3?(c.centroid.addSelf(this.vertices[c.a]),c.centroid.addSelf(this.vertices[c.b]),c.centroid.addSelf(this.vertices[c.c]),c.centroid.divideScalar(3)):c instanceof THREE.Face4&&(c.centroid.addSelf(this.vertices[c.a]),c.centroid.addSelf(this.vertices[c.b]),c.centroid.addSelf(this.vertices[c.c]),c.centroid.addSelf(this.vertices[c.d]),c.centroid.divideScalar(4))},computeFaceNormals:function(){var a,b,c,d,e,f,g=new THREE.Vector3,h=new THREE.Vector3;
-a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],d=this.vertices[c.a],e=this.vertices[c.b],f=this.vertices[c.c],g.sub(f,e),h.sub(d,e),g.crossSelf(h),g.isZero()||g.normalize(),c.normal.copy(g)},computeVertexNormals:function(){var a,b,c,d;if(void 0===this.__tmpVertices){d=this.__tmpVertices=Array(this.vertices.length);a=0;for(b=this.vertices.length;a<b;a++)d[a]=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],c instanceof THREE.Face3?c.vertexNormals=[new THREE.Vector3,new THREE.Vector3,
-new THREE.Vector3]:c instanceof THREE.Face4&&(c.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3])}else{d=this.__tmpVertices;a=0;for(b=this.vertices.length;a<b;a++)d[a].set(0,0,0)}a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],c instanceof THREE.Face3?(d[c.a].addSelf(c.normal),d[c.b].addSelf(c.normal),d[c.c].addSelf(c.normal)):c instanceof THREE.Face4&&(d[c.a].addSelf(c.normal),d[c.b].addSelf(c.normal),d[c.c].addSelf(c.normal),d[c.d].addSelf(c.normal));a=
-0;for(b=this.vertices.length;a<b;a++)d[a].normalize();a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],c instanceof THREE.Face3?(c.vertexNormals[0].copy(d[c.a]),c.vertexNormals[1].copy(d[c.b]),c.vertexNormals[2].copy(d[c.c])):c instanceof THREE.Face4&&(c.vertexNormals[0].copy(d[c.a]),c.vertexNormals[1].copy(d[c.b]),c.vertexNormals[2].copy(d[c.c]),c.vertexNormals[3].copy(d[c.d]))},computeMorphNormals:function(){var a,b,c,d,e;c=0;for(d=this.faces.length;c<d;c++){e=this.faces[c];e.__originalFaceNormal?
-e.__originalFaceNormal.copy(e.normal):e.__originalFaceNormal=e.normal.clone();e.__originalVertexNormals||(e.__originalVertexNormals=[]);a=0;for(b=e.vertexNormals.length;a<b;a++)e.__originalVertexNormals[a]?e.__originalVertexNormals[a].copy(e.vertexNormals[a]):e.__originalVertexNormals[a]=e.vertexNormals[a].clone()}var f=new THREE.Geometry;f.faces=this.faces;a=0;for(b=this.morphTargets.length;a<b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};this.morphNormals[a].faceNormals=[];this.morphNormals[a].vertexNormals=
-[];var g=this.morphNormals[a].faceNormals,h=this.morphNormals[a].vertexNormals,i,j;c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],i=new THREE.Vector3,j=e instanceof THREE.Face3?{a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3}:{a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3,d:new THREE.Vector3},g.push(i),h.push(j)}g=this.morphNormals[a];f.vertices=this.morphTargets[a].vertices;f.computeFaceNormals();f.computeVertexNormals();c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],
-i=g.faceNormals[c],j=g.vertexNormals[c],i.copy(e.normal),e instanceof THREE.Face3?(j.a.copy(e.vertexNormals[0]),j.b.copy(e.vertexNormals[1]),j.c.copy(e.vertexNormals[2])):(j.a.copy(e.vertexNormals[0]),j.b.copy(e.vertexNormals[1]),j.c.copy(e.vertexNormals[2]),j.d.copy(e.vertexNormals[3]))}c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],e.normal=e.__originalFaceNormal,e.vertexNormals=e.__originalVertexNormals},computeTangents:function(){function a(a,b,c,d,e,f,v){h=a.vertices[b];i=a.vertices[c];
-j=a.vertices[d];m=g[e];n=g[f];l=g[v];o=i.x-h.x;p=j.x-h.x;q=i.y-h.y;t=j.y-h.y;r=i.z-h.z;A=j.z-h.z;u=n.u-m.u;s=l.u-m.u;D=n.v-m.v;z=l.v-m.v;w=1/(u*z-s*D);G.set((z*o-D*p)*w,(z*q-D*t)*w,(z*r-D*A)*w);L.set((u*p-s*o)*w,(u*t-s*q)*w,(u*A-s*r)*w);C[b].addSelf(G);C[c].addSelf(G);C[d].addSelf(G);E[b].addSelf(L);E[c].addSelf(L);E[d].addSelf(L)}var b,c,d,e,f,g,h,i,j,m,n,l,o,p,q,t,r,A,u,s,D,z,w,v,C=[],E=[],G=new THREE.Vector3,L=new THREE.Vector3,B=new THREE.Vector3,J=new THREE.Vector3,H=new THREE.Vector3;b=0;for(c=
-this.vertices.length;b<c;b++)C[b]=new THREE.Vector3,E[b]=new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)f=this.faces[b],g=this.faceVertexUvs[0][b],f instanceof THREE.Face3?a(this,f.a,f.b,f.c,0,1,2):f instanceof THREE.Face4&&(a(this,f.a,f.b,f.d,0,1,3),a(this,f.b,f.c,f.d,1,2,3));var I=["a","b","c","d"];b=0;for(c=this.faces.length;b<c;b++){f=this.faces[b];for(d=0;d<f.vertexNormals.length;d++)H.copy(f.vertexNormals[d]),e=f[I[d]],v=C[e],B.copy(v),B.subSelf(H.multiplyScalar(H.dot(v))).normalize(),
-J.cross(f.vertexNormals[d],v),e=J.dot(E[e]),e=0>e?-1:1,f.vertexTangents[d]=new THREE.Vector4(B.x,B.y,B.z,e)}this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;c<d;c++)0<c&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){this.boundingBox||(this.boundingBox={min:new THREE.Vector3,max:new THREE.Vector3});if(0<this.vertices.length){var a;a=this.vertices[0];this.boundingBox.min.copy(a);this.boundingBox.max.copy(a);for(var b=
-this.boundingBox.min,c=this.boundingBox.max,d=1,e=this.vertices.length;d<e;d++)(a=this.vertices[d],a.x<b.x?b.x=a.x:a.x>c.x&&(c.x=a.x),a.y<b.y?b.y=a.y:a.y>c.y&&(c.y=a.y),a.z<b.z)?b.z=a.z:a.z>c.z&&(c.z=a.z)}else this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){var a=0;null===this.boundingSphere&&(this.boundingSphere={radius:0});for(var b=0,c=this.vertices.length;b<c;b++){var d=this.vertices[b].lengthSq();d>a&&(a=d)}this.boundingSphere.radius=Math.sqrt(a)},
-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=[]};
+a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],d=this.vertices[c.a],e=this.vertices[c.b],f=this.vertices[c.c],g.sub(f,e),h.sub(d,e),g.crossSelf(h),g.isZero()||g.normalize(),c.normal.copy(g)},computeVertexNormals:function(a){var b,c,d,e;if(void 0===this.__tmpVertices){e=this.__tmpVertices=Array(this.vertices.length);b=0;for(c=this.vertices.length;b<c;b++)e[b]=new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d instanceof THREE.Face3?d.vertexNormals=[new THREE.Vector3,new THREE.Vector3,
+new THREE.Vector3]:d instanceof THREE.Face4&&(d.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3])}else{e=this.__tmpVertices;b=0;for(c=this.vertices.length;b<c;b++)e[b].set(0,0,0)}if(a){var f,g,h,i=new THREE.Vector3,j=new THREE.Vector3,m=new THREE.Vector3,n=new THREE.Vector3,l=new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d instanceof THREE.Face3?(a=this.vertices[d.a],f=this.vertices[d.b],g=this.vertices[d.c],i.sub(g,f),j.sub(a,f),i.crossSelf(j),
+e[d.a].addSelf(i),e[d.b].addSelf(i),e[d.c].addSelf(i)):d instanceof THREE.Face4&&(a=this.vertices[d.a],f=this.vertices[d.b],g=this.vertices[d.c],h=this.vertices[d.d],m.sub(h,f),j.sub(a,f),m.crossSelf(j),e[d.a].addSelf(m),e[d.b].addSelf(m),e[d.d].addSelf(m),n.sub(h,g),l.sub(f,g),n.crossSelf(l),e[d.b].addSelf(n),e[d.c].addSelf(n),e[d.d].addSelf(n))}else{b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d instanceof THREE.Face3?(e[d.a].addSelf(d.normal),e[d.b].addSelf(d.normal),e[d.c].addSelf(d.normal)):
+d instanceof THREE.Face4&&(e[d.a].addSelf(d.normal),e[d.b].addSelf(d.normal),e[d.c].addSelf(d.normal),e[d.d].addSelf(d.normal))}b=0;for(c=this.vertices.length;b<c;b++)e[b].normalize();b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d instanceof THREE.Face3?(d.vertexNormals[0].copy(e[d.a]),d.vertexNormals[1].copy(e[d.b]),d.vertexNormals[2].copy(e[d.c])):d instanceof THREE.Face4&&(d.vertexNormals[0].copy(e[d.a]),d.vertexNormals[1].copy(e[d.b]),d.vertexNormals[2].copy(e[d.c]),d.vertexNormals[3].copy(e[d.d]))},
+computeMorphNormals:function(){var a,b,c,d,e;c=0;for(d=this.faces.length;c<d;c++){e=this.faces[c];e.__originalFaceNormal?e.__originalFaceNormal.copy(e.normal):e.__originalFaceNormal=e.normal.clone();e.__originalVertexNormals||(e.__originalVertexNormals=[]);a=0;for(b=e.vertexNormals.length;a<b;a++)e.__originalVertexNormals[a]?e.__originalVertexNormals[a].copy(e.vertexNormals[a]):e.__originalVertexNormals[a]=e.vertexNormals[a].clone()}var f=new THREE.Geometry;f.faces=this.faces;a=0;for(b=this.morphTargets.length;a<
+b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};this.morphNormals[a].faceNormals=[];this.morphNormals[a].vertexNormals=[];var g=this.morphNormals[a].faceNormals,h=this.morphNormals[a].vertexNormals,i,j;c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],i=new THREE.Vector3,j=e instanceof THREE.Face3?{a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3}:{a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3,d:new THREE.Vector3},g.push(i),h.push(j)}g=this.morphNormals[a];f.vertices=
+this.morphTargets[a].vertices;f.computeFaceNormals();f.computeVertexNormals();c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],i=g.faceNormals[c],j=g.vertexNormals[c],i.copy(e.normal),e instanceof THREE.Face3?(j.a.copy(e.vertexNormals[0]),j.b.copy(e.vertexNormals[1]),j.c.copy(e.vertexNormals[2])):(j.a.copy(e.vertexNormals[0]),j.b.copy(e.vertexNormals[1]),j.c.copy(e.vertexNormals[2]),j.d.copy(e.vertexNormals[3]))}c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],e.normal=e.__originalFaceNormal,
+e.vertexNormals=e.__originalVertexNormals},computeTangents:function(){function a(a,b,c,d,e,f,v){h=a.vertices[b];i=a.vertices[c];j=a.vertices[d];m=g[e];n=g[f];l=g[v];o=i.x-h.x;p=j.x-h.x;q=i.y-h.y;t=j.y-h.y;r=i.z-h.z;A=j.z-h.z;u=n.u-m.u;s=l.u-m.u;D=n.v-m.v;z=l.v-m.v;w=1/(u*z-s*D);G.set((z*o-D*p)*w,(z*q-D*t)*w,(z*r-D*A)*w);L.set((u*p-s*o)*w,(u*t-s*q)*w,(u*A-s*r)*w);C[b].addSelf(G);C[c].addSelf(G);C[d].addSelf(G);E[b].addSelf(L);E[c].addSelf(L);E[d].addSelf(L)}var b,c,d,e,f,g,h,i,j,m,n,l,o,p,q,t,r,A,
+u,s,D,z,w,v,C=[],E=[],G=new THREE.Vector3,L=new THREE.Vector3,B=new THREE.Vector3,J=new THREE.Vector3,H=new THREE.Vector3;b=0;for(c=this.vertices.length;b<c;b++)C[b]=new THREE.Vector3,E[b]=new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)f=this.faces[b],g=this.faceVertexUvs[0][b],f instanceof THREE.Face3?a(this,f.a,f.b,f.c,0,1,2):f instanceof THREE.Face4&&(a(this,f.a,f.b,f.d,0,1,3),a(this,f.b,f.c,f.d,1,2,3));var I=["a","b","c","d"];b=0;for(c=this.faces.length;b<c;b++){f=this.faces[b];for(d=0;d<
+f.vertexNormals.length;d++)H.copy(f.vertexNormals[d]),e=f[I[d]],v=C[e],B.copy(v),B.subSelf(H.multiplyScalar(H.dot(v))).normalize(),J.cross(f.vertexNormals[d],v),e=J.dot(E[e]),e=0>e?-1:1,f.vertexTangents[d]=new THREE.Vector4(B.x,B.y,B.z,e)}this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;c<d;c++)0<c&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){this.boundingBox||(this.boundingBox={min:new THREE.Vector3,max:new THREE.Vector3});
+if(0<this.vertices.length){var a;a=this.vertices[0];this.boundingBox.min.copy(a);this.boundingBox.max.copy(a);for(var b=this.boundingBox.min,c=this.boundingBox.max,d=1,e=this.vertices.length;d<e;d++)(a=this.vertices[d],a.x<b.x?b.x=a.x:a.x>c.x&&(c.x=a.x),a.y<b.y?b.y=a.y:a.y>c.y&&(c.y=a.y),a.z<b.z)?b.z=a.z:a.z>c.z&&(c.z=a.z)}else this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){var a=0;null===this.boundingSphere&&(this.boundingSphere={radius:0});for(var b=
+0,c=this.vertices.length;b<c;b++){var d=this.vertices[b].lengthSq();d>a&&(a=d)}this.boundingSphere.radius=Math.sqrt(a)},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.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]=
@@ -280,19 +281,19 @@ THREE.CanvasRenderer=function(a){function b(a){A!==a&&(A=q.globalAlpha=a)}functi
 document.createElement("canvas"),n,l,o,p,q=m.getContext("2d"),t=new THREE.Color(0),r=0,A=1,u=0,s=null,D=null,z=null,w=null,v=null,C,E,G,L,B=new THREE.RenderableVertex,J=new THREE.RenderableVertex,H,I,O,N,M,T,R,P,S,$,K,ja,Q=new THREE.Color,ha=new THREE.Color,da=new THREE.Color,Y=new THREE.Color,aa=new THREE.Color,ba=new THREE.Color,ia=new THREE.Color,ya={},Na={},za,Oa,Aa,pa,xb,Va,fb,kb,Bb,Cb,eb=new THREE.Rectangle,Ra=new THREE.Rectangle,Ia=new THREE.Rectangle,lb=!1,La=new THREE.Color,$a=new THREE.Color,
 db=new THREE.Color,ka=new THREE.Vector3,ab,bb,mb,ua,gb,qb,a=16;ab=document.createElement("canvas");ab.width=ab.height=2;bb=ab.getContext("2d");bb.fillStyle="rgba(0,0,0,1)";bb.fillRect(0,0,2,2);mb=bb.getImageData(0,0,2,2);ua=mb.data;gb=document.createElement("canvas");gb.width=gb.height=a;qb=gb.getContext("2d");qb.translate(-a/2,-a/2);qb.scale(a,a);a--;this.domElement=m;this.sortElements=this.sortObjects=this.autoClear=!0;this.info={render:{vertices:0,faces:0}};this.setSize=function(a,b){n=a;l=b;o=
 Math.floor(n/2);p=Math.floor(l/2);m.width=n;m.height=l;eb.set(-o,-p,o,p);Ra.set(-o,-p,o,p);A=1;u=0;v=w=z=D=s=null};this.setClearColor=function(a,b){t.copy(a);r=void 0!==b?b:1;Ra.set(-o,-p,o,p)};this.setClearColorHex=function(a,b){t.setHex(a);r=void 0!==b?b:1;Ra.set(-o,-p,o,p)};this.getMaxAnisotropy=function(){return 0};this.clear=function(){q.setTransform(1,0,0,-1,o,p);!1===Ra.isEmpty()&&(Ra.minSelf(eb),Ra.inflate(2),1>r&&q.clearRect(Math.floor(Ra.getX()),Math.floor(Ra.getY()),Math.floor(Ra.getWidth()),
-Math.floor(Ra.getHeight())),0<r&&(c(THREE.NormalBlending),b(1),e("rgba("+Math.floor(255*t.r)+","+Math.floor(255*t.g)+","+Math.floor(255*t.b)+","+r+")"),q.fillRect(Math.floor(Ra.getX()),Math.floor(Ra.getY()),Math.floor(Ra.getWidth()),Math.floor(Ra.getHeight()))),Ra.empty())};this.render=function(a,l){function m(a,b,c){for(var d=0,e=i.length;d<e;d++){var f=i[d],g=f.color;if(f instanceof THREE.DirectionalLight){var h=f.matrixWorld.getPosition().normalize(),k=b.dot(h);0>=k||(k*=f.intensity,c.r+=g.r*k,
+Math.floor(Ra.getHeight())),0<r&&(c(THREE.NormalBlending),b(1),e("rgba("+Math.floor(255*t.r)+","+Math.floor(255*t.g)+","+Math.floor(255*t.b)+","+r+")"),q.fillRect(Math.floor(Ra.getX()),Math.floor(Ra.getY()),Math.floor(Ra.getWidth()),Math.floor(Ra.getHeight()))),Ra.empty())};this.render=function(a,m){function l(a,b,c){for(var d=0,e=i.length;d<e;d++){var f=i[d],g=f.color;if(f instanceof THREE.DirectionalLight){var h=f.matrixWorld.getPosition().normalize(),k=b.dot(h);0>=k||(k*=f.intensity,c.r+=g.r*k,
 c.g+=g.g*k,c.b+=g.b*k)}else f instanceof THREE.PointLight&&(h=f.matrixWorld.getPosition(),k=b.dot(ka.sub(h,a).normalize()),0>=k||(k*=0==f.distance?1:1-Math.min(a.distanceTo(h)/f.distance,1),0!=k&&(k*=f.intensity,c.r+=g.r*k,c.g+=g.g*k,c.b+=g.b*k)))}}function n(a,d,e,g,h,k,i,j){f.info.render.vertices+=3;f.info.render.faces++;b(j.opacity);c(j.blending);H=a.positionScreen.x;I=a.positionScreen.y;O=d.positionScreen.x;N=d.positionScreen.y;M=e.positionScreen.x;T=e.positionScreen.y;r(H,I,O,N,M,T);(j instanceof
-THREE.MeshLambertMaterial||j instanceof THREE.MeshPhongMaterial)&&null===j.map&&null===j.map?(ba.copy(j.color),ia.copy(j.emissive),j.vertexColors===THREE.FaceColors&&(ba.r*=i.color.r,ba.g*=i.color.g,ba.b*=i.color.b),!0===lb)?!1===j.wireframe&&j.shading==THREE.SmoothShading&&3==i.vertexNormalsLength?(ha.r=da.r=Y.r=La.r,ha.g=da.g=Y.g=La.g,ha.b=da.b=Y.b=La.b,m(i.v1.positionWorld,i.vertexNormalsWorld[0],ha),m(i.v2.positionWorld,i.vertexNormalsWorld[1],da),m(i.v3.positionWorld,i.vertexNormalsWorld[2],
-Y),ha.r=ha.r*ba.r+ia.r,ha.g=ha.g*ba.g+ia.g,ha.b=ha.b*ba.b+ia.b,da.r=da.r*ba.r+ia.r,da.g=da.g*ba.g+ia.g,da.b=da.b*ba.b+ia.b,Y.r=Y.r*ba.r+ia.r,Y.g=Y.g*ba.g+ia.g,Y.b=Y.b*ba.b+ia.b,aa.r=0.5*(da.r+Y.r),aa.g=0.5*(da.g+Y.g),aa.b=0.5*(da.b+Y.b),Aa=wc(ha,da,Y,aa),ma(H,I,O,N,M,T,0,0,1,0,0,1,Aa)):(Q.r=La.r,Q.g=La.g,Q.b=La.b,m(i.centroidWorld,i.normalWorld,Q),Q.r=Q.r*ba.r+ia.r,Q.g=Q.g*ba.g+ia.g,Q.b=Q.b*ba.b+ia.b,!0===j.wireframe?s(Q,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):u(Q)):!0===j.wireframe?
-s(j.color,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):u(j.color):j instanceof THREE.MeshBasicMaterial||j instanceof THREE.MeshLambertMaterial||j instanceof THREE.MeshPhongMaterial?null!==j.map?j.map.mapping instanceof THREE.UVMapping&&(pa=i.uvs[0],A(H,I,O,N,M,T,pa[g].u,pa[g].v,pa[h].u,pa[h].v,pa[k].u,pa[k].v,j.map)):null!==j.envMap?j.envMap.mapping instanceof THREE.SphericalReflectionMapping&&(a=l.matrixWorldInverse,ka.copy(i.vertexNormalsWorld[g]),xb=0.5*(ka.x*a.elements[0]+ka.y*
+THREE.MeshLambertMaterial||j instanceof THREE.MeshPhongMaterial)&&null===j.map&&null===j.map?(ba.copy(j.color),ia.copy(j.emissive),j.vertexColors===THREE.FaceColors&&(ba.r*=i.color.r,ba.g*=i.color.g,ba.b*=i.color.b),!0===lb)?!1===j.wireframe&&j.shading==THREE.SmoothShading&&3==i.vertexNormalsLength?(ha.r=da.r=Y.r=La.r,ha.g=da.g=Y.g=La.g,ha.b=da.b=Y.b=La.b,l(i.v1.positionWorld,i.vertexNormalsWorld[0],ha),l(i.v2.positionWorld,i.vertexNormalsWorld[1],da),l(i.v3.positionWorld,i.vertexNormalsWorld[2],
+Y),ha.r=ha.r*ba.r+ia.r,ha.g=ha.g*ba.g+ia.g,ha.b=ha.b*ba.b+ia.b,da.r=da.r*ba.r+ia.r,da.g=da.g*ba.g+ia.g,da.b=da.b*ba.b+ia.b,Y.r=Y.r*ba.r+ia.r,Y.g=Y.g*ba.g+ia.g,Y.b=Y.b*ba.b+ia.b,aa.r=0.5*(da.r+Y.r),aa.g=0.5*(da.g+Y.g),aa.b=0.5*(da.b+Y.b),Aa=wc(ha,da,Y,aa),ma(H,I,O,N,M,T,0,0,1,0,0,1,Aa)):(Q.r=La.r,Q.g=La.g,Q.b=La.b,l(i.centroidWorld,i.normalWorld,Q),Q.r=Q.r*ba.r+ia.r,Q.g=Q.g*ba.g+ia.g,Q.b=Q.b*ba.b+ia.b,!0===j.wireframe?s(Q,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):u(Q)):!0===j.wireframe?
+s(j.color,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):u(j.color):j instanceof THREE.MeshBasicMaterial||j instanceof THREE.MeshLambertMaterial||j instanceof THREE.MeshPhongMaterial?null!==j.map?j.map.mapping instanceof THREE.UVMapping&&(pa=i.uvs[0],A(H,I,O,N,M,T,pa[g].u,pa[g].v,pa[h].u,pa[h].v,pa[k].u,pa[k].v,j.map)):null!==j.envMap?j.envMap.mapping instanceof THREE.SphericalReflectionMapping&&(a=m.matrixWorldInverse,ka.copy(i.vertexNormalsWorld[g]),xb=0.5*(ka.x*a.elements[0]+ka.y*
 a.elements[4]+ka.z*a.elements[8])+0.5,Va=0.5*(ka.x*a.elements[1]+ka.y*a.elements[5]+ka.z*a.elements[9])+0.5,ka.copy(i.vertexNormalsWorld[h]),fb=0.5*(ka.x*a.elements[0]+ka.y*a.elements[4]+ka.z*a.elements[8])+0.5,kb=0.5*(ka.x*a.elements[1]+ka.y*a.elements[5]+ka.z*a.elements[9])+0.5,ka.copy(i.vertexNormalsWorld[k]),Bb=0.5*(ka.x*a.elements[0]+ka.y*a.elements[4]+ka.z*a.elements[8])+0.5,Cb=0.5*(ka.x*a.elements[1]+ka.y*a.elements[5]+ka.z*a.elements[9])+0.5,A(H,I,O,N,M,T,xb,Va,fb,kb,Bb,Cb,j.envMap)):(Q.copy(j.color),
-j.vertexColors===THREE.FaceColors&&(Q.r*=i.color.r,Q.g*=i.color.g,Q.b*=i.color.b),!0===j.wireframe?s(Q,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):u(Q)):j instanceof THREE.MeshDepthMaterial?(za=l.near,Oa=l.far,ha.r=ha.g=ha.b=1-nb(a.positionScreen.z,za,Oa),da.r=da.g=da.b=1-nb(d.positionScreen.z,za,Oa),Y.r=Y.g=Y.b=1-nb(e.positionScreen.z,za,Oa),aa.r=0.5*(da.r+Y.r),aa.g=0.5*(da.g+Y.g),aa.b=0.5*(da.b+Y.b),Aa=wc(ha,da,Y,aa),ma(H,I,O,N,M,T,0,0,1,0,0,1,Aa)):j instanceof THREE.MeshNormalMaterial&&
+j.vertexColors===THREE.FaceColors&&(Q.r*=i.color.r,Q.g*=i.color.g,Q.b*=i.color.b),!0===j.wireframe?s(Q,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):u(Q)):j instanceof THREE.MeshDepthMaterial?(za=m.near,Oa=m.far,ha.r=ha.g=ha.b=1-nb(a.positionScreen.z,za,Oa),da.r=da.g=da.b=1-nb(d.positionScreen.z,za,Oa),Y.r=Y.g=Y.b=1-nb(e.positionScreen.z,za,Oa),aa.r=0.5*(da.r+Y.r),aa.g=0.5*(da.g+Y.g),aa.b=0.5*(da.b+Y.b),Aa=wc(ha,da,Y,aa),ma(H,I,O,N,M,T,0,0,1,0,0,1,Aa)):j instanceof THREE.MeshNormalMaterial&&
 (Q.r=gc(i.normalWorld.x),Q.g=gc(i.normalWorld.y),Q.b=gc(i.normalWorld.z),!0===j.wireframe?s(Q,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):u(Q))}function r(a,b,c,d,e,f){q.beginPath();q.moveTo(a,b);q.lineTo(c,d);q.lineTo(e,f);q.closePath()}function t(a,b,c,d,e,f,g,h){q.beginPath();q.moveTo(a,b);q.lineTo(c,d);q.lineTo(e,f);q.lineTo(g,h);q.closePath()}function s(a,b,c,e){z!==b&&(z=q.lineWidth=b);w!==c&&(w=q.lineCap=c);v!==e&&(v=q.lineJoin=e);d(a.getContextStyle());q.stroke();Ia.inflate(2*
 b)}function u(a){e(a.getContextStyle());q.fill()}function A(a,b,c,d,f,g,h,k,i,j,l,m,ma){if(!(ma instanceof THREE.DataTexture||void 0===ma.image||0==ma.image.width)){if(!0===ma.needsUpdate){var n=ma.wrapS==THREE.RepeatWrapping,nb=ma.wrapT==THREE.RepeatWrapping;ya[ma.id]=q.createPattern(ma.image,!0===n&&!0===nb?"repeat":!0===n&&!1===nb?"repeat-x":!1===n&&!0===nb?"repeat-y":"no-repeat");ma.needsUpdate=!1}void 0===ya[ma.id]?e("rgba(0,0,0,1)"):e(ya[ma.id]);var n=ma.offset.x/ma.repeat.x,nb=ma.offset.y/
 ma.repeat.y,o=ma.image.width*ma.repeat.x,p=ma.image.height*ma.repeat.y,h=(h+n)*o,k=(1-k+nb)*p,c=c-a,d=d-b,f=f-a,g=g-b,i=(i+n)*o-h,j=(1-j+nb)*p-k,l=(l+n)*o-h,m=(1-m+nb)*p-k,n=i*m-l*j;0===n?(void 0===Na[ma.id]&&(b=document.createElement("canvas"),b.width=ma.image.width,b.height=ma.image.height,b=b.getContext("2d"),b.drawImage(ma.image,0,0),Na[ma.id]=b.getImageData(0,0,ma.image.width,ma.image.height).data),b=Na[ma.id],h=4*(Math.floor(h)+Math.floor(k)*ma.image.width),Q.setRGB(b[h]/255,b[h+1]/255,b[h+
 2]/255),u(Q)):(n=1/n,ma=(m*c-j*f)*n,j=(m*d-j*g)*n,c=(i*f-l*c)*n,d=(i*g-l*d)*n,a=a-ma*h-c*k,h=b-j*h-d*k,q.save(),q.transform(ma,j,c,d,a,h),q.fill(),q.restore())}}function ma(a,b,c,d,e,f,g,h,k,i,j,l,m){var ma,n;ma=m.width-1;n=m.height-1;g*=ma;h*=n;c-=a;d-=b;e-=a;f-=b;k=k*ma-g;i=i*n-h;j=j*ma-g;l=l*n-h;n=1/(k*l-j*i);ma=(l*c-i*e)*n;i=(l*d-i*f)*n;c=(k*e-j*c)*n;d=(k*f-j*d)*n;a=a-ma*g-c*h;b=b-i*g-d*h;q.save();q.transform(ma,i,c,d,a,b);q.clip();q.drawImage(m,0,0);q.restore()}function wc(a,b,c,d){ua[0]=255*
-a.r|0;ua[1]=255*a.g|0;ua[2]=255*a.b|0;ua[4]=255*b.r|0;ua[5]=255*b.g|0;ua[6]=255*b.b|0;ua[8]=255*c.r|0;ua[9]=255*c.g|0;ua[10]=255*c.b|0;ua[12]=255*d.r|0;ua[13]=255*d.g|0;ua[14]=255*d.b|0;bb.putImageData(mb,0,0);qb.drawImage(ab,0,0);return gb}function nb(a,b,c){a=(a-b)/(c-b);return a*a*(3-2*a)}function gc(a){a=0.5*(a+1);return 0>a?0:1<a?1:a}function Xb(a,b){var c=b.x-a.x,d=b.y-a.y,e=c*c+d*d;0!==e&&(e=1/Math.sqrt(e),c*=e,d*=e,b.x+=c,b.y+=d,a.x-=c,a.y-=d)}if(!1===l instanceof THREE.Camera)console.error("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.");
-else{var Yb,xc,na,ea;!0===this.autoClear?this.clear():q.setTransform(1,0,0,-1,o,p);f.info.render.vertices=0;f.info.render.faces=0;g=j.projectScene(a,l,this.sortObjects,this.sortElements);h=g.elements;i=g.lights;lb=0<i.length;if(!0===lb){La.setRGB(0,0,0);$a.setRGB(0,0,0);db.setRGB(0,0,0);Yb=0;for(xc=i.length;Yb<xc;Yb++){ea=i[Yb];var oa=ea.color;ea instanceof THREE.AmbientLight?(La.r+=oa.r,La.g+=oa.g,La.b+=oa.b):ea instanceof THREE.DirectionalLight?($a.r+=oa.r,$a.g+=oa.g,$a.b+=oa.b):ea instanceof THREE.PointLight&&
+a.r|0;ua[1]=255*a.g|0;ua[2]=255*a.b|0;ua[4]=255*b.r|0;ua[5]=255*b.g|0;ua[6]=255*b.b|0;ua[8]=255*c.r|0;ua[9]=255*c.g|0;ua[10]=255*c.b|0;ua[12]=255*d.r|0;ua[13]=255*d.g|0;ua[14]=255*d.b|0;bb.putImageData(mb,0,0);qb.drawImage(ab,0,0);return gb}function nb(a,b,c){a=(a-b)/(c-b);return a*a*(3-2*a)}function gc(a){a=0.5*(a+1);return 0>a?0:1<a?1:a}function Xb(a,b){var c=b.x-a.x,d=b.y-a.y,e=c*c+d*d;0!==e&&(e=1/Math.sqrt(e),c*=e,d*=e,b.x+=c,b.y+=d,a.x-=c,a.y-=d)}if(!1===m instanceof THREE.Camera)console.error("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.");
+else{var Yb,xc,na,ea;!0===this.autoClear?this.clear():q.setTransform(1,0,0,-1,o,p);f.info.render.vertices=0;f.info.render.faces=0;g=j.projectScene(a,m,this.sortObjects,this.sortElements);h=g.elements;i=g.lights;lb=0<i.length;if(!0===lb){La.setRGB(0,0,0);$a.setRGB(0,0,0);db.setRGB(0,0,0);Yb=0;for(xc=i.length;Yb<xc;Yb++){ea=i[Yb];var oa=ea.color;ea instanceof THREE.AmbientLight?(La.r+=oa.r,La.g+=oa.g,La.b+=oa.b):ea instanceof THREE.DirectionalLight?($a.r+=oa.r,$a.g+=oa.g,$a.b+=oa.b):ea instanceof THREE.PointLight&&
 (db.r+=oa.r,db.g+=oa.g,db.b+=oa.b)}}Yb=0;for(xc=h.length;Yb<xc;Yb++)if(na=h[Yb],ea=na.material,!(void 0===ea||!1===ea.visible)){Ia.empty();if(na instanceof THREE.RenderableParticle){C=na;C.x*=o;C.y*=p;var oa=C,D=na;b(ea.opacity);c(ea.blending);var zb=void 0,Ab=void 0,rb=void 0,sb=void 0,hc=na=void 0,Pc=void 0;ea instanceof THREE.ParticleBasicMaterial?null===ea.map?(rb=D.object.scale.x,sb=D.object.scale.y,rb*=D.scale.x*o,sb*=D.scale.y*p,Ia.set(oa.x-rb,oa.y-sb,oa.x+rb,oa.y+sb),!1!==eb.intersects(Ia)&&
 (e(ea.color.getContextStyle()),q.save(),q.translate(oa.x,oa.y),q.rotate(-D.rotation),q.scale(rb,sb),q.fillRect(-1,-1,2,2),q.restore())):(na=ea.map.image,hc=na.width>>1,Pc=na.height>>1,rb=D.scale.x*o,sb=D.scale.y*p,zb=rb*hc,Ab=sb*Pc,Ia.set(oa.x-zb,oa.y-Ab,oa.x+zb,oa.y+Ab),!1!==eb.intersects(Ia)&&(q.save(),q.translate(oa.x,oa.y),q.rotate(-D.rotation),q.scale(rb,-sb),q.translate(-hc,-Pc),q.drawImage(na,0,0),q.restore())):ea instanceof THREE.ParticleCanvasMaterial&&(zb=D.scale.x*o,Ab=D.scale.y*p,Ia.set(oa.x-
 zb,oa.y-Ab,oa.x+zb,oa.y+Ab),!1!==eb.intersects(Ia)&&(d(ea.color.getContextStyle()),e(ea.color.getContextStyle()),q.save(),q.translate(oa.x,oa.y),q.rotate(-D.rotation),q.scale(zb,Ab),ea.program(q),q.restore()))}else if(na instanceof THREE.RenderableLine){if(C=na.v1,E=na.v2,C.positionScreen.x*=o,C.positionScreen.y*=p,E.positionScreen.x*=o,E.positionScreen.y*=p,Ia.addPoint(C.positionScreen.x,C.positionScreen.y),Ia.addPoint(E.positionScreen.x,E.positionScreen.y),!0===eb.intersects(Ia)&&(oa=C,D=E,b(ea.opacity),
@@ -300,10 +301,10 @@ c(ea.blending),q.beginPath(),q.moveTo(oa.positionScreen.x,oa.positionScreen.y),q
 p,G.positionScreen.x*=o,G.positionScreen.y*=p,!0===ea.overdraw&&(Xb(C.positionScreen,E.positionScreen),Xb(E.positionScreen,G.positionScreen),Xb(G.positionScreen,C.positionScreen)),Ia.add3Points(C.positionScreen.x,C.positionScreen.y,E.positionScreen.x,E.positionScreen.y,G.positionScreen.x,G.positionScreen.y),!0===eb.intersects(Ia)&&n(C,E,G,0,1,2,na,ea,a);else if(na instanceof THREE.RenderableFace4&&(C=na.v1,E=na.v2,G=na.v3,L=na.v4,C.positionScreen.x*=o,C.positionScreen.y*=p,E.positionScreen.x*=o,E.positionScreen.y*=
 p,G.positionScreen.x*=o,G.positionScreen.y*=p,L.positionScreen.x*=o,L.positionScreen.y*=p,B.positionScreen.copy(E.positionScreen),J.positionScreen.copy(L.positionScreen),!0===ea.overdraw&&(Xb(C.positionScreen,E.positionScreen),Xb(E.positionScreen,L.positionScreen),Xb(L.positionScreen,C.positionScreen),Xb(G.positionScreen,B.positionScreen),Xb(G.positionScreen,J.positionScreen)),Ia.addPoint(C.positionScreen.x,C.positionScreen.y),Ia.addPoint(E.positionScreen.x,E.positionScreen.y),Ia.addPoint(G.positionScreen.x,
 G.positionScreen.y),Ia.addPoint(L.positionScreen.x,L.positionScreen.y),!0===eb.intersects(Ia)))(oa=C,D=E,zb=G,Ab=L,rb=B,sb=J,hc=a,f.info.render.vertices+=4,f.info.render.faces++,b(ea.opacity),c(ea.blending),void 0!==ea.map&&null!==ea.map||void 0!==ea.envMap&&null!==ea.envMap)?(n(oa,D,Ab,0,1,3,na,ea,hc),n(rb,zb,sb,1,2,3,na,ea,hc)):(H=oa.positionScreen.x,I=oa.positionScreen.y,O=D.positionScreen.x,N=D.positionScreen.y,M=zb.positionScreen.x,T=zb.positionScreen.y,R=Ab.positionScreen.x,P=Ab.positionScreen.y,
-S=rb.positionScreen.x,$=rb.positionScreen.y,K=sb.positionScreen.x,ja=sb.positionScreen.y,ea instanceof THREE.MeshLambertMaterial||ea instanceof THREE.MeshPhongMaterial)?(ba.copy(ea.color),ia.copy(ea.emissive),ea.vertexColors===THREE.FaceColors&&(ba.r*=na.color.r,ba.g*=na.color.g,ba.b*=na.color.b),!0===lb)?!1===ea.wireframe&&ea.shading==THREE.SmoothShading&&4==na.vertexNormalsLength?(ha.r=da.r=Y.r=aa.r=La.r,ha.g=da.g=Y.g=aa.g=La.g,ha.b=da.b=Y.b=aa.b=La.b,m(na.v1.positionWorld,na.vertexNormalsWorld[0],
-ha),m(na.v2.positionWorld,na.vertexNormalsWorld[1],da),m(na.v4.positionWorld,na.vertexNormalsWorld[3],Y),m(na.v3.positionWorld,na.vertexNormalsWorld[2],aa),ha.r=ha.r*ba.r+ia.r,ha.g=ha.g*ba.g+ia.g,ha.b=ha.b*ba.b+ia.b,da.r=da.r*ba.r+ia.r,da.g=da.g*ba.g+ia.g,da.b=da.b*ba.b+ia.b,Y.r=Y.r*ba.r+ia.r,Y.g=Y.g*ba.g+ia.g,Y.b=Y.b*ba.b+ia.b,aa.r=aa.r*ba.r+ia.r,aa.g=aa.g*ba.g+ia.g,aa.b=aa.b*ba.b+ia.b,Aa=wc(ha,da,Y,aa),r(H,I,O,N,R,P),ma(H,I,O,N,R,P,0,0,1,0,0,1,Aa),r(S,$,M,T,K,ja),ma(S,$,M,T,K,ja,1,0,1,1,0,1,Aa)):
-(Q.r=La.r,Q.g=La.g,Q.b=La.b,m(na.centroidWorld,na.normalWorld,Q),Q.r=Q.r*ba.r+ia.r,Q.g=Q.g*ba.g+ia.g,Q.b=Q.b*ba.b+ia.b,t(H,I,O,N,M,T,R,P),!0===ea.wireframe?s(Q,ea.wireframeLinewidth,ea.wireframeLinecap,ea.wireframeLinejoin):u(Q)):(Q.r=ba.r+ia.r,Q.g=ba.g+ia.g,Q.b=ba.b+ia.b,t(H,I,O,N,M,T,R,P),!0===ea.wireframe?s(Q,ea.wireframeLinewidth,ea.wireframeLinecap,ea.wireframeLinejoin):u(Q)):ea instanceof THREE.MeshBasicMaterial?(Q.copy(ea.color),ea.vertexColors===THREE.FaceColors&&(Q.r*=na.color.r,Q.g*=na.color.g,
-Q.b*=na.color.b),t(H,I,O,N,M,T,R,P),!0===ea.wireframe?s(Q,ea.wireframeLinewidth,ea.wireframeLinecap,ea.wireframeLinejoin):u(Q)):ea instanceof THREE.MeshNormalMaterial?(Q.r=gc(na.normalWorld.x),Q.g=gc(na.normalWorld.y),Q.b=gc(na.normalWorld.z),t(H,I,O,N,M,T,R,P),!0===ea.wireframe?s(Q,ea.wireframeLinewidth,ea.wireframeLinecap,ea.wireframeLinejoin):u(Q)):ea instanceof THREE.MeshDepthMaterial&&(za=l.near,Oa=l.far,ha.r=ha.g=ha.b=1-nb(oa.positionScreen.z,za,Oa),da.r=da.g=da.b=1-nb(D.positionScreen.z,za,
+S=rb.positionScreen.x,$=rb.positionScreen.y,K=sb.positionScreen.x,ja=sb.positionScreen.y,ea instanceof THREE.MeshLambertMaterial||ea instanceof THREE.MeshPhongMaterial)?(ba.copy(ea.color),ia.copy(ea.emissive),ea.vertexColors===THREE.FaceColors&&(ba.r*=na.color.r,ba.g*=na.color.g,ba.b*=na.color.b),!0===lb)?!1===ea.wireframe&&ea.shading==THREE.SmoothShading&&4==na.vertexNormalsLength?(ha.r=da.r=Y.r=aa.r=La.r,ha.g=da.g=Y.g=aa.g=La.g,ha.b=da.b=Y.b=aa.b=La.b,l(na.v1.positionWorld,na.vertexNormalsWorld[0],
+ha),l(na.v2.positionWorld,na.vertexNormalsWorld[1],da),l(na.v4.positionWorld,na.vertexNormalsWorld[3],Y),l(na.v3.positionWorld,na.vertexNormalsWorld[2],aa),ha.r=ha.r*ba.r+ia.r,ha.g=ha.g*ba.g+ia.g,ha.b=ha.b*ba.b+ia.b,da.r=da.r*ba.r+ia.r,da.g=da.g*ba.g+ia.g,da.b=da.b*ba.b+ia.b,Y.r=Y.r*ba.r+ia.r,Y.g=Y.g*ba.g+ia.g,Y.b=Y.b*ba.b+ia.b,aa.r=aa.r*ba.r+ia.r,aa.g=aa.g*ba.g+ia.g,aa.b=aa.b*ba.b+ia.b,Aa=wc(ha,da,Y,aa),r(H,I,O,N,R,P),ma(H,I,O,N,R,P,0,0,1,0,0,1,Aa),r(S,$,M,T,K,ja),ma(S,$,M,T,K,ja,1,0,1,1,0,1,Aa)):
+(Q.r=La.r,Q.g=La.g,Q.b=La.b,l(na.centroidWorld,na.normalWorld,Q),Q.r=Q.r*ba.r+ia.r,Q.g=Q.g*ba.g+ia.g,Q.b=Q.b*ba.b+ia.b,t(H,I,O,N,M,T,R,P),!0===ea.wireframe?s(Q,ea.wireframeLinewidth,ea.wireframeLinecap,ea.wireframeLinejoin):u(Q)):(Q.r=ba.r+ia.r,Q.g=ba.g+ia.g,Q.b=ba.b+ia.b,t(H,I,O,N,M,T,R,P),!0===ea.wireframe?s(Q,ea.wireframeLinewidth,ea.wireframeLinecap,ea.wireframeLinejoin):u(Q)):ea instanceof THREE.MeshBasicMaterial?(Q.copy(ea.color),ea.vertexColors===THREE.FaceColors&&(Q.r*=na.color.r,Q.g*=na.color.g,
+Q.b*=na.color.b),t(H,I,O,N,M,T,R,P),!0===ea.wireframe?s(Q,ea.wireframeLinewidth,ea.wireframeLinecap,ea.wireframeLinejoin):u(Q)):ea instanceof THREE.MeshNormalMaterial?(Q.r=gc(na.normalWorld.x),Q.g=gc(na.normalWorld.y),Q.b=gc(na.normalWorld.z),t(H,I,O,N,M,T,R,P),!0===ea.wireframe?s(Q,ea.wireframeLinewidth,ea.wireframeLinecap,ea.wireframeLinejoin):u(Q)):ea instanceof THREE.MeshDepthMaterial&&(za=m.near,Oa=m.far,ha.r=ha.g=ha.b=1-nb(oa.positionScreen.z,za,Oa),da.r=da.g=da.b=1-nb(D.positionScreen.z,za,
 Oa),Y.r=Y.g=Y.b=1-nb(Ab.positionScreen.z,za,Oa),aa.r=aa.g=aa.b=1-nb(zb.positionScreen.z,za,Oa),Aa=wc(ha,da,Y,aa),r(H,I,O,N,R,P),ma(H,I,O,N,R,P,0,0,1,0,0,1,Aa),r(S,$,M,T,K,ja),ma(S,$,M,T,K,ja,1,0,1,1,0,1,Aa));Ra.addRectangle(Ia)}q.setTransform(1,0,0,1,0,0)}}};
 THREE.ShaderChunk={fog_pars_fragment:"#ifdef USE_FOG\nuniform vec3 fogColor;\n#ifdef FOG_EXP2\nuniform float fogDensity;\n#else\nuniform float fogNear;\nuniform float fogFar;\n#endif\n#endif",fog_fragment:"#ifdef USE_FOG\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n#ifdef FOG_EXP2\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n#else\nfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n#endif\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\nuniform float reflectivity;\nuniform samplerCube envMap;\nuniform float flipEnvMap;\nuniform int combine;\n#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\nuniform bool useRefract;\nuniform float refractionRatio;\n#else\nvarying vec3 vReflect;\n#endif\n#endif",
 envmap_fragment:"#ifdef USE_ENVMAP\nvec3 reflectVec;\n#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\nvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\nif ( useRefract ) {\nreflectVec = refract( cameraToVertex, normal, refractionRatio );\n} else { \nreflectVec = reflect( cameraToVertex, normal );\n}\n#else\nreflectVec = vReflect;\n#endif\n#ifdef DOUBLE_SIDED\nfloat flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\nvec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n#else\nvec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n#endif\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\nif ( combine == 1 ) {\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );\n} else if ( combine == 2 ) {\ngl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;\n} else {\ngl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );\n}\n#endif",
@@ -474,12 +475,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,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;
+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;
 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: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":
+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":
 "","#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 +488,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: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);
+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);
 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),

+ 74 - 12
src/core/Geometry.js

@@ -150,7 +150,7 @@ THREE.Geometry.prototype = {
 
 	},
 
-	computeVertexNormals: function () {
+	computeVertexNormals: function ( areaWeighted ) {
 
 		var v, vl, f, fl, face, vertices;
 
@@ -196,22 +196,84 @@ THREE.Geometry.prototype = {
 
 		}
 
-		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+		if ( areaWeighted ) {
 
-			face = this.faces[ f ];
+			// vertex normals weighted by triangle areas
+			// http://www.iquilezles.org/www/articles/normals/normals.htm
 
-			if ( face instanceof THREE.Face3 ) {
+			var vA, vB, vC, vD;
+			var cb = new THREE.Vector3(), ab = new THREE.Vector3(),
+				db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3();
 
-				vertices[ face.a ].addSelf( face.normal );
-				vertices[ face.b ].addSelf( face.normal );
-				vertices[ face.c ].addSelf( face.normal );
+			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 
-			} else if ( face instanceof THREE.Face4 ) {
+				face = this.faces[ f ];
+
+				if ( face instanceof THREE.Face3 ) {
+
+					vA = this.vertices[ face.a ];
+					vB = this.vertices[ face.b ];
+					vC = this.vertices[ face.c ];
+
+					cb.sub( vC, vB );
+					ab.sub( vA, vB );
+					cb.crossSelf( ab );
+
+					vertices[ face.a ].addSelf( cb );
+					vertices[ face.b ].addSelf( cb );
+					vertices[ face.c ].addSelf( cb );
+
+				} else if ( face instanceof THREE.Face4 ) {
+
+					vA = this.vertices[ face.a ];
+					vB = this.vertices[ face.b ];
+					vC = this.vertices[ face.c ];
+					vD = this.vertices[ face.d ];
+
+					// abd
+
+					db.sub( vD, vB );
+					ab.sub( vA, vB );
+					db.crossSelf( ab );
+
+					vertices[ face.a ].addSelf( db );
+					vertices[ face.b ].addSelf( db );
+					vertices[ face.d ].addSelf( db );
+
+					// bcd
+
+					dc.sub( vD, vC );
+					bc.sub( vB, vC );
+					dc.crossSelf( bc );
 
-				vertices[ face.a ].addSelf( face.normal );
-				vertices[ face.b ].addSelf( face.normal );
-				vertices[ face.c ].addSelf( face.normal );
-				vertices[ face.d ].addSelf( face.normal );
+					vertices[ face.b ].addSelf( dc );
+					vertices[ face.c ].addSelf( dc );
+					vertices[ face.d ].addSelf( dc );
+
+				}
+
+			}
+
+		} else {
+
+			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+
+				face = this.faces[ f ];
+
+				if ( face instanceof THREE.Face3 ) {
+
+					vertices[ face.a ].addSelf( face.normal );
+					vertices[ face.b ].addSelf( face.normal );
+					vertices[ face.c ].addSelf( face.normal );
+
+				} else if ( face instanceof THREE.Face4 ) {
+
+					vertices[ face.a ].addSelf( face.normal );
+					vertices[ face.b ].addSelf( face.normal );
+					vertices[ face.c ].addSelf( face.normal );
+					vertices[ face.d ].addSelf( face.normal );
+
+				}
 
 			}