2
0
Эх сурвалжийг харах

Added skin rendering example plus some postprocessing fixes to make it work.

alteredq 14 жил өмнө
parent
commit
0959969fc3

+ 8 - 8
build/Three.js

@@ -276,14 +276,14 @@ o.blendFunc(o.SRC_ALPHA,o.ONE_MINUS_SRC_ALPHA);o.clearColor(P.r,P.g,P.b,fa);this
 THREE.ShaderLib.sprite.vertexShader));o.linkProgram(X.program);X.attributes={};X.uniforms={};X.attributes.position=o.getAttribLocation(X.program,"position");X.attributes.uv=o.getAttribLocation(X.program,"uv");X.uniforms.uvOffset=o.getUniformLocation(X.program,"uvOffset");X.uniforms.uvScale=o.getUniformLocation(X.program,"uvScale");X.uniforms.rotation=o.getUniformLocation(X.program,"rotation");X.uniforms.scale=o.getUniformLocation(X.program,"scale");X.uniforms.alignment=o.getUniformLocation(X.program,
 "alignment");X.uniforms.map=o.getUniformLocation(X.program,"map");X.uniforms.opacity=o.getUniformLocation(X.program,"opacity");X.uniforms.useScreenCoordinates=o.getUniformLocation(X.program,"useScreenCoordinates");X.uniforms.affectedByDistance=o.getUniformLocation(X.program,"affectedByDistance");X.uniforms.screenPosition=o.getUniformLocation(X.program,"screenPosition");X.uniforms.modelViewMatrix=o.getUniformLocation(X.program,"modelViewMatrix");X.uniforms.projectionMatrix=o.getUniformLocation(X.program,
 "projectionMatrix");var Ba=!1;this.setSize=function(b,e){za.width=b;za.height=e;this.setViewport(0,0,za.width,za.height)};this.setViewport=function(b,e,c,f){ma=b;ia=e;sa=c;O=f;o.viewport(ma,ia,sa,O)};this.setScissor=function(b,e,c,f){o.scissor(b,e,c,f)};this.enableScissorTest=function(b){b?o.enable(o.SCISSOR_TEST):o.disable(o.SCISSOR_TEST)};this.setClearColorHex=function(b,e){P.setHex(b);fa=e;o.clearColor(P.r,P.g,P.b,fa)};this.setClearColor=function(b,e){P.copy(b);fa=e;o.clearColor(P.r,P.g,P.b,fa)};
-this.clear=function(){o.clear(o.COLOR_BUFFER_BIT|o.DEPTH_BUFFER_BIT|o.STENCIL_BUFFER_BIT)};this.getContext=function(){return o};this.deallocateObject=function(b){if(b.__webglInit)if(b.__webglInit=!1,delete b._modelViewMatrix,delete b._normalMatrixArray,delete b._modelViewMatrixArray,delete b._objectMatrixArray,b instanceof THREE.Mesh)for(g in b.geometry.geometryGroups){var e=b.geometry.geometryGroups[g];o.deleteBuffer(e.__webglVertexBuffer);o.deleteBuffer(e.__webglNormalBuffer);o.deleteBuffer(e.__webglTangentBuffer);
-o.deleteBuffer(e.__webglColorBuffer);o.deleteBuffer(e.__webglUVBuffer);o.deleteBuffer(e.__webglUV2Buffer);o.deleteBuffer(e.__webglSkinVertexABuffer);o.deleteBuffer(e.__webglSkinVertexBBuffer);o.deleteBuffer(e.__webglSkinIndicesBuffer);o.deleteBuffer(e.__webglSkinWeightsBuffer);o.deleteBuffer(e.__webglFaceBuffer);o.deleteBuffer(e.__webglLineBuffer);if(e.numMorphTargets)for(var c=0,f=e.numMorphTargets;c<f;c++)o.deleteBuffer(e.__webglMorphTargetsBuffers[c])}else if(b instanceof THREE.Ribbon)b=b.geometry,
-o.deleteBuffer(b.__webglVertexBuffer),o.deleteBuffer(b.__webglColorBuffer);else if(b instanceof THREE.Line)b=b.geometry,o.deleteBuffer(b.__webglVertexBuffer),o.deleteBuffer(b.__webglColorBuffer);else if(b instanceof THREE.ParticleSystem)b=b.geometry,o.deleteBuffer(b.__webglVertexBuffer),o.deleteBuffer(b.__webglColorBuffer)};this.deallocateTexture=function(b){if(b.__webglInit)b.__webglInit=!1,o.deleteTexture(b.__webglTexture)};this.initMaterial=function(b,e,c,f){var h,k,m;b instanceof THREE.MeshDepthMaterial?
-m="depth":b instanceof THREE.MeshNormalMaterial?m="normal":b instanceof THREE.MeshBasicMaterial?m="basic":b instanceof THREE.MeshLambertMaterial?m="lambert":b instanceof THREE.MeshPhongMaterial?m="phong":b instanceof THREE.LineBasicMaterial?m="basic":b instanceof THREE.ParticleBasicMaterial&&(m="particle_basic");if(m){var n=THREE.ShaderLib[m];b.uniforms=THREE.UniformsUtils.clone(n.uniforms);b.vertexShader=n.vertexShader;b.fragmentShader=n.fragmentShader}var p,t,v;p=v=n=0;for(t=e.length;p<t;p++)k=
-e[p],k instanceof THREE.SpotLight&&v++,k instanceof THREE.DirectionalLight&&v++,k instanceof THREE.PointLight&&n++;n+v<=_maxLights?p=v:(p=Math.ceil(_maxLights*v/(n+v)),n=_maxLights-p);k={directional:p,point:n};n=v=0;for(p=e.length;n<p;n++)t=e[n],t instanceof THREE.SpotLight&&t.castShadow&&v++;var u=50;if(f!==void 0&&f instanceof THREE.SkinnedMesh)u=f.bones.length;var w;a:{p=b.fragmentShader;t=b.vertexShader;var n=b.uniforms,e=b.attributes,c={map:!!b.map,envMap:!!b.envMap,lightMap:!!b.lightMap,vertexColors:b.vertexColors,
-fog:c,sizeAttenuation:b.sizeAttenuation,skinning:b.skinning,morphTargets:b.morphTargets,maxMorphTargets:this.maxMorphTargets,maxDirLights:k.directional,maxPointLights:k.point,maxBones:u,shadowMapEnabled:this.shadowMapEnabled&&f.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapWidth:this.shadowMapWidth,shadowMapHeight:this.shadowMapHeight,maxShadows:v,alphaTest:b.alphaTest},x,f=[];m?f.push(m):(f.push(p),f.push(t));for(x in c)f.push(x),f.push(c[x]);m=f.join();x=0;for(f=pa.length;x<f;x++)if(pa[x].code==
-m){w=pa[x].program;break a}x=o.createProgram();f=[Fa?"#define VERTEX_TEXTURES":"","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#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.vertexColors?"#define USE_COLOR":"",c.skinning?"#define USE_SKINNING":"",c.morphTargets?"#define USE_MORPHTARGETS":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?
-"#define SHADOWMAP_SOFT":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nuniform mat4 cameraInverseMatrix;\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;\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
+this.getClearColor=function(b){b.copy(P)};this.clear=function(){o.clear(o.COLOR_BUFFER_BIT|o.DEPTH_BUFFER_BIT|o.STENCIL_BUFFER_BIT)};this.getContext=function(){return o};this.deallocateObject=function(b){if(b.__webglInit)if(b.__webglInit=!1,delete b._modelViewMatrix,delete b._normalMatrixArray,delete b._modelViewMatrixArray,delete b._objectMatrixArray,b instanceof THREE.Mesh)for(g in b.geometry.geometryGroups){var e=b.geometry.geometryGroups[g];o.deleteBuffer(e.__webglVertexBuffer);o.deleteBuffer(e.__webglNormalBuffer);
+o.deleteBuffer(e.__webglTangentBuffer);o.deleteBuffer(e.__webglColorBuffer);o.deleteBuffer(e.__webglUVBuffer);o.deleteBuffer(e.__webglUV2Buffer);o.deleteBuffer(e.__webglSkinVertexABuffer);o.deleteBuffer(e.__webglSkinVertexBBuffer);o.deleteBuffer(e.__webglSkinIndicesBuffer);o.deleteBuffer(e.__webglSkinWeightsBuffer);o.deleteBuffer(e.__webglFaceBuffer);o.deleteBuffer(e.__webglLineBuffer);if(e.numMorphTargets)for(var c=0,f=e.numMorphTargets;c<f;c++)o.deleteBuffer(e.__webglMorphTargetsBuffers[c])}else if(b instanceof
+THREE.Ribbon)b=b.geometry,o.deleteBuffer(b.__webglVertexBuffer),o.deleteBuffer(b.__webglColorBuffer);else if(b instanceof THREE.Line)b=b.geometry,o.deleteBuffer(b.__webglVertexBuffer),o.deleteBuffer(b.__webglColorBuffer);else if(b instanceof THREE.ParticleSystem)b=b.geometry,o.deleteBuffer(b.__webglVertexBuffer),o.deleteBuffer(b.__webglColorBuffer)};this.deallocateTexture=function(b){if(b.__webglInit)b.__webglInit=!1,o.deleteTexture(b.__webglTexture)};this.initMaterial=function(b,e,c,f){var h,k,m;
+b instanceof THREE.MeshDepthMaterial?m="depth":b instanceof THREE.MeshNormalMaterial?m="normal":b instanceof THREE.MeshBasicMaterial?m="basic":b instanceof THREE.MeshLambertMaterial?m="lambert":b instanceof THREE.MeshPhongMaterial?m="phong":b instanceof THREE.LineBasicMaterial?m="basic":b instanceof THREE.ParticleBasicMaterial&&(m="particle_basic");if(m){var n=THREE.ShaderLib[m];b.uniforms=THREE.UniformsUtils.clone(n.uniforms);b.vertexShader=n.vertexShader;b.fragmentShader=n.fragmentShader}var p,
+t,v;p=v=n=0;for(t=e.length;p<t;p++)k=e[p],k instanceof THREE.SpotLight&&v++,k instanceof THREE.DirectionalLight&&v++,k instanceof THREE.PointLight&&n++;n+v<=_maxLights?p=v:(p=Math.ceil(_maxLights*v/(n+v)),n=_maxLights-p);k={directional:p,point:n};n=v=0;for(p=e.length;n<p;n++)t=e[n],t instanceof THREE.SpotLight&&t.castShadow&&v++;var u=50;if(f!==void 0&&f instanceof THREE.SkinnedMesh)u=f.bones.length;var w;a:{p=b.fragmentShader;t=b.vertexShader;var n=b.uniforms,e=b.attributes,c={map:!!b.map,envMap:!!b.envMap,
+lightMap:!!b.lightMap,vertexColors:b.vertexColors,fog:c,sizeAttenuation:b.sizeAttenuation,skinning:b.skinning,morphTargets:b.morphTargets,maxMorphTargets:this.maxMorphTargets,maxDirLights:k.directional,maxPointLights:k.point,maxBones:u,shadowMapEnabled:this.shadowMapEnabled&&f.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapWidth:this.shadowMapWidth,shadowMapHeight:this.shadowMapHeight,maxShadows:v,alphaTest:b.alphaTest},x,f=[];m?f.push(m):(f.push(p),f.push(t));for(x in c)f.push(x),f.push(c[x]);
+m=f.join();x=0;for(f=pa.length;x<f;x++)if(pa[x].code==m){w=pa[x].program;break a}x=o.createProgram();f=[Fa?"#define VERTEX_TEXTURES":"","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#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.vertexColors?"#define USE_COLOR":"",c.skinning?"#define USE_SKINNING":"",c.morphTargets?"#define USE_MORPHTARGETS":
+"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nuniform mat4 cameraInverseMatrix;\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;\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
 k=["#ifdef GL_ES\nprecision highp float;\n#endif","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SHADOWS "+c.maxShadows,c.alphaTest?"#define ALPHATEST "+c.alphaTest:"",c.fog?"#define USE_FOG":"",c.fog instanceof THREE.FogExp2?"#define FOG_EXP2":"",c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":
 "",c.shadowMapSoft?"#define SHADOWMAP_WIDTH "+c.shadowMapWidth.toFixed(1):"",c.shadowMapSoft?"#define SHADOWMAP_HEIGHT "+c.shadowMapHeight.toFixed(1):"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n");o.attachShader(x,M("fragment",k+p));o.attachShader(x,M("vertex",f+t));o.linkProgram(x);o.getProgramParameter(x,o.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+o.getProgramParameter(x,o.VALIDATE_STATUS)+", gl error ["+o.getError()+"]");x.uniforms=
 {};x.attributes={};var L,f=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","objectMatrix","cameraPosition","cameraInverseMatrix","boneGlobalMatrices","morphTargetInfluences"];for(L in n)f.push(L);L=f;f=0;for(n=L.length;f<n;f++)p=L[f],x.uniforms[p]=o.getUniformLocation(x,p);f=["position","normal","uv","uv2","tangent","color","skinVertexA","skinVertexB","skinIndex","skinWeight"];for(L=0;L<c.maxMorphTargets;L++)f.push("morphTarget"+L);for(w in e)f.push(w);w=f;L=0;for(e=w.length;L<e;L++)c=

+ 16 - 16
build/custom/ThreeWebGL.js

@@ -55,8 +55,8 @@ this.matrixRotationWorld.extractRotation(this.matrixWorld,this.scale),this.matri
 THREE.Projector=function(){function b(){var b=r[m]=r[m]||new THREE.RenderableVertex;m++;return b}function c(b,c){return c.z-b.z}function d(b,c){var d=0,f=1,e=b.z+b.w,j=c.z+c.w,h=-b.z+b.w,k=-c.z+c.w;return e>=0&&j>=0&&h>=0&&k>=0?!0:e<0&&j<0||h<0&&k<0?!1:(e<0?d=Math.max(d,e/(e-j)):j<0&&(f=Math.min(f,e/(e-j))),h<0?d=Math.max(d,h/(h-k)):k<0&&(f=Math.min(f,h/(h-k))),f<d?!1:(b.lerpSelf(c,d),c.lerpSelf(b,1-f),!0))}var e,j,h=[],k,m,r=[],p,u,n=[],s,v=[],B,y,E=[],C,xa,ya=[],pa=[],ra=[],fa=new THREE.Vector4,
 F=new THREE.Vector4,w=new THREE.Matrix4,ia=new THREE.Matrix4,L=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4],ja=new THREE.Vector4,Y=new THREE.Vector4;this.projectVector=function(b,c){w.multiply(c.projectionMatrix,c.matrixWorldInverse);w.multiplyVector3(b);return b};this.unprojectVector=function(b,c){w.multiply(c.matrixWorld,THREE.Matrix4.makeInvert(c.projectionMatrix));w.multiplyVector3(b);return b};this.projectObjects=function(b,d,k){var f,
 m;j=pa.length=0;f=b.objects;b=0;for(d=f.length;b<d;b++){m=f[b];var p;if(!(p=!m.visible))if(p=m instanceof THREE.Mesh)if(p=m.frustumCulled){a:{p=void 0;for(var r=m.matrixWorld,u=-m.geometry.boundingSphere.radius*Math.max(m.scale.x,Math.max(m.scale.y,m.scale.z)),n=0;n<6;n++)if(p=L[n].x*r.n14+L[n].y*r.n24+L[n].z*r.n34+L[n].w,p<=u){p=!1;break a}p=!0}p=!p}if(!p)p=h[j]=h[j]||new THREE.RenderableObject,j++,e=p,fa.copy(m.position),w.multiplyVector3(fa),e.object=m,e.z=fa.z,pa.push(e)}k&&pa.sort(c);return pa};
-this.projectScene=function(e,j,h){var f=j.near,pa=j.far,fa,va,T,Z,J,W,S,V,ga,P,sa,Ga,za,Ea,R,Aa,Ca;xa=y=s=u=ra.length=0;j.matrixAutoUpdate&&j.update(void 0,!0);e.update(void 0,!1,j);w.multiply(j.projectionMatrix,j.matrixWorldInverse);L[0].set(w.n41-w.n11,w.n42-w.n12,w.n43-w.n13,w.n44-w.n14);L[1].set(w.n41+w.n11,w.n42+w.n12,w.n43+w.n13,w.n44+w.n14);L[2].set(w.n41+w.n21,w.n42+w.n22,w.n43+w.n23,w.n44+w.n24);L[3].set(w.n41-w.n21,w.n42-w.n22,w.n43-w.n23,w.n44-w.n24);L[4].set(w.n41-w.n31,w.n42-w.n32,w.n43-
-w.n33,w.n44-w.n34);L[5].set(w.n41+w.n31,w.n42+w.n32,w.n43+w.n33,w.n44+w.n34);for(fa=0;fa<6;fa++)ga=L[fa],ga.divideScalar(Math.sqrt(ga.x*ga.x+ga.y*ga.y+ga.z*ga.z));ga=this.projectObjects(e,j,!0);e=0;for(fa=ga.length;e<fa;e++)if(P=ga[e].object,P.visible)if(sa=P.matrixWorld,Ga=P.matrixRotationWorld,za=P.materials,Ea=P.overdraw,m=0,P instanceof THREE.Mesh){R=P.geometry;Z=R.vertices;Aa=R.faces;R=R.faceVertexUvs;va=0;for(T=Z.length;va<T;va++)k=b(),k.positionWorld.copy(Z[va].position),sa.multiplyVector3(k.positionWorld),
+this.projectScene=function(e,j,h){var f=j.near,pa=j.far,fa,va,T,Z,J,W,S,V,wa,P,sa,Ga,za,Ea,R,Aa,Ca;xa=y=s=u=ra.length=0;j.matrixAutoUpdate&&j.update(void 0,!0);e.update(void 0,!1,j);w.multiply(j.projectionMatrix,j.matrixWorldInverse);L[0].set(w.n41-w.n11,w.n42-w.n12,w.n43-w.n13,w.n44-w.n14);L[1].set(w.n41+w.n11,w.n42+w.n12,w.n43+w.n13,w.n44+w.n14);L[2].set(w.n41+w.n21,w.n42+w.n22,w.n43+w.n23,w.n44+w.n24);L[3].set(w.n41-w.n21,w.n42-w.n22,w.n43-w.n23,w.n44-w.n24);L[4].set(w.n41-w.n31,w.n42-w.n32,w.n43-
+w.n33,w.n44-w.n34);L[5].set(w.n41+w.n31,w.n42+w.n32,w.n43+w.n33,w.n44+w.n34);for(fa=0;fa<6;fa++)wa=L[fa],wa.divideScalar(Math.sqrt(wa.x*wa.x+wa.y*wa.y+wa.z*wa.z));wa=this.projectObjects(e,j,!0);e=0;for(fa=wa.length;e<fa;e++)if(P=wa[e].object,P.visible)if(sa=P.matrixWorld,Ga=P.matrixRotationWorld,za=P.materials,Ea=P.overdraw,m=0,P instanceof THREE.Mesh){R=P.geometry;Z=R.vertices;Aa=R.faces;R=R.faceVertexUvs;va=0;for(T=Z.length;va<T;va++)k=b(),k.positionWorld.copy(Z[va].position),sa.multiplyVector3(k.positionWorld),
 k.positionScreen.copy(k.positionWorld),w.multiplyVector4(k.positionScreen),k.positionScreen.x/=k.positionScreen.w,k.positionScreen.y/=k.positionScreen.w,k.visible=k.positionScreen.z>f&&k.positionScreen.z<pa;Z=0;for(va=Aa.length;Z<va;Z++){T=Aa[Z];if(T instanceof THREE.Face3)if(J=r[T.a],W=r[T.b],S=r[T.c],J.visible&&W.visible&&S.visible&&(P.doubleSided||P.flipSided!=(S.positionScreen.x-J.positionScreen.x)*(W.positionScreen.y-J.positionScreen.y)-(S.positionScreen.y-J.positionScreen.y)*(W.positionScreen.x-
 J.positionScreen.x)<0))V=n[u]=n[u]||new THREE.RenderableFace3,u++,p=V,p.v1.copy(J),p.v2.copy(W),p.v3.copy(S);else continue;else if(T instanceof THREE.Face4)if(J=r[T.a],W=r[T.b],S=r[T.c],V=r[T.d],J.visible&&W.visible&&S.visible&&V.visible&&(P.doubleSided||P.flipSided!=((V.positionScreen.x-J.positionScreen.x)*(W.positionScreen.y-J.positionScreen.y)-(V.positionScreen.y-J.positionScreen.y)*(W.positionScreen.x-J.positionScreen.x)<0||(W.positionScreen.x-S.positionScreen.x)*(V.positionScreen.y-S.positionScreen.y)-
 (W.positionScreen.y-S.positionScreen.y)*(V.positionScreen.x-S.positionScreen.x)<0)))Ca=v[s]=v[s]||new THREE.RenderableFace4,s++,p=Ca,p.v1.copy(J),p.v2.copy(W),p.v3.copy(S),p.v4.copy(V);else continue;p.normalWorld.copy(T.normal);Ga.multiplyVector3(p.normalWorld);p.centroidWorld.copy(T.centroid);sa.multiplyVector3(p.centroidWorld);p.centroidScreen.copy(p.centroidWorld);w.multiplyVector3(p.centroidScreen);S=T.vertexNormals;J=0;for(W=S.length;J<W;J++)V=p.vertexNormalsWorld[J],V.copy(S[J]),Ga.multiplyVector3(V);
@@ -201,11 +201,11 @@ f.vertexAttribPointer(b.skinWeight,4,f.FLOAT,!1,0,0));k instanceof THREE.Mesh?(j
 f.LINE_STRIP:f.LINES,f.lineWidth(j.linewidth),f.drawArrays(k,0,h.__webglLineCount),M.data.drawCalls++):k instanceof THREE.ParticleSystem?(f.drawArrays(f.POINTS,0,h.__webglParticleCount),M.data.drawCalls++):k instanceof THREE.Ribbon&&(f.drawArrays(f.TRIANGLE_STRIP,0,h.__webglVertexCount),M.data.drawCalls++)}}function j(b,c,d){if(!b.__webglVertexBuffer)b.__webglVertexBuffer=f.createBuffer();if(!b.__webglNormalBuffer)b.__webglNormalBuffer=f.createBuffer();b.hasPos&&(f.bindBuffer(f.ARRAY_BUFFER,b.__webglVertexBuffer),
 f.bufferData(f.ARRAY_BUFFER,b.positionArray,f.DYNAMIC_DRAW),f.enableVertexAttribArray(c.attributes.position),f.vertexAttribPointer(c.attributes.position,3,f.FLOAT,!1,0,0));if(b.hasNormal){f.bindBuffer(f.ARRAY_BUFFER,b.__webglNormalBuffer);if(d==THREE.FlatShading){var e,h,j,k,m,H,p,r,n,q,u=b.count*3;for(q=0;q<u;q+=9)d=b.normalArray,e=d[q],h=d[q+1],j=d[q+2],k=d[q+3],H=d[q+4],r=d[q+5],m=d[q+6],p=d[q+7],n=d[q+8],e=(e+k+m)/3,h=(h+H+p)/3,j=(j+r+n)/3,d[q]=e,d[q+1]=h,d[q+2]=j,d[q+3]=e,d[q+4]=h,d[q+5]=j,d[q+
 6]=e,d[q+7]=h,d[q+8]=j}f.bufferData(f.ARRAY_BUFFER,b.normalArray,f.DYNAMIC_DRAW);f.enableVertexAttribArray(c.attributes.normal);f.vertexAttribPointer(c.attributes.normal,3,f.FLOAT,!1,0,0)}f.drawArrays(f.TRIANGLES,0,b.count);b.count=0}function h(b){if(T!=b.doubleSided)b.doubleSided?f.disable(f.CULL_FACE):f.enable(f.CULL_FACE),T=b.doubleSided;if(Z!=b.flipSided)b.flipSided?f.frontFace(f.CW):f.frontFace(f.CCW),Z=b.flipSided}function k(b){W!=b&&(b?f.enable(f.DEPTH_TEST):f.disable(f.DEPTH_TEST),W=b)}function m(b){S!=
-b&&(f.depthMask(b),S=b)}function r(b,c,d){V!=b&&(b?f.enable(f.POLYGON_OFFSET_FILL):f.disable(f.POLYGON_OFFSET_FILL),V=b);if(b&&(ga!=c||P!=d))f.polygonOffset(c,d),ga=c,P=d}function p(b){R[0].set(b.n41-b.n11,b.n42-b.n12,b.n43-b.n13,b.n44-b.n14);R[1].set(b.n41+b.n11,b.n42+b.n12,b.n43+b.n13,b.n44+b.n14);R[2].set(b.n41+b.n21,b.n42+b.n22,b.n43+b.n23,b.n44+b.n24);R[3].set(b.n41-b.n21,b.n42-b.n22,b.n43-b.n23,b.n44-b.n24);R[4].set(b.n41-b.n31,b.n42-b.n32,b.n43-b.n33,b.n44-b.n34);R[5].set(b.n41+b.n31,b.n42+
+b&&(f.depthMask(b),S=b)}function r(b,c,d){V!=b&&(b?f.enable(f.POLYGON_OFFSET_FILL):f.disable(f.POLYGON_OFFSET_FILL),V=b);if(b&&(wa!=c||P!=d))f.polygonOffset(c,d),wa=c,P=d}function p(b){R[0].set(b.n41-b.n11,b.n42-b.n12,b.n43-b.n13,b.n44-b.n14);R[1].set(b.n41+b.n11,b.n42+b.n12,b.n43+b.n13,b.n44+b.n14);R[2].set(b.n41+b.n21,b.n42+b.n22,b.n43+b.n23,b.n44+b.n24);R[3].set(b.n41-b.n21,b.n42-b.n22,b.n43-b.n23,b.n44-b.n24);R[4].set(b.n41-b.n31,b.n42-b.n32,b.n43-b.n33,b.n44-b.n34);R[5].set(b.n41+b.n31,b.n42+
 b.n32,b.n43+b.n33,b.n44+b.n34);for(var c,b=0;b<6;b++)c=R[b],c.divideScalar(Math.sqrt(c.x*c.x+c.y*c.y+c.z*c.z))}function u(b){for(var c=b.matrixWorld,f=-b.geometry.boundingSphere.radius*Math.max(b.scale.x,Math.max(b.scale.y,b.scale.z)),d=0;d<6;d++)if(b=R[d].x*c.n14+R[d].y*c.n24+R[d].z*c.n34+R[d].w,b<=f)return!1;return!0}function n(b,c){b.list[b.count]=c;b.count+=1}function s(b){var c,d,f=b.object,e=b.opaque,h=b.transparent;h.count=0;b=e.count=0;for(c=f.materials.length;b<c;b++)d=f.materials[b],d.transparent?
 n(h,d):n(e,d)}function v(b){var c,d,f,e,h=b.object,j=b.buffer,k=b.opaque,m=b.transparent;m.count=0;b=k.count=0;for(f=h.materials.length;b<f;b++)if(c=h.materials[b],c instanceof THREE.MeshFaceMaterial){c=0;for(d=j.materials.length;c<d;c++)(e=j.materials[c])&&(e.transparent?n(m,e):n(k,e))}else(e=c)&&(e.transparent?n(m,e):n(k,e))}function B(b,c){return c.z-b.z}function y(b,c){var m,r,Ma,q=0,n,s,H,I,D=b.lights;qa||(qa=new THREE.Camera(M.shadowCameraFov,c.aspect,M.shadowCameraNear,M.shadowCameraFar));
 m=0;for(r=D.length;m<r;m++)if(Ma=D[m],Ma instanceof THREE.SpotLight&&Ma.castShadow){M.shadowMap[q]||(M.shadowMap[q]=new THREE.WebGLRenderTarget(M.shadowMapWidth,M.shadowMapHeight,{minFilter:THREE.LinearFilter,magFilter:THREE.LinearFilter,format:THREE.RGBAFormat}));Sa[q]||(Sa[q]=new THREE.Matrix4);n=M.shadowMap[q];s=Sa[q];qa.position.copy(Ma.position);qa.target.position.copy(Ma.target.position);qa.update(void 0,!0);b.update(void 0,!1,qa);s.set(0.5,0,0,0.5,0,0.5,0,0.5,0,0,0.5,0.5,0,0,0,1);s.multiplySelf(qa.projectionMatrix);
-s.multiplySelf(qa.matrixWorldInverse);qa.matrixWorldInverse.flattenToArray(Ta);qa.projectionMatrix.flattenToArray(Ca);Aa.multiply(qa.projectionMatrix,qa.matrixWorldInverse);p(Aa);M.initWebGLObjects(b);L(n);f.clearColor(1,1,1,1);M.clear();f.clearColor(wa.r,wa.g,wa.b,Ka);s=b.__webglObjects.length;Ma=b.__webglObjectsImmediate.length;for(n=0;n<s;n++)H=b.__webglObjects[n],I=H.object,I.visible&&I.castShadow?!(I instanceof THREE.Mesh)||!I.frustumCulled||u(I)?(I.matrixWorld.flattenToArray(I._objectMatrixArray),
+s.multiplySelf(qa.matrixWorldInverse);qa.matrixWorldInverse.flattenToArray(Ta);qa.projectionMatrix.flattenToArray(Ca);Aa.multiply(qa.projectionMatrix,qa.matrixWorldInverse);p(Aa);M.initWebGLObjects(b);L(n);f.clearColor(1,1,1,1);M.clear();f.clearColor(ga.r,ga.g,ga.b,Ka);s=b.__webglObjects.length;Ma=b.__webglObjectsImmediate.length;for(n=0;n<s;n++)H=b.__webglObjects[n],I=H.object,I.visible&&I.castShadow?!(I instanceof THREE.Mesh)||!I.frustumCulled||u(I)?(I.matrixWorld.flattenToArray(I._objectMatrixArray),
 C(I,qa,!1),H.render=!0):H.render=!1:H.render=!1;k(!0);F(THREE.NormalBlending);for(n=0;n<s;n++)if(H=b.__webglObjects[n],H.render)I=H.object,buffer=H.buffer,h(I),H=I.customDepthMaterial?I.customDepthMaterial:I.geometry.morphTargets.length?Xa:Ua,e(qa,D,null,H,buffer,I);for(n=0;n<Ma;n++)H=b.__webglObjectsImmediate[n],I=H.object,I.visible&&I.castShadow&&(I.matrixAutoUpdate&&I.matrixWorld.flattenToArray(I._objectMatrixArray),C(I,qa,!1),h(I),program=d(qa,D,null,Ua,I),I.render(function(b){j(b,program,Ua.shading)}));
 q++}}function E(b,c){var d,e,h;d=q.attributes;var j=q.uniforms,k=Ea/za,m,p=[],r=za*0.5,n=Ea*0.5,s=!0;f.useProgram(q.program);Va=q.program;W=J=-1;Ya||(f.enableVertexAttribArray(q.attributes.position),f.enableVertexAttribArray(q.attributes.uv),Ya=!0);f.disable(f.CULL_FACE);f.enable(f.BLEND);f.depthMask(!0);f.bindBuffer(f.ARRAY_BUFFER,q.vertexBuffer);f.vertexAttribPointer(d.position,2,f.FLOAT,!1,16,0);f.vertexAttribPointer(d.uv,2,f.FLOAT,!1,16,8);f.bindBuffer(f.ELEMENT_ARRAY_BUFFER,q.elementBuffer);
 f.uniformMatrix4fv(j.projectionMatrix,!1,Ca);f.activeTexture(f.TEXTURE0);f.uniform1i(j.map,0);d=0;for(e=b.__webglSprites.length;d<e;d++)h=b.__webglSprites[d],h.useScreenCoordinates?h.z=-h.position.z:(h._modelViewMatrix.multiplyToArray(c.matrixWorldInverse,h.matrixWorld,h._modelViewMatrixArray),h.z=-h._modelViewMatrix.n34);b.__webglSprites.sort(B);d=0;for(e=b.__webglSprites.length;d<e;d++)h=b.__webglSprites[d],h.material===void 0&&h.map&&h.map.image&&h.map.image.width&&(h.useScreenCoordinates?(f.uniform1i(j.useScreenCoordinates,
@@ -224,23 +224,23 @@ f.bindFramebuffer(f.FRAMEBUFFER,null)}var e,h;b?(c=c?b.__webglFramebuffer[b.acti
 f.bindTexture(f.TEXTURE_2D,null))}function Y(b,c){var d;b=="fragment"?d=f.createShader(f.FRAGMENT_SHADER):b=="vertex"&&(d=f.createShader(f.VERTEX_SHADER));f.shaderSource(d,c);f.compileShader(d);if(!f.getShaderParameter(d,f.COMPILE_STATUS))return console.error(f.getShaderInfoLog(d)),console.error(c),null;return d}function ua(b){switch(b){case THREE.NearestFilter:case THREE.NearestMipMapNearestFilter:case THREE.NearestMipMapLinearFilter:return f.NEAREST;default:return f.LINEAR}}function Q(b){switch(b){case THREE.RepeatWrapping:return f.REPEAT;
 case THREE.ClampToEdgeWrapping:return f.CLAMP_TO_EDGE;case THREE.MirroredRepeatWrapping:return f.MIRRORED_REPEAT;case THREE.NearestFilter:return f.NEAREST;case THREE.NearestMipMapNearestFilter:return f.NEAREST_MIPMAP_NEAREST;case THREE.NearestMipMapLinearFilter:return f.NEAREST_MIPMAP_LINEAR;case THREE.LinearFilter:return f.LINEAR;case THREE.LinearMipMapNearestFilter:return f.LINEAR_MIPMAP_NEAREST;case THREE.LinearMipMapLinearFilter:return f.LINEAR_MIPMAP_LINEAR;case THREE.ByteType:return f.BYTE;
 case THREE.UnsignedByteType:return f.UNSIGNED_BYTE;case THREE.ShortType:return f.SHORT;case THREE.UnsignedShortType:return f.UNSIGNED_SHORT;case THREE.IntType:return f.INT;case THREE.UnsignedShortType:return f.UNSIGNED_INT;case THREE.FloatType:return f.FLOAT;case THREE.AlphaFormat:return f.ALPHA;case THREE.RGBFormat:return f.RGB;case THREE.RGBAFormat:return f.RGBA;case THREE.LuminanceFormat:return f.LUMINANCE;case THREE.LuminanceAlphaFormat:return f.LUMINANCE_ALPHA}return 0}var M=this,f,Da=[],Va=
-null,va=null,T=null,Z=null,J=null,W=null,S=null,V=null,ga=null,P=null,sa=0,Ga=0,za=0,Ea=0,R=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4],Aa=new THREE.Matrix4,Ca=new Float32Array(16),Ta=new Float32Array(16),Ia=new THREE.Vector4,Wa={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]}},b=b||{},Ja=b.canvas!==void 0?b.canvas:document.createElement("canvas"),ab=b.stencil!==void 0?
-b.stencil:!0,bb=b.preserveDrawingBuffer!==void 0?b.preserveDrawingBuffer:!1,cb=b.antialias!==void 0?b.antialias:!1,wa=b.clearColor!==void 0?new THREE.Color(b.clearColor):new THREE.Color(0),Ka=b.clearAlpha!==void 0?b.clearAlpha:0;_maxLights=b.maxLights!==void 0?b.maxLights:4;this.data={vertices:0,faces:0,drawCalls:0};this.maxMorphTargets=8;this.domElement=Ja;this.sortObjects=this.autoClear=!0;this.shadowMapBias=0.0039;this.shadowMapDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowCameraNear=
+null,va=null,T=null,Z=null,J=null,W=null,S=null,V=null,wa=null,P=null,sa=0,Ga=0,za=0,Ea=0,R=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4],Aa=new THREE.Matrix4,Ca=new Float32Array(16),Ta=new Float32Array(16),Ia=new THREE.Vector4,Wa={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]}},b=b||{},Ja=b.canvas!==void 0?b.canvas:document.createElement("canvas"),ab=b.stencil!==void 0?
+b.stencil:!0,bb=b.preserveDrawingBuffer!==void 0?b.preserveDrawingBuffer:!1,cb=b.antialias!==void 0?b.antialias:!1,ga=b.clearColor!==void 0?new THREE.Color(b.clearColor):new THREE.Color(0),Ka=b.clearAlpha!==void 0?b.clearAlpha:0;_maxLights=b.maxLights!==void 0?b.maxLights:4;this.data={vertices:0,faces:0,drawCalls:0};this.maxMorphTargets=8;this.domElement=Ja;this.sortObjects=this.autoClear=!0;this.shadowMapBias=0.0039;this.shadowMapDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowCameraNear=
 1;this.shadowCameraFar=5E3;this.shadowCameraFov=50;this.shadowMap=[];this.shadowMapEnabled=!1;this.shadowMapSoft=!0;var qa,Sa=[],b=THREE.ShaderLib.depthRGBA,Za=THREE.UniformsUtils.clone(b.uniforms),Ua=new THREE.MeshShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:Za}),Xa=new THREE.MeshShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:Za,morphTargets:!0});Ua._shadowPass=!0;Xa._shadowPass=!0;try{if(!(f=Ja.getContext("experimental-webgl",
 {antialias:cb,stencil:ab,preserveDrawingBuffer:bb})))throw"Error creating WebGL context.";console.log(navigator.userAgent+" | "+f.getParameter(f.VERSION)+" | "+f.getParameter(f.VENDOR)+" | "+f.getParameter(f.RENDERER)+" | "+f.getParameter(f.SHADING_LANGUAGE_VERSION))}catch(db){console.error(db)}f.clearColor(0,0,0,1);f.clearDepth(1);f.clearStencil(0);f.enable(f.DEPTH_TEST);f.depthFunc(f.LEQUAL);f.frontFace(f.CCW);f.cullFace(f.BACK);f.enable(f.CULL_FACE);f.enable(f.BLEND);f.blendEquation(f.FUNC_ADD);
-f.blendFunc(f.SRC_ALPHA,f.ONE_MINUS_SRC_ALPHA);f.clearColor(wa.r,wa.g,wa.b,Ka);this.context=f;var $a=f.getParameter(f.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0,q={};q.vertices=new Float32Array(16);q.faces=new Uint16Array(6);i=0;q.vertices[i++]=-1;q.vertices[i++]=-1;q.vertices[i++]=0;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=-1;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=0;q.vertices[i++]=-1;q.vertices[i++]=1;q.vertices[i++]=0;i=q.vertices[i++]=
+f.blendFunc(f.SRC_ALPHA,f.ONE_MINUS_SRC_ALPHA);f.clearColor(ga.r,ga.g,ga.b,Ka);this.context=f;var $a=f.getParameter(f.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0,q={};q.vertices=new Float32Array(16);q.faces=new Uint16Array(6);i=0;q.vertices[i++]=-1;q.vertices[i++]=-1;q.vertices[i++]=0;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=-1;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=1;q.vertices[i++]=0;q.vertices[i++]=-1;q.vertices[i++]=1;q.vertices[i++]=0;i=q.vertices[i++]=
 0;q.faces[i++]=0;q.faces[i++]=1;q.faces[i++]=2;q.faces[i++]=0;q.faces[i++]=2;q.faces[i++]=3;q.vertexBuffer=f.createBuffer();q.elementBuffer=f.createBuffer();f.bindBuffer(f.ARRAY_BUFFER,q.vertexBuffer);f.bufferData(f.ARRAY_BUFFER,q.vertices,f.STATIC_DRAW);f.bindBuffer(f.ELEMENT_ARRAY_BUFFER,q.elementBuffer);f.bufferData(f.ELEMENT_ARRAY_BUFFER,q.faces,f.STATIC_DRAW);q.program=f.createProgram();f.attachShader(q.program,Y("fragment",THREE.ShaderLib.sprite.fragmentShader));f.attachShader(q.program,Y("vertex",
 THREE.ShaderLib.sprite.vertexShader));f.linkProgram(q.program);q.attributes={};q.uniforms={};q.attributes.position=f.getAttribLocation(q.program,"position");q.attributes.uv=f.getAttribLocation(q.program,"uv");q.uniforms.uvOffset=f.getUniformLocation(q.program,"uvOffset");q.uniforms.uvScale=f.getUniformLocation(q.program,"uvScale");q.uniforms.rotation=f.getUniformLocation(q.program,"rotation");q.uniforms.scale=f.getUniformLocation(q.program,"scale");q.uniforms.alignment=f.getUniformLocation(q.program,
 "alignment");q.uniforms.map=f.getUniformLocation(q.program,"map");q.uniforms.opacity=f.getUniformLocation(q.program,"opacity");q.uniforms.useScreenCoordinates=f.getUniformLocation(q.program,"useScreenCoordinates");q.uniforms.affectedByDistance=f.getUniformLocation(q.program,"affectedByDistance");q.uniforms.screenPosition=f.getUniformLocation(q.program,"screenPosition");q.uniforms.modelViewMatrix=f.getUniformLocation(q.program,"modelViewMatrix");q.uniforms.projectionMatrix=f.getUniformLocation(q.program,
-"projectionMatrix");var Ya=!1;this.setSize=function(b,c){Ja.width=b;Ja.height=c;this.setViewport(0,0,Ja.width,Ja.height)};this.setViewport=function(b,c,d,e){sa=b;Ga=c;za=d;Ea=e;f.viewport(sa,Ga,za,Ea)};this.setScissor=function(b,c,d,e){f.scissor(b,c,d,e)};this.enableScissorTest=function(b){b?f.enable(f.SCISSOR_TEST):f.disable(f.SCISSOR_TEST)};this.setClearColorHex=function(b,c){wa.setHex(b);Ka=c;f.clearColor(wa.r,wa.g,wa.b,Ka)};this.setClearColor=function(b,c){wa.copy(b);Ka=c;f.clearColor(wa.r,wa.g,
-wa.b,Ka)};this.clear=function(){f.clear(f.COLOR_BUFFER_BIT|f.DEPTH_BUFFER_BIT|f.STENCIL_BUFFER_BIT)};this.getContext=function(){return f};this.deallocateObject=function(b){if(b.__webglInit)if(b.__webglInit=!1,delete b._modelViewMatrix,delete b._normalMatrixArray,delete b._modelViewMatrixArray,delete b._objectMatrixArray,b instanceof THREE.Mesh)for(g in b.geometry.geometryGroups){var c=b.geometry.geometryGroups[g];f.deleteBuffer(c.__webglVertexBuffer);f.deleteBuffer(c.__webglNormalBuffer);f.deleteBuffer(c.__webglTangentBuffer);
-f.deleteBuffer(c.__webglColorBuffer);f.deleteBuffer(c.__webglUVBuffer);f.deleteBuffer(c.__webglUV2Buffer);f.deleteBuffer(c.__webglSkinVertexABuffer);f.deleteBuffer(c.__webglSkinVertexBBuffer);f.deleteBuffer(c.__webglSkinIndicesBuffer);f.deleteBuffer(c.__webglSkinWeightsBuffer);f.deleteBuffer(c.__webglFaceBuffer);f.deleteBuffer(c.__webglLineBuffer);if(c.numMorphTargets)for(var d=0,e=c.numMorphTargets;d<e;d++)f.deleteBuffer(c.__webglMorphTargetsBuffers[d])}else if(b instanceof THREE.Ribbon)b=b.geometry,
-f.deleteBuffer(b.__webglVertexBuffer),f.deleteBuffer(b.__webglColorBuffer);else if(b instanceof THREE.Line)b=b.geometry,f.deleteBuffer(b.__webglVertexBuffer),f.deleteBuffer(b.__webglColorBuffer);else if(b instanceof THREE.ParticleSystem)b=b.geometry,f.deleteBuffer(b.__webglVertexBuffer),f.deleteBuffer(b.__webglColorBuffer)};this.deallocateTexture=function(b){if(b.__webglInit)b.__webglInit=!1,f.deleteTexture(b.__webglTexture)};this.initMaterial=function(b,c,d,e){var h,j,k;b instanceof THREE.MeshDepthMaterial?
-k="depth":b instanceof THREE.MeshNormalMaterial?k="normal":b instanceof THREE.MeshBasicMaterial?k="basic":b instanceof THREE.MeshLambertMaterial?k="lambert":b instanceof THREE.MeshPhongMaterial?k="phong":b instanceof THREE.LineBasicMaterial?k="basic":b instanceof THREE.ParticleBasicMaterial&&(k="particle_basic");if(k){var m=THREE.ShaderLib[k];b.uniforms=THREE.UniformsUtils.clone(m.uniforms);b.vertexShader=m.vertexShader;b.fragmentShader=m.fragmentShader}var p,r,n;p=n=m=0;for(r=c.length;p<r;p++)j=
-c[p],j instanceof THREE.SpotLight&&n++,j instanceof THREE.DirectionalLight&&n++,j instanceof THREE.PointLight&&m++;m+n<=_maxLights?p=n:(p=Math.ceil(_maxLights*n/(m+n)),m=_maxLights-p);j={directional:p,point:m};m=n=0;for(p=c.length;m<p;m++)r=c[m],r instanceof THREE.SpotLight&&r.castShadow&&n++;var q=50;if(e!==void 0&&e instanceof THREE.SkinnedMesh)q=e.bones.length;var s;a:{p=b.fragmentShader;r=b.vertexShader;var m=b.uniforms,c=b.attributes,d={map:!!b.map,envMap:!!b.envMap,lightMap:!!b.lightMap,vertexColors:b.vertexColors,
-fog:d,sizeAttenuation:b.sizeAttenuation,skinning:b.skinning,morphTargets:b.morphTargets,maxMorphTargets:this.maxMorphTargets,maxDirLights:j.directional,maxPointLights:j.point,maxBones:q,shadowMapEnabled:this.shadowMapEnabled&&e.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapWidth:this.shadowMapWidth,shadowMapHeight:this.shadowMapHeight,maxShadows:n,alphaTest:b.alphaTest},u,e=[];k?e.push(k):(e.push(p),e.push(r));for(u in d)e.push(u),e.push(d[u]);k=e.join();u=0;for(e=Da.length;u<e;u++)if(Da[u].code==
-k){s=Da[u].program;break a}u=f.createProgram();e=[$a?"#define VERTEX_TEXTURES":"","#define MAX_DIR_LIGHTS "+d.maxDirLights,"#define MAX_POINT_LIGHTS "+d.maxPointLights,"#define MAX_SHADOWS "+d.maxShadows,"#define MAX_BONES "+d.maxBones,d.map?"#define USE_MAP":"",d.envMap?"#define USE_ENVMAP":"",d.lightMap?"#define USE_LIGHTMAP":"",d.vertexColors?"#define USE_COLOR":"",d.skinning?"#define USE_SKINNING":"",d.morphTargets?"#define USE_MORPHTARGETS":"",d.shadowMapEnabled?"#define USE_SHADOWMAP":"",d.shadowMapSoft?
-"#define SHADOWMAP_SOFT":"",d.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nuniform mat4 cameraInverseMatrix;\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;\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
+"projectionMatrix");var Ya=!1;this.setSize=function(b,c){Ja.width=b;Ja.height=c;this.setViewport(0,0,Ja.width,Ja.height)};this.setViewport=function(b,c,d,e){sa=b;Ga=c;za=d;Ea=e;f.viewport(sa,Ga,za,Ea)};this.setScissor=function(b,c,d,e){f.scissor(b,c,d,e)};this.enableScissorTest=function(b){b?f.enable(f.SCISSOR_TEST):f.disable(f.SCISSOR_TEST)};this.setClearColorHex=function(b,c){ga.setHex(b);Ka=c;f.clearColor(ga.r,ga.g,ga.b,Ka)};this.setClearColor=function(b,c){ga.copy(b);Ka=c;f.clearColor(ga.r,ga.g,
+ga.b,Ka)};this.getClearColor=function(b){b.copy(ga)};this.clear=function(){f.clear(f.COLOR_BUFFER_BIT|f.DEPTH_BUFFER_BIT|f.STENCIL_BUFFER_BIT)};this.getContext=function(){return f};this.deallocateObject=function(b){if(b.__webglInit)if(b.__webglInit=!1,delete b._modelViewMatrix,delete b._normalMatrixArray,delete b._modelViewMatrixArray,delete b._objectMatrixArray,b instanceof THREE.Mesh)for(g in b.geometry.geometryGroups){var c=b.geometry.geometryGroups[g];f.deleteBuffer(c.__webglVertexBuffer);f.deleteBuffer(c.__webglNormalBuffer);
+f.deleteBuffer(c.__webglTangentBuffer);f.deleteBuffer(c.__webglColorBuffer);f.deleteBuffer(c.__webglUVBuffer);f.deleteBuffer(c.__webglUV2Buffer);f.deleteBuffer(c.__webglSkinVertexABuffer);f.deleteBuffer(c.__webglSkinVertexBBuffer);f.deleteBuffer(c.__webglSkinIndicesBuffer);f.deleteBuffer(c.__webglSkinWeightsBuffer);f.deleteBuffer(c.__webglFaceBuffer);f.deleteBuffer(c.__webglLineBuffer);if(c.numMorphTargets)for(var d=0,e=c.numMorphTargets;d<e;d++)f.deleteBuffer(c.__webglMorphTargetsBuffers[d])}else if(b instanceof
+THREE.Ribbon)b=b.geometry,f.deleteBuffer(b.__webglVertexBuffer),f.deleteBuffer(b.__webglColorBuffer);else if(b instanceof THREE.Line)b=b.geometry,f.deleteBuffer(b.__webglVertexBuffer),f.deleteBuffer(b.__webglColorBuffer);else if(b instanceof THREE.ParticleSystem)b=b.geometry,f.deleteBuffer(b.__webglVertexBuffer),f.deleteBuffer(b.__webglColorBuffer)};this.deallocateTexture=function(b){if(b.__webglInit)b.__webglInit=!1,f.deleteTexture(b.__webglTexture)};this.initMaterial=function(b,c,d,e){var h,j,k;
+b instanceof THREE.MeshDepthMaterial?k="depth":b instanceof THREE.MeshNormalMaterial?k="normal":b instanceof THREE.MeshBasicMaterial?k="basic":b instanceof THREE.MeshLambertMaterial?k="lambert":b instanceof THREE.MeshPhongMaterial?k="phong":b instanceof THREE.LineBasicMaterial?k="basic":b instanceof THREE.ParticleBasicMaterial&&(k="particle_basic");if(k){var m=THREE.ShaderLib[k];b.uniforms=THREE.UniformsUtils.clone(m.uniforms);b.vertexShader=m.vertexShader;b.fragmentShader=m.fragmentShader}var p,
+r,n;p=n=m=0;for(r=c.length;p<r;p++)j=c[p],j instanceof THREE.SpotLight&&n++,j instanceof THREE.DirectionalLight&&n++,j instanceof THREE.PointLight&&m++;m+n<=_maxLights?p=n:(p=Math.ceil(_maxLights*n/(m+n)),m=_maxLights-p);j={directional:p,point:m};m=n=0;for(p=c.length;m<p;m++)r=c[m],r instanceof THREE.SpotLight&&r.castShadow&&n++;var q=50;if(e!==void 0&&e instanceof THREE.SkinnedMesh)q=e.bones.length;var s;a:{p=b.fragmentShader;r=b.vertexShader;var m=b.uniforms,c=b.attributes,d={map:!!b.map,envMap:!!b.envMap,
+lightMap:!!b.lightMap,vertexColors:b.vertexColors,fog:d,sizeAttenuation:b.sizeAttenuation,skinning:b.skinning,morphTargets:b.morphTargets,maxMorphTargets:this.maxMorphTargets,maxDirLights:j.directional,maxPointLights:j.point,maxBones:q,shadowMapEnabled:this.shadowMapEnabled&&e.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapWidth:this.shadowMapWidth,shadowMapHeight:this.shadowMapHeight,maxShadows:n,alphaTest:b.alphaTest},u,e=[];k?e.push(k):(e.push(p),e.push(r));for(u in d)e.push(u),e.push(d[u]);
+k=e.join();u=0;for(e=Da.length;u<e;u++)if(Da[u].code==k){s=Da[u].program;break a}u=f.createProgram();e=[$a?"#define VERTEX_TEXTURES":"","#define MAX_DIR_LIGHTS "+d.maxDirLights,"#define MAX_POINT_LIGHTS "+d.maxPointLights,"#define MAX_SHADOWS "+d.maxShadows,"#define MAX_BONES "+d.maxBones,d.map?"#define USE_MAP":"",d.envMap?"#define USE_ENVMAP":"",d.lightMap?"#define USE_LIGHTMAP":"",d.vertexColors?"#define USE_COLOR":"",d.skinning?"#define USE_SKINNING":"",d.morphTargets?"#define USE_MORPHTARGETS":
+"",d.shadowMapEnabled?"#define USE_SHADOWMAP":"",d.shadowMapSoft?"#define SHADOWMAP_SOFT":"",d.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nuniform mat4 cameraInverseMatrix;\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;\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
 j=["#ifdef GL_ES\nprecision highp float;\n#endif","#define MAX_DIR_LIGHTS "+d.maxDirLights,"#define MAX_POINT_LIGHTS "+d.maxPointLights,"#define MAX_SHADOWS "+d.maxShadows,d.alphaTest?"#define ALPHATEST "+d.alphaTest:"",d.fog?"#define USE_FOG":"",d.fog instanceof THREE.FogExp2?"#define FOG_EXP2":"",d.map?"#define USE_MAP":"",d.envMap?"#define USE_ENVMAP":"",d.lightMap?"#define USE_LIGHTMAP":"",d.vertexColors?"#define USE_COLOR":"",d.shadowMapEnabled?"#define USE_SHADOWMAP":"",d.shadowMapSoft?"#define SHADOWMAP_SOFT":
 "",d.shadowMapSoft?"#define SHADOWMAP_WIDTH "+d.shadowMapWidth.toFixed(1):"",d.shadowMapSoft?"#define SHADOWMAP_HEIGHT "+d.shadowMapHeight.toFixed(1):"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n");f.attachShader(u,Y("fragment",j+p));f.attachShader(u,Y("vertex",e+r));f.linkProgram(u);f.getProgramParameter(u,f.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+f.getProgramParameter(u,f.VALIDATE_STATUS)+", gl error ["+f.getError()+"]");u.uniforms=
 {};u.attributes={};var v,e=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","objectMatrix","cameraPosition","cameraInverseMatrix","boneGlobalMatrices","morphTargetInfluences"];for(v in m)e.push(v);v=e;e=0;for(m=v.length;e<m;e++)p=v[e],u.uniforms[p]=f.getUniformLocation(u,p);e=["position","normal","uv","uv2","tangent","color","skinVertexA","skinVertexB","skinIndex","skinWeight"];for(v=0;v<d.maxMorphTargets;v++)e.push("morphTarget"+v);for(s in c)e.push(s);s=e;v=0;for(c=s.length;v<c;v++)d=

+ 412 - 0
examples/js/ShaderSkin.js

@@ -0,0 +1,412 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ *
+ */
+
+
+THREE.ShaderSkin = {
+
+	/* ------------------------------------------------------------------------------------------
+	//	Skin shader
+	//		- Blinn-Phong
+	//		- normal + diffuse maps
+	//		- four blur layers
+	//		- point and directional lights (use with "lights: true" material option)
+	//
+	//		- based on Nvidia Advanced Skin Rendering GDC 2007 presentation
+	//			http://developer.download.nvidia.com/presentations/2007/gdc/Advanced_Skin.pdf
+	// ------------------------------------------------------------------------------------------ */
+
+	'skin' : {
+
+		uniforms: THREE.UniformsUtils.merge( [
+
+			THREE.UniformsLib[ "fog" ],
+			THREE.UniformsLib[ "lights" ],
+
+			{
+
+			"passID": { type: "i", value: 0 },
+
+			"tDiffuse"	: { type: "t", value: 0, texture: null },
+			"tNormal"	: { type: "t", value: 1, texture: null },
+
+			"tBlur1"	: { type: "t", value: 2, texture: null },
+			"tBlur2"	: { type: "t", value: 3, texture: null },
+			"tBlur3"	: { type: "t", value: 4, texture: null },
+			"tBlur4"	: { type: "t", value: 5, texture: null },
+
+			"uNormalScale": { type: "f", value: 1.0 },
+
+			"uDiffuseColor":  { type: "c", value: new THREE.Color( 0xeeeeee ) },
+			"uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
+			"uAmbientColor":  { type: "c", value: new THREE.Color( 0x050505 ) },
+			"uShininess": 	  { type: "f", value: 30 },
+			"uOpacity": 	  { type: "f", value: 1 }
+
+			}
+
+		] ),
+
+		fragmentShader: [
+
+			"uniform vec3 uAmbientColor;",
+			"uniform vec3 uDiffuseColor;",
+			"uniform vec3 uSpecularColor;",
+			"uniform float uShininess;",
+			"uniform float uOpacity;",
+
+			"uniform int passID;",
+
+			"uniform sampler2D tDiffuse;",
+			"uniform sampler2D tNormal;",
+
+			"uniform sampler2D tBlur1;",
+			"uniform sampler2D tBlur2;",
+			"uniform sampler2D tBlur3;",
+			"uniform sampler2D tBlur4;",
+
+			"uniform float uNormalScale;",
+
+			"varying vec3 vTangent;",
+			"varying vec3 vBinormal;",
+			"varying vec3 vNormal;",
+			"varying vec2 vUv;",
+
+			"uniform vec3 ambientLightColor;",
+
+			"#if MAX_DIR_LIGHTS > 0",
+				"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
+				"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
+			"#endif",
+
+			"#if MAX_POINT_LIGHTS > 0",
+				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
+				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
+			"#endif",
+
+			"varying vec3 vViewPosition;",
+
+			THREE.ShaderChunk[ "fog_pars_fragment" ],
+
+			"void main() {",
+
+				"gl_FragColor = vec4( 1.0 );",
+
+				"vec4 mColor = vec4( uDiffuseColor, uOpacity );",
+				"vec4 mSpecular = vec4( uSpecularColor, uOpacity );",
+
+				"vec3 specularTex = vec3( 1.0 );",
+
+				"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
+				"normalTex.xy *= uNormalScale;",
+				"normalTex = normalize( normalTex );",
+
+				"vec4 colDiffuse = texture2D( tDiffuse, vUv );",
+				"colDiffuse *= colDiffuse;",
+
+				"gl_FragColor = gl_FragColor * pow( colDiffuse, vec4( 0.5 ) );",
+
+
+				"mat3 tsb = mat3( vTangent, vBinormal, vNormal );",
+				"vec3 finalNormal = tsb * normalTex;",
+
+				"vec3 normal = normalize( finalNormal );",
+				"vec3 viewPosition = normalize( vViewPosition );",
+
+				// point lights
+
+				"vec4 specularTotal = vec4( vec3( 0.0 ), 1.0 );",
+
+				"#if MAX_POINT_LIGHTS > 0",
+
+					"vec4 pointTotal = vec4( vec3( 0.0 ), 1.0 );",
+
+					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
+
+						"vec3 pointVector = normalize( vPointLight[ i ].xyz );",
+						"vec3 pointHalfVector = normalize( vPointLight[ i ].xyz + viewPosition );",
+						"float pointDistance = vPointLight[ i ].w;",
+
+						"float pointDotNormalHalf = dot( normal, pointHalfVector );",
+						"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
+
+						"float pointSpecularWeight = 0.0;",
+
+						"if ( passID == 1 && pointDotNormalHalf >= 0.0 )",
+							"pointSpecularWeight = specularTex.r * pow( pointDotNormalHalf, uShininess );",
+
+						"pointTotal  += pointDistance * vec4( pointLightColor[ i ], 1.0 ) * ( mColor * pointDiffuseWeight );",
+						"specularTotal  += pointDistance * vec4( pointLightColor[ i ], 1.0 ) * ( mSpecular * pointSpecularWeight * pointDiffuseWeight );",
+
+					"}",
+
+				"#endif",
+
+				// directional lights
+
+				"#if MAX_DIR_LIGHTS > 0",
+
+					"vec4 dirTotal = vec4( vec3( 0.0 ), 1.0 );",
+
+					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
+
+						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
+
+						"vec3 dirVector = normalize( lDirection.xyz );",
+						"vec3 dirHalfVector = normalize( lDirection.xyz + viewPosition );",
+
+						"float dirDotNormalHalf = dot( normal, dirHalfVector );",
+						"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
+
+						"float dirSpecularWeight = 0.0;",
+						"if ( passID == 1 && dirDotNormalHalf >= 0.0 )",
+							"dirSpecularWeight = specularTex.r * pow( dirDotNormalHalf, uShininess );",
+
+						"dirTotal  += vec4( directionalLightColor[ i ], 1.0 ) * ( mColor * dirDiffuseWeight );",
+						"specularTotal += vec4( directionalLightColor[ i ], 1.0 ) * ( mSpecular * dirSpecularWeight * dirDiffuseWeight );",
+
+					"}",
+
+				"#endif",
+
+				// all lights contribution summation
+
+				"vec4 totalLight = vec4( vec3( 0.0 ), uOpacity );",
+
+				"#if MAX_DIR_LIGHTS > 0",
+					"totalLight += dirTotal;",
+				"#endif",
+
+				"#if MAX_POINT_LIGHTS > 0",
+					"totalLight += pointTotal;",
+				"#endif",
+
+				"gl_FragColor = gl_FragColor * totalLight;",
+
+				"if ( passID == 0 ) {",
+
+					"gl_FragColor = vec4( sqrt( gl_FragColor.xyz ), gl_FragColor.w );",
+
+				"} else if ( passID == 1 ) {",
+
+					//"#define VERSION1",
+
+					"#ifdef VERSION1",
+
+						"vec3 nonblurColor = sqrt( gl_FragColor.xyz );",
+
+					"#else",
+
+						"vec3 nonblurColor = gl_FragColor.xyz;",
+
+					"#endif",
+
+					"vec3 blur1Color = texture2D( tBlur1, vUv ).xyz;",
+					"vec3 blur2Color = texture2D( tBlur2, vUv ).xyz;",
+					"vec3 blur3Color = texture2D( tBlur3, vUv ).xyz;",
+					"vec3 blur4Color = texture2D( tBlur4, vUv ).xyz;",
+
+
+					//"gl_FragColor = vec4( blur1Color, gl_FragColor.w );",
+
+					//"gl_FragColor = vec4( vec3( 0.22, 0.5, 0.7 ) * nonblurColor + vec3( 0.2, 0.5, 0.3 ) * blur1Color + vec3( 0.58, 0.0, 0.0 ) * blur2Color, gl_FragColor.w );",
+
+					//"gl_FragColor = vec4( vec3( 0.25, 0.6, 0.8 ) * nonblurColor + vec3( 0.15, 0.25, 0.2 ) * blur1Color + vec3( 0.15, 0.15, 0.0 ) * blur2Color + vec3( 0.45, 0.0, 0.0 ) * blur3Color, gl_FragColor.w );",
+
+
+					"gl_FragColor = vec4( vec3( 0.22,  0.437, 0.635 ) * nonblurColor + ",
+										 "vec3( 0.101, 0.355, 0.365 ) * blur1Color + ",
+										 "vec3( 0.119, 0.208, 0.0 )   * blur2Color + ",
+										 "vec3( 0.114, 0.0,   0.0 )   * blur3Color + ",
+										 "vec3( 0.444, 0.0,   0.0 )   * blur4Color",
+										 ", gl_FragColor.w );",
+
+					"gl_FragColor.xyz *= pow( colDiffuse.xyz, vec3( 0.5 ) );",
+
+					"gl_FragColor += specularTotal;",
+					"gl_FragColor.xyz += ambientLightColor * uAmbientColor * colDiffuse.xyz;",
+
+					"#ifndef VERSION1",
+
+						"gl_FragColor.xyz = sqrt( gl_FragColor.xyz );",
+
+					"#endif",
+
+				"}",
+
+				THREE.ShaderChunk[ "fog_fragment" ],
+
+			"}"
+
+		].join("\n"),
+
+		vertexShader: [
+
+			"attribute vec4 tangent;",
+
+			"#ifdef VERTEX_TEXTURES",
+
+				"uniform sampler2D tDisplacement;",
+				"uniform float uDisplacementScale;",
+				"uniform float uDisplacementBias;",
+
+			"#endif",
+
+			"varying vec3 vTangent;",
+			"varying vec3 vBinormal;",
+			"varying vec3 vNormal;",
+			"varying vec2 vUv;",
+
+			"#if MAX_POINT_LIGHTS > 0",
+
+				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+
+				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
+
+			"#endif",
+
+			"varying vec3 vViewPosition;",
+
+			"void main() {",
+
+				"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
+
+				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+
+				"vViewPosition = -mvPosition.xyz;",
+
+				"vNormal = normalize( normalMatrix * normal );",
+
+				// tangent and binormal vectors
+
+				"vTangent = normalize( normalMatrix * tangent.xyz );",
+
+				"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
+				"vBinormal = normalize( vBinormal );",
+
+				"vUv = uv;",
+
+				// point lights
+
+				"#if MAX_POINT_LIGHTS > 0",
+
+					"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
+
+						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
+
+						"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
+
+						"float lDistance = 1.0;",
+
+						"if ( pointLightDistance[ i ] > 0.0 )",
+							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+
+						"lVector = normalize( lVector );",
+
+						"vPointLight[ i ] = vec4( lVector, lDistance );",
+
+					"}",
+
+				"#endif",
+
+				// displacement mapping
+
+				"#ifdef VERTEX_TEXTURES",
+
+					"vec3 dv = texture2D( tDisplacement, uv ).xyz;",
+					"float df = uDisplacementScale * dv.x + uDisplacementBias;",
+					"vec4 displacedPosition = vec4( vNormal.xyz * df, 0.0 ) + mvPosition;",
+					"gl_Position = projectionMatrix * displacedPosition;",
+
+				"#else",
+
+					"gl_Position = projectionMatrix * mvPosition;",
+
+				"#endif",
+
+			"}"
+
+		].join("\n"),
+
+		vertexShaderUV: [
+
+			"attribute vec4 tangent;",
+
+			"#ifdef VERTEX_TEXTURES",
+
+				"uniform sampler2D tDisplacement;",
+				"uniform float uDisplacementScale;",
+				"uniform float uDisplacementBias;",
+
+			"#endif",
+
+			"varying vec3 vTangent;",
+			"varying vec3 vBinormal;",
+			"varying vec3 vNormal;",
+			"varying vec2 vUv;",
+
+			"#if MAX_POINT_LIGHTS > 0",
+
+				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+
+				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
+
+			"#endif",
+
+			"varying vec3 vViewPosition;",
+
+			"void main() {",
+
+				"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
+
+				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+
+				"vViewPosition = -mvPosition.xyz;",
+
+				"vNormal = normalize( normalMatrix * normal );",
+
+				// tangent and binormal vectors
+
+				"vTangent = normalize( normalMatrix * tangent.xyz );",
+
+				"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
+				"vBinormal = normalize( vBinormal );",
+
+				"vUv = uv;",
+
+				// point lights
+
+				"#if MAX_POINT_LIGHTS > 0",
+
+					"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
+
+						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
+
+						"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
+
+						"float lDistance = 1.0;",
+
+						"if ( pointLightDistance[ i ] > 0.0 )",
+							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+
+						"lVector = normalize( lVector );",
+
+						"vPointLight[ i ] = vec4( lVector, lDistance );",
+
+					"}",
+
+				"#endif",
+
+				"gl_Position = vec4( uv.x * 2.0 - 1.0, uv.y * 2.0 - 1.0, 0.0, 1.0 );",
+
+			"}"
+
+		].join("\n")
+
+	}
+
+
+};

+ 4 - 2
examples/js/postprocessing/BloomPass.js

@@ -7,7 +7,7 @@ THREE.BloomPass = function( strength, kernelSize, sigma, resolution ) {
 	strength = ( strength !== undefined ) ? strength : 1;
 	kernelSize = ( kernelSize !== undefined ) ? kernelSize : 25;
 	sigma = ( sigma !== undefined ) ? sigma : 4.0;
-	resolution = ( resolution !== resolution ) ? resolution : 256;
+	resolution = ( resolution !== undefined ) ? resolution : 256;
 
 	// render targets
 
@@ -52,6 +52,7 @@ THREE.BloomPass = function( strength, kernelSize, sigma, resolution ) {
 	} );
 
 	this.needsSwap = false;
+	this.clear = false;
 
 };
 
@@ -70,6 +71,7 @@ THREE.BloomPass.prototype = {
 
 		renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTargetX, true );
 
+
 		// Render quad with blured scene into texture (convolution pass 2)
 
 		this.convolutionUniforms[ "tDiffuse" ].texture = this.renderTargetX;
@@ -85,7 +87,7 @@ THREE.BloomPass.prototype = {
 
 		if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
 
-		renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, readBuffer, false );
+		renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, readBuffer, this.clear );
 
 	}
 

+ 18 - 1
examples/js/postprocessing/RenderPass.js

@@ -2,15 +2,19 @@
  * @author alteredq / http://alteredqualia.com/
  */
 
-THREE.RenderPass = function ( scene, camera, overrideMaterial ) {
+THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor ) {
 
 	this.scene = scene;
 	this.camera = camera;
+
 	this.overrideMaterial = overrideMaterial;
+	this.clearColor = clearColor;
 
 	this.clear = true;
 	this.needsSwap = false;
 
+	this.oldClearColor = new THREE.Color();
+
 };
 
 THREE.RenderPass.prototype = {
@@ -19,8 +23,21 @@ THREE.RenderPass.prototype = {
 
 		this.scene.overrideMaterial = this.overrideMaterial;
 
+		if ( this.clearColor ) {
+
+			renderer.getClearColor( this.oldClearColor );
+			renderer.setClearColor( this.clearColor, 1 );
+
+		}
+
 		renderer.render( this.scene, this.camera, readBuffer, this.clear );
 
+		if ( this.clearColor ) {
+
+			renderer.setClearColor( this.oldClearColor, 1 );
+
+		}
+
 		this.scene.overrideMaterial = null;
 
 	}

+ 310 - 0
examples/webgl_materials_skin.html

@@ -0,0 +1,310 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js webgl - materials - skin [Lee Perry-Smith]</title>
+		<meta charset="utf-8">
+		<style type="text/css">
+			body {
+				background:#000;
+				color:#aaa;
+				padding:0;
+				margin:0;
+				font-weight: bold;
+				overflow:hidden;
+			}
+
+			a {	color: #eee;	}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				color: #eee;
+				padding: 5px;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				z-index:1000;
+			}
+
+			#oldie {
+				background:rgb(200,100,0) !important;
+				color:#fff;
+			}
+
+		</style>
+	</head>
+
+	<body>
+
+		<div id="info">
+			<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - webgl skin rendering demo.
+			<a href="http://www.ir-ltd.net/infinite-3d-head-scan-released/" target="_blank">Lee Perry-Smith</a> head.
+		</div>
+
+		<script type="text/javascript" src="../build/Three.js"></script>
+
+
+		<script type="text/javascript" src="js/ShaderExtras.js"></script>
+		<script type="text/javascript" src="js/ShaderSkin.js"></script>
+
+		<script type="text/javascript" src="js/postprocessing/EffectComposer.js"></script>
+		<script type="text/javascript" src="js/postprocessing/RenderPass.js"></script>
+		<script type="text/javascript" src="js/postprocessing/BloomPass.js"></script>
+		<script type="text/javascript" src="js/postprocessing/TexturePass.js"></script>
+		<script type="text/javascript" src="js/postprocessing/ShaderPass.js"></script>
+		<script type="text/javascript" src="js/postprocessing/MaskPass.js"></script>
+
+
+		<script type="text/javascript" src="js/Detector.js"></script>
+		<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
+
+		<script type="text/javascript">
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var statsEnabled = false;
+
+			var container, stats, loader;
+
+			var camera, scene, renderer;
+
+			var mesh;
+
+			var composer, composerUV1, composerUV2, composerUV3;
+
+			var directionalLight, pointLight, ambientLight;
+
+			var mouseX = 0, mouseY = 0;
+			var targetX = 0, targetY = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.Camera( 35, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera.position.z = 900;
+
+				scene = new THREE.Scene();
+
+				// LIGHTS
+
+				ambientLight = new THREE.AmbientLight( 0x222222 );
+				scene.add( ambientLight );
+
+				directionalLight = new THREE.DirectionalLight( 0xffeedd, 1 );
+				directionalLight.position.set( 1, -1, 1 );
+				directionalLight.position.normalize();
+				scene.add( directionalLight );
+
+				// MATERIALS
+
+				var ambient = 0x111111, diffuse = 0xbbbbbb, specular = 0x070707, shininess = 50;
+
+				specular = 0x090909;
+
+				var shader = THREE.ShaderSkin[ "skin" ];
+
+				var uniformsUV = THREE.UniformsUtils.clone( shader.uniforms );
+
+				uniformsUV[ "tNormal" ].texture = THREE.ImageUtils.loadTexture( "obj/leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg" );
+				uniformsUV[ "uNormalScale" ].value = -0.75;
+
+				uniformsUV[ "tDiffuse" ].texture = THREE.ImageUtils.loadTexture( "obj/leeperrysmith/Map-COL.jpg" );
+
+				uniformsUV[ "passID" ].value = 0;
+
+				uniformsUV[ "uDiffuseColor" ].value.setHex( diffuse );
+				uniformsUV[ "uSpecularColor" ].value.setHex( specular );
+				uniformsUV[ "uAmbientColor" ].value.setHex( ambient );
+
+				uniformsUV[ "uShininess" ].value = shininess;
+
+				var uniforms = THREE.UniformsUtils.clone( uniformsUV );
+				uniforms[ "tDiffuse" ].texture = uniformsUV[ "tDiffuse" ].texture;
+				uniforms[ "tNormal" ].texture = uniformsUV[ "tNormal" ].texture;
+				uniforms[ "passID" ].value = 1;
+
+				var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true };
+				var parametersUV = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShaderUV, uniforms: uniformsUV, lights: true };
+
+
+				material = new THREE.MeshShaderMaterial( parameters );
+				var materialUV = new THREE.MeshShaderMaterial( parametersUV );
+
+				// LOADER
+
+				loader = new THREE.JSONLoader( true );
+				document.body.appendChild( loader.statusDomElement );
+
+				loader.load( { model: "obj/leeperrysmith/LeePerrySmithV2.js", callback: function( geometry ) { createScene( geometry, 100, material ) } } );
+
+				// RENDERER
+
+				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setClearColorHex( 0x050505, 1 );
+				renderer.autoClear = false;
+
+				container.appendChild( renderer.domElement );
+
+				// STATS
+
+				if ( statsEnabled ) {
+
+					stats = new Stats();
+					stats.domElement.style.position = 'absolute';
+					stats.domElement.style.top = '0px';
+					stats.domElement.style.zIndex = 100;
+					container.appendChild( stats.domElement );
+
+				}
+
+				// EVENTS
+
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+
+				// POSTPROCESSING
+
+				var renderModelUV = new THREE.RenderPass( scene, camera, materialUV, new THREE.Color( 0xca9c8d ) );
+				var renderModel = new THREE.RenderPass( scene, camera );
+
+				THREE.ColorUtils.adjustHSV( renderModelUV.clearColor, 0, -0.5, -0.45 );
+
+				var effectScreen = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] );
+
+				var effectBloom1 = new THREE.BloomPass( 1, 15, 2, 512 );
+				var effectBloom2 = new THREE.BloomPass( 1, 25, 4, 512 );
+				var effectBloom3 = new THREE.BloomPass( 1, 25, 8, 512 );
+
+				effectBloom1.clear = true;
+				effectBloom2.clear = true;
+				effectBloom3.clear = true;
+
+				effectScreen.renderToScreen = true;
+
+				//
+
+				var pars = { minFilter: THREE.LinearMipmapLinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBufer: false };
+				var rtwidth = 512;
+				var rtheight = 512;
+
+				//
+
+				composerScene = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtwidth, rtheight, pars ) );
+				composerScene.addPass( renderModelUV );
+
+				renderScene = new THREE.TexturePass( composerScene.renderTarget2 );
+
+				//
+
+				composerUV1 = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtwidth, rtheight, pars ) );
+
+				composerUV1.addPass( renderScene );
+				composerUV1.addPass( effectBloom1 );
+
+				composerUV2 = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtwidth, rtheight, pars ) );
+
+				composerUV2.addPass( renderScene );
+				composerUV2.addPass( effectBloom2 );
+
+				composerUV3 = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtwidth, rtheight, pars ) );
+
+				composerUV3.addPass( renderScene );
+				composerUV3.addPass( effectBloom3 );
+
+				//
+
+				var effectBloom = new THREE.BloomPass( 0.25 );
+
+				var effectBleach = new THREE.ShaderPass( THREE.ShaderExtras[ "bleachbypass" ] );
+				effectBleach.uniforms.opacity.value = 0.25;
+
+				effectBleach.renderToScreen = true;
+
+				composerFinal = new THREE.EffectComposer( renderer );
+
+				composerFinal.addPass( renderModel );
+				composerFinal.addPass( effectBloom );
+				composerFinal.addPass( effectBleach );
+
+				//
+
+				uniforms[ "tBlur1" ].texture = composerScene.renderTarget2;
+				uniforms[ "tBlur2" ].texture = composerUV1.renderTarget2;
+				uniforms[ "tBlur3" ].texture = composerUV2.renderTarget2;
+				uniforms[ "tBlur4" ].texture = composerUV3.renderTarget2;
+
+
+			}
+
+			function createScene( geometry, scale, material ) {
+
+				geometry.computeTangents();
+
+				mesh = new THREE.Mesh( geometry, material );
+				mesh.position.y = - 50;
+				mesh.scale.set( scale, scale, scale );
+				mesh.doubleSided = true;
+
+				scene.add( mesh );
+
+				loader.statusDomElement.style.display = "none";
+
+			}
+
+			function onDocumentMouseMove(event) {
+
+				mouseX = ( event.clientX - windowHalfX );
+				mouseY = ( event.clientY - windowHalfY );
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				if ( statsEnabled ) stats.update();
+
+			}
+
+			function render() {
+
+				targetX = mouseX * .001;
+				targetY = mouseY * .001;
+
+				if ( mesh ) {
+
+					mesh.rotation.y += 0.05 * ( targetX - mesh.rotation.y );
+					mesh.rotation.x += 0.05 * ( targetY - mesh.rotation.x );
+
+				}
+
+				renderer.clear();
+
+				composerScene.render();
+
+				composerUV1.render();
+				composerUV2.render();
+				composerUV3.render();
+
+				//composerFinal.render( 0.1 );
+				renderer.render( scene, camera );
+
+			}
+
+
+		</script>
+
+	</body>
+</html>

+ 1 - 1
examples/webgl_postprocessing.html

@@ -232,7 +232,7 @@
 
 				//
 
-				renderScene = new THREE.TexturePass( composerScene.renderTarget );
+				renderScene = new THREE.TexturePass( composerScene.renderTarget2 );
 
 				rtParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBufer: true };
 

+ 6 - 0
src/renderers/WebGLRenderer.js

@@ -277,6 +277,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	};
 
+	this.getClearColor = function ( color ) {
+
+		color.copy( _clearColor );
+
+	};
+
 	this.clear = function () {
 
 		_gl.clear( _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT | _gl.STENCIL_BUFFER_BIT );