Browse Source

Added minecraft fake ambient occlusion demo.

For some reason it doesn't work with the current Chrome canary (10.0.607.0) when using ANGLE :(.

Also OBJ converter demo is having problems with generated tiled texture in latest canary, so it looks like some bug was introduced in ANGLE's handling of UVs (baked AO relies on "zoomed" UVs).

Need to investigate more, maybe file a bug report.
alteredq 14 years ago
parent
commit
45f47b89b7
5 changed files with 926 additions and 17 deletions
  1. 5 5
      build/Three.js
  2. 5 5
      build/ThreeDebug.js
  3. 5 5
      build/ThreeExtras.js
  4. 908 0
      examples/geometry_minecraft_ao.html
  5. 3 2
      src/renderers/WebGLRenderer.js

+ 5 - 5
build/Three.js

@@ -169,10 +169,10 @@ THREE.MeshPhongMaterial){j=f.ambient;g=f.specular;f=f.shininess;c.uniform4f(z.un
 0);c.uniform1i(z.uniforms.enableMap,1)}else c.uniform1i(z.uniforms.enableMap,0);if(y){d(y,1);c.uniform1i(z.uniforms.tCube,1);c.uniform1i(z.uniforms.enableCubeMap,1)}else c.uniform1i(z.uniforms.enableCubeMap,0);i=z.attributes;c.bindBuffer(c.ARRAY_BUFFER,p.__webGLVertexBuffer);c.vertexAttribPointer(i.position,3,c.FLOAT,false,0,0);if(i.normal>=0){c.bindBuffer(c.ARRAY_BUFFER,p.__webGLNormalBuffer);c.vertexAttribPointer(i.normal,3,c.FLOAT,false,0,0)}if(i.tangent>=0){c.bindBuffer(c.ARRAY_BUFFER,p.__webGLTangentBuffer);
 c.vertexAttribPointer(i.tangent,4,c.FLOAT,false,0,0)}if(i.uv>=0)if(p.__webGLUVBuffer){c.bindBuffer(c.ARRAY_BUFFER,p.__webGLUVBuffer);c.enableVertexAttribArray(i.uv);c.vertexAttribPointer(i.uv,2,c.FLOAT,false,0,0)}else c.disableVertexAttribArray(i.uv);if(u){c.lineWidth(s);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,p.__webGLLineBuffer);c.drawElements(c.LINES,p.__webGLLineCount,c.UNSIGNED_SHORT,0)}else{c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,p.__webGLFaceBuffer);c.drawElements(c.TRIANGLES,p.__webGLFaceCount,c.UNSIGNED_SHORT,
 0)}};this.renderPass=function(g,k,f,p,j,i){var u,s,G,y,H;G=0;for(y=f.material.length;G<y;G++){u=f.material[G];if(u instanceof THREE.MeshFaceMaterial){u=0;for(s=p.material.length;u<s;u++)if((H=p.material[u])&&H.blending==j&&H.opacity<1==i){this.setBlending(H.blending);this.renderBuffer(g,k,H,p)}}else if((H=u)&&H.blending==j&&H.opacity<1==i){this.setBlending(H.blending);this.renderBuffer(g,k,H,p)}}};this.render=function(g,k){var f,p,j,i,u=g.lights;this.initWebGLObjects(g);this.autoClear&&this.clear();
-k.autoUpdateMatrix&&k.updateMatrix();f=0;for(p=g.__webGLObjects.length;f<p;f++){j=g.__webGLObjects[f];i=j.object;j=j.buffer;if(i.visible){this.setupMatrices(i,k);this.renderPass(k,u,i,j,THREE.NormalBlending,false)}}f=0;for(p=g.__webGLObjects.length;f<p;f++){j=g.__webGLObjects[f];i=j.object;j=j.buffer;if(i.visible){this.setupMatrices(i,k);this.renderPass(k,u,i,j,THREE.AdditiveBlending,false);this.renderPass(k,u,i,j,THREE.SubtractiveBlending,false);this.renderPass(k,u,i,j,THREE.AdditiveBlending,true);
-this.renderPass(k,u,i,j,THREE.SubtractiveBlending,true);this.renderPass(k,u,i,j,THREE.NormalBlending,true)}}};this.initWebGLObjects=function(g){var k,f,p,j,i,u;if(!g.__webGLObjects){g.__webGLObjects=[];g.__webGLObjectsMap={}}k=0;for(f=g.objects.length;k<f;k++){p=g.objects[k];if(g.__webGLObjectsMap[p.id]==undefined)g.__webGLObjectsMap[p.id]={};u=g.__webGLObjectsMap[p.id];if(p instanceof THREE.Mesh)for(i in p.geometry.geometryChunks){j=p.geometry.geometryChunks[i];j.__webGLVertexBuffer||this.createBuffers(p,
-i);if(u[i]==undefined){j={buffer:j,object:p};g.__webGLObjects.push(j);u[i]=1}}}};this.removeObject=function(g,k){var f,p;for(f=g.__webGLObjects.length-1;f>=0;f--){p=g.__webGLObjects[f].object;k==p&&g.__webGLObjects.splice(f,1)}};this.setupMatrices=function(g,k){g.autoUpdateMatrix&&g.updateMatrix();r.multiply(k.matrix,g.matrix);E.set(k.matrix.flatten());M.set(r.flatten());O.set(k.projectionMatrix.flatten());q=THREE.Matrix4.makeInvert3x3(r).transpose();J.set(q.m);K.set(g.matrix.flatten())};this.loadMatrices=
-function(g){c.uniformMatrix4fv(g.uniforms.viewMatrix,false,E);c.uniformMatrix4fv(g.uniforms.modelViewMatrix,false,M);c.uniformMatrix4fv(g.uniforms.projectionMatrix,false,O);c.uniformMatrix3fv(g.uniforms.normalMatrix,false,J);c.uniformMatrix4fv(g.uniforms.objectMatrix,false,K)};this.loadCamera=function(g,k){c.uniform3f(g.uniforms.cameraPosition,k.position.x,k.position.y,k.position.z)};this.setBlending=function(g){switch(g){case THREE.AdditiveBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE);
-break;case THREE.SubtractiveBlending:c.blendFunc(c.DST_COLOR,c.ZERO);break;default:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA)}};this.setFaceCulling=function(g,k){if(g){!k||k=="ccw"?c.frontFace(c.CCW):c.frontFace(c.CW);if(g=="back")c.cullFace(c.BACK);else g=="front"?c.cullFace(c.FRONT):c.cullFace(c.FRONT_AND_BACK);c.enable(c.CULL_FACE)}else c.disable(c.CULL_FACE)};this.supportsVertexTextures=function(){return c.getParameter(c.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0}};
+k.autoUpdateMatrix&&k.updateMatrix();E.set(k.matrix.flatten());O.set(k.projectionMatrix.flatten());f=0;for(p=g.__webGLObjects.length;f<p;f++){j=g.__webGLObjects[f];i=j.object;j=j.buffer;if(i.visible){this.setupMatrices(i,k);this.renderPass(k,u,i,j,THREE.NormalBlending,false)}}f=0;for(p=g.__webGLObjects.length;f<p;f++){j=g.__webGLObjects[f];i=j.object;j=j.buffer;if(i.visible){this.setupMatrices(i,k);this.renderPass(k,u,i,j,THREE.AdditiveBlending,false);this.renderPass(k,u,i,j,THREE.SubtractiveBlending,
+false);this.renderPass(k,u,i,j,THREE.AdditiveBlending,true);this.renderPass(k,u,i,j,THREE.SubtractiveBlending,true);this.renderPass(k,u,i,j,THREE.NormalBlending,true)}}};this.initWebGLObjects=function(g){var k,f,p,j,i,u;if(!g.__webGLObjects){g.__webGLObjects=[];g.__webGLObjectsMap={}}k=0;for(f=g.objects.length;k<f;k++){p=g.objects[k];if(g.__webGLObjectsMap[p.id]==undefined)g.__webGLObjectsMap[p.id]={};u=g.__webGLObjectsMap[p.id];if(p instanceof THREE.Mesh)for(i in p.geometry.geometryChunks){j=p.geometry.geometryChunks[i];
+j.__webGLVertexBuffer||this.createBuffers(p,i);if(u[i]==undefined){j={buffer:j,object:p};g.__webGLObjects.push(j);u[i]=1}}}};this.removeObject=function(g,k){var f,p;for(f=g.__webGLObjects.length-1;f>=0;f--){p=g.__webGLObjects[f].object;k==p&&g.__webGLObjects.splice(f,1)}};this.setupMatrices=function(g,k){g.autoUpdateMatrix&&g.updateMatrix();r.multiply(k.matrix,g.matrix);M.set(r.flatten());q=THREE.Matrix4.makeInvert3x3(r).transpose();J.set(q.m);K.set(g.matrix.flatten())};this.loadMatrices=function(g){c.uniformMatrix4fv(g.uniforms.viewMatrix,
+false,E);c.uniformMatrix4fv(g.uniforms.modelViewMatrix,false,M);c.uniformMatrix4fv(g.uniforms.projectionMatrix,false,O);c.uniformMatrix3fv(g.uniforms.normalMatrix,false,J);c.uniformMatrix4fv(g.uniforms.objectMatrix,false,K)};this.loadCamera=function(g,k){c.uniform3f(g.uniforms.cameraPosition,k.position.x,k.position.y,k.position.z)};this.setBlending=function(g){switch(g){case THREE.AdditiveBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE);break;case THREE.SubtractiveBlending:c.blendFunc(c.DST_COLOR,
+c.ZERO);break;default:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA)}};this.setFaceCulling=function(g,k){if(g){!k||k=="ccw"?c.frontFace(c.CCW):c.frontFace(c.CW);if(g=="back")c.cullFace(c.BACK);else g=="front"?c.cullFace(c.FRONT):c.cullFace(c.FRONT_AND_BACK);c.enable(c.CULL_FACE)}else c.disable(c.CULL_FACE)};this.supportsVertexTextures=function(){return c.getParameter(c.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0}};
 THREE.RenderableFace3=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.v3=new THREE.Vertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[];this.faceMaterial=this.meshMaterial=null;this.overdraw=false;this.uvs=[null,null,null]};THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=null;this.scale=new THREE.Vector2;this.material=null};
 THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.material=null};

+ 5 - 5
build/ThreeDebug.js

@@ -170,10 +170,10 @@ THREE.MeshPhongMaterial){j=f.ambient;g=f.specular;f=f.shininess;c.uniform4f(A.un
 0);c.uniform1i(A.uniforms.enableMap,1)}else c.uniform1i(A.uniforms.enableMap,0);if(z){d(z,1);c.uniform1i(A.uniforms.tCube,1);c.uniform1i(A.uniforms.enableCubeMap,1)}else c.uniform1i(A.uniforms.enableCubeMap,0);i=A.attributes;c.bindBuffer(c.ARRAY_BUFFER,p.__webGLVertexBuffer);c.vertexAttribPointer(i.position,3,c.FLOAT,false,0,0);if(i.normal>=0){c.bindBuffer(c.ARRAY_BUFFER,p.__webGLNormalBuffer);c.vertexAttribPointer(i.normal,3,c.FLOAT,false,0,0)}if(i.tangent>=0){c.bindBuffer(c.ARRAY_BUFFER,p.__webGLTangentBuffer);
 c.vertexAttribPointer(i.tangent,4,c.FLOAT,false,0,0)}if(i.uv>=0)if(p.__webGLUVBuffer){c.bindBuffer(c.ARRAY_BUFFER,p.__webGLUVBuffer);c.enableVertexAttribArray(i.uv);c.vertexAttribPointer(i.uv,2,c.FLOAT,false,0,0)}else c.disableVertexAttribArray(i.uv);if(u){c.lineWidth(t);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,p.__webGLLineBuffer);c.drawElements(c.LINES,p.__webGLLineCount,c.UNSIGNED_SHORT,0)}else{c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,p.__webGLFaceBuffer);c.drawElements(c.TRIANGLES,p.__webGLFaceCount,c.UNSIGNED_SHORT,
 0)}};this.renderPass=function(g,l,f,p,j,i){var u,t,G,z,H;G=0;for(z=f.material.length;G<z;G++){u=f.material[G];if(u instanceof THREE.MeshFaceMaterial){u=0;for(t=p.material.length;u<t;u++)if((H=p.material[u])&&H.blending==j&&H.opacity<1==i){this.setBlending(H.blending);this.renderBuffer(g,l,H,p)}}else if((H=u)&&H.blending==j&&H.opacity<1==i){this.setBlending(H.blending);this.renderBuffer(g,l,H,p)}}};this.render=function(g,l){var f,p,j,i,u=g.lights;this.initWebGLObjects(g);this.autoClear&&this.clear();
-l.autoUpdateMatrix&&l.updateMatrix();f=0;for(p=g.__webGLObjects.length;f<p;f++){j=g.__webGLObjects[f];i=j.object;j=j.buffer;if(i.visible){this.setupMatrices(i,l);this.renderPass(l,u,i,j,THREE.NormalBlending,false)}}f=0;for(p=g.__webGLObjects.length;f<p;f++){j=g.__webGLObjects[f];i=j.object;j=j.buffer;if(i.visible){this.setupMatrices(i,l);this.renderPass(l,u,i,j,THREE.AdditiveBlending,false);this.renderPass(l,u,i,j,THREE.SubtractiveBlending,false);this.renderPass(l,u,i,j,THREE.AdditiveBlending,true);
-this.renderPass(l,u,i,j,THREE.SubtractiveBlending,true);this.renderPass(l,u,i,j,THREE.NormalBlending,true)}}};this.initWebGLObjects=function(g){var l,f,p,j,i,u;if(!g.__webGLObjects){g.__webGLObjects=[];g.__webGLObjectsMap={}}l=0;for(f=g.objects.length;l<f;l++){p=g.objects[l];if(g.__webGLObjectsMap[p.id]==undefined)g.__webGLObjectsMap[p.id]={};u=g.__webGLObjectsMap[p.id];if(p instanceof THREE.Mesh)for(i in p.geometry.geometryChunks){j=p.geometry.geometryChunks[i];j.__webGLVertexBuffer||this.createBuffers(p,
-i);if(u[i]==undefined){j={buffer:j,object:p};g.__webGLObjects.push(j);u[i]=1}}}};this.removeObject=function(g,l){var f,p;for(f=g.__webGLObjects.length-1;f>=0;f--){p=g.__webGLObjects[f].object;l==p&&g.__webGLObjects.splice(f,1)}};this.setupMatrices=function(g,l){g.autoUpdateMatrix&&g.updateMatrix();s.multiply(l.matrix,g.matrix);E.set(l.matrix.flatten());M.set(s.flatten());O.set(l.projectionMatrix.flatten());r=THREE.Matrix4.makeInvert3x3(s).transpose();J.set(r.m);K.set(g.matrix.flatten())};this.loadMatrices=
-function(g){c.uniformMatrix4fv(g.uniforms.viewMatrix,false,E);c.uniformMatrix4fv(g.uniforms.modelViewMatrix,false,M);c.uniformMatrix4fv(g.uniforms.projectionMatrix,false,O);c.uniformMatrix3fv(g.uniforms.normalMatrix,false,J);c.uniformMatrix4fv(g.uniforms.objectMatrix,false,K)};this.loadCamera=function(g,l){c.uniform3f(g.uniforms.cameraPosition,l.position.x,l.position.y,l.position.z)};this.setBlending=function(g){switch(g){case THREE.AdditiveBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE);
-break;case THREE.SubtractiveBlending:c.blendFunc(c.DST_COLOR,c.ZERO);break;default:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA)}};this.setFaceCulling=function(g,l){if(g){!l||l=="ccw"?c.frontFace(c.CCW):c.frontFace(c.CW);if(g=="back")c.cullFace(c.BACK);else g=="front"?c.cullFace(c.FRONT):c.cullFace(c.FRONT_AND_BACK);c.enable(c.CULL_FACE)}else c.disable(c.CULL_FACE)};this.supportsVertexTextures=function(){return c.getParameter(c.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0}};
+l.autoUpdateMatrix&&l.updateMatrix();E.set(l.matrix.flatten());O.set(l.projectionMatrix.flatten());f=0;for(p=g.__webGLObjects.length;f<p;f++){j=g.__webGLObjects[f];i=j.object;j=j.buffer;if(i.visible){this.setupMatrices(i,l);this.renderPass(l,u,i,j,THREE.NormalBlending,false)}}f=0;for(p=g.__webGLObjects.length;f<p;f++){j=g.__webGLObjects[f];i=j.object;j=j.buffer;if(i.visible){this.setupMatrices(i,l);this.renderPass(l,u,i,j,THREE.AdditiveBlending,false);this.renderPass(l,u,i,j,THREE.SubtractiveBlending,
+false);this.renderPass(l,u,i,j,THREE.AdditiveBlending,true);this.renderPass(l,u,i,j,THREE.SubtractiveBlending,true);this.renderPass(l,u,i,j,THREE.NormalBlending,true)}}};this.initWebGLObjects=function(g){var l,f,p,j,i,u;if(!g.__webGLObjects){g.__webGLObjects=[];g.__webGLObjectsMap={}}l=0;for(f=g.objects.length;l<f;l++){p=g.objects[l];if(g.__webGLObjectsMap[p.id]==undefined)g.__webGLObjectsMap[p.id]={};u=g.__webGLObjectsMap[p.id];if(p instanceof THREE.Mesh)for(i in p.geometry.geometryChunks){j=p.geometry.geometryChunks[i];
+j.__webGLVertexBuffer||this.createBuffers(p,i);if(u[i]==undefined){j={buffer:j,object:p};g.__webGLObjects.push(j);u[i]=1}}}};this.removeObject=function(g,l){var f,p;for(f=g.__webGLObjects.length-1;f>=0;f--){p=g.__webGLObjects[f].object;l==p&&g.__webGLObjects.splice(f,1)}};this.setupMatrices=function(g,l){g.autoUpdateMatrix&&g.updateMatrix();s.multiply(l.matrix,g.matrix);M.set(s.flatten());r=THREE.Matrix4.makeInvert3x3(s).transpose();J.set(r.m);K.set(g.matrix.flatten())};this.loadMatrices=function(g){c.uniformMatrix4fv(g.uniforms.viewMatrix,
+false,E);c.uniformMatrix4fv(g.uniforms.modelViewMatrix,false,M);c.uniformMatrix4fv(g.uniforms.projectionMatrix,false,O);c.uniformMatrix3fv(g.uniforms.normalMatrix,false,J);c.uniformMatrix4fv(g.uniforms.objectMatrix,false,K)};this.loadCamera=function(g,l){c.uniform3f(g.uniforms.cameraPosition,l.position.x,l.position.y,l.position.z)};this.setBlending=function(g){switch(g){case THREE.AdditiveBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE);break;case THREE.SubtractiveBlending:c.blendFunc(c.DST_COLOR,
+c.ZERO);break;default:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA)}};this.setFaceCulling=function(g,l){if(g){!l||l=="ccw"?c.frontFace(c.CCW):c.frontFace(c.CW);if(g=="back")c.cullFace(c.BACK);else g=="front"?c.cullFace(c.FRONT):c.cullFace(c.FRONT_AND_BACK);c.enable(c.CULL_FACE)}else c.disable(c.CULL_FACE)};this.supportsVertexTextures=function(){return c.getParameter(c.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0}};
 THREE.RenderableFace3=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.v3=new THREE.Vertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[];this.faceMaterial=this.meshMaterial=null;this.overdraw=false;this.uvs=[null,null,null]};THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=null;this.scale=new THREE.Vector2;this.material=null};
 THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.material=null};

+ 5 - 5
build/ThreeExtras.js

@@ -169,11 +169,11 @@ THREE.MeshPhongMaterial){n=h.ambient;i=h.specular;h=h.shininess;c.uniform4f(G.un
 0);c.uniform1i(G.uniforms.enableMap,1)}else c.uniform1i(G.uniforms.enableMap,0);if(E){d(E,1);c.uniform1i(G.uniforms.tCube,1);c.uniform1i(G.uniforms.enableCubeMap,1)}else c.uniform1i(G.uniforms.enableCubeMap,0);m=G.attributes;c.bindBuffer(c.ARRAY_BUFFER,w.__webGLVertexBuffer);c.vertexAttribPointer(m.position,3,c.FLOAT,false,0,0);if(m.normal>=0){c.bindBuffer(c.ARRAY_BUFFER,w.__webGLNormalBuffer);c.vertexAttribPointer(m.normal,3,c.FLOAT,false,0,0)}if(m.tangent>=0){c.bindBuffer(c.ARRAY_BUFFER,w.__webGLTangentBuffer);
 c.vertexAttribPointer(m.tangent,4,c.FLOAT,false,0,0)}if(m.uv>=0)if(w.__webGLUVBuffer){c.bindBuffer(c.ARRAY_BUFFER,w.__webGLUVBuffer);c.enableVertexAttribArray(m.uv);c.vertexAttribPointer(m.uv,2,c.FLOAT,false,0,0)}else c.disableVertexAttribArray(m.uv);if(D){c.lineWidth(A);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,w.__webGLLineBuffer);c.drawElements(c.LINES,w.__webGLLineCount,c.UNSIGNED_SHORT,0)}else{c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,w.__webGLFaceBuffer);c.drawElements(c.TRIANGLES,w.__webGLFaceCount,c.UNSIGNED_SHORT,
 0)}};this.renderPass=function(i,p,h,w,n,m){var D,A,L,E,O;L=0;for(E=h.material.length;L<E;L++){D=h.material[L];if(D instanceof THREE.MeshFaceMaterial){D=0;for(A=w.material.length;D<A;D++)if((O=w.material[D])&&O.blending==n&&O.opacity<1==m){this.setBlending(O.blending);this.renderBuffer(i,p,O,w)}}else if((O=D)&&O.blending==n&&O.opacity<1==m){this.setBlending(O.blending);this.renderBuffer(i,p,O,w)}}};this.render=function(i,p){var h,w,n,m,D=i.lights;this.initWebGLObjects(i);this.autoClear&&this.clear();
-p.autoUpdateMatrix&&p.updateMatrix();h=0;for(w=i.__webGLObjects.length;h<w;h++){n=i.__webGLObjects[h];m=n.object;n=n.buffer;if(m.visible){this.setupMatrices(m,p);this.renderPass(p,D,m,n,THREE.NormalBlending,false)}}h=0;for(w=i.__webGLObjects.length;h<w;h++){n=i.__webGLObjects[h];m=n.object;n=n.buffer;if(m.visible){this.setupMatrices(m,p);this.renderPass(p,D,m,n,THREE.AdditiveBlending,false);this.renderPass(p,D,m,n,THREE.SubtractiveBlending,false);this.renderPass(p,D,m,n,THREE.AdditiveBlending,true);
-this.renderPass(p,D,m,n,THREE.SubtractiveBlending,true);this.renderPass(p,D,m,n,THREE.NormalBlending,true)}}};this.initWebGLObjects=function(i){var p,h,w,n,m,D;if(!i.__webGLObjects){i.__webGLObjects=[];i.__webGLObjectsMap={}}p=0;for(h=i.objects.length;p<h;p++){w=i.objects[p];if(i.__webGLObjectsMap[w.id]==undefined)i.__webGLObjectsMap[w.id]={};D=i.__webGLObjectsMap[w.id];if(w instanceof THREE.Mesh)for(m in w.geometry.geometryChunks){n=w.geometry.geometryChunks[m];n.__webGLVertexBuffer||this.createBuffers(w,
-m);if(D[m]==undefined){n={buffer:n,object:w};i.__webGLObjects.push(n);D[m]=1}}}};this.removeObject=function(i,p){var h,w;for(h=i.__webGLObjects.length-1;h>=0;h--){w=i.__webGLObjects[h].object;p==w&&i.__webGLObjects.splice(h,1)}};this.setupMatrices=function(i,p){i.autoUpdateMatrix&&i.updateMatrix();q.multiply(p.matrix,i.matrix);v.set(p.matrix.flatten());z.set(q.flatten());K.set(p.projectionMatrix.flatten());s=THREE.Matrix4.makeInvert3x3(q).transpose();F.set(s.m);y.set(i.matrix.flatten())};this.loadMatrices=
-function(i){c.uniformMatrix4fv(i.uniforms.viewMatrix,false,v);c.uniformMatrix4fv(i.uniforms.modelViewMatrix,false,z);c.uniformMatrix4fv(i.uniforms.projectionMatrix,false,K);c.uniformMatrix3fv(i.uniforms.normalMatrix,false,F);c.uniformMatrix4fv(i.uniforms.objectMatrix,false,y)};this.loadCamera=function(i,p){c.uniform3f(i.uniforms.cameraPosition,p.position.x,p.position.y,p.position.z)};this.setBlending=function(i){switch(i){case THREE.AdditiveBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE);
-break;case THREE.SubtractiveBlending:c.blendFunc(c.DST_COLOR,c.ZERO);break;default:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA)}};this.setFaceCulling=function(i,p){if(i){!p||p=="ccw"?c.frontFace(c.CCW):c.frontFace(c.CW);if(i=="back")c.cullFace(c.BACK);else i=="front"?c.cullFace(c.FRONT):c.cullFace(c.FRONT_AND_BACK);c.enable(c.CULL_FACE)}else c.disable(c.CULL_FACE)};this.supportsVertexTextures=function(){return c.getParameter(c.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0}};
+p.autoUpdateMatrix&&p.updateMatrix();v.set(p.matrix.flatten());K.set(p.projectionMatrix.flatten());h=0;for(w=i.__webGLObjects.length;h<w;h++){n=i.__webGLObjects[h];m=n.object;n=n.buffer;if(m.visible){this.setupMatrices(m,p);this.renderPass(p,D,m,n,THREE.NormalBlending,false)}}h=0;for(w=i.__webGLObjects.length;h<w;h++){n=i.__webGLObjects[h];m=n.object;n=n.buffer;if(m.visible){this.setupMatrices(m,p);this.renderPass(p,D,m,n,THREE.AdditiveBlending,false);this.renderPass(p,D,m,n,THREE.SubtractiveBlending,
+false);this.renderPass(p,D,m,n,THREE.AdditiveBlending,true);this.renderPass(p,D,m,n,THREE.SubtractiveBlending,true);this.renderPass(p,D,m,n,THREE.NormalBlending,true)}}};this.initWebGLObjects=function(i){var p,h,w,n,m,D;if(!i.__webGLObjects){i.__webGLObjects=[];i.__webGLObjectsMap={}}p=0;for(h=i.objects.length;p<h;p++){w=i.objects[p];if(i.__webGLObjectsMap[w.id]==undefined)i.__webGLObjectsMap[w.id]={};D=i.__webGLObjectsMap[w.id];if(w instanceof THREE.Mesh)for(m in w.geometry.geometryChunks){n=w.geometry.geometryChunks[m];
+n.__webGLVertexBuffer||this.createBuffers(w,m);if(D[m]==undefined){n={buffer:n,object:w};i.__webGLObjects.push(n);D[m]=1}}}};this.removeObject=function(i,p){var h,w;for(h=i.__webGLObjects.length-1;h>=0;h--){w=i.__webGLObjects[h].object;p==w&&i.__webGLObjects.splice(h,1)}};this.setupMatrices=function(i,p){i.autoUpdateMatrix&&i.updateMatrix();q.multiply(p.matrix,i.matrix);z.set(q.flatten());s=THREE.Matrix4.makeInvert3x3(q).transpose();F.set(s.m);y.set(i.matrix.flatten())};this.loadMatrices=function(i){c.uniformMatrix4fv(i.uniforms.viewMatrix,
+false,v);c.uniformMatrix4fv(i.uniforms.modelViewMatrix,false,z);c.uniformMatrix4fv(i.uniforms.projectionMatrix,false,K);c.uniformMatrix3fv(i.uniforms.normalMatrix,false,F);c.uniformMatrix4fv(i.uniforms.objectMatrix,false,y)};this.loadCamera=function(i,p){c.uniform3f(i.uniforms.cameraPosition,p.position.x,p.position.y,p.position.z)};this.setBlending=function(i){switch(i){case THREE.AdditiveBlending:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE);break;case THREE.SubtractiveBlending:c.blendFunc(c.DST_COLOR,
+c.ZERO);break;default:c.blendEquation(c.FUNC_ADD);c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA)}};this.setFaceCulling=function(i,p){if(i){!p||p=="ccw"?c.frontFace(c.CCW):c.frontFace(c.CW);if(i=="back")c.cullFace(c.BACK);else i=="front"?c.cullFace(c.FRONT):c.cullFace(c.FRONT_AND_BACK);c.enable(c.CULL_FACE)}else c.disable(c.CULL_FACE)};this.supportsVertexTextures=function(){return c.getParameter(c.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0}};
 THREE.RenderableFace3=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.v3=new THREE.Vertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[];this.faceMaterial=this.meshMaterial=null;this.overdraw=false;this.uvs=[null,null,null]};THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=null;this.scale=new THREE.Vector2;this.material=null};
 THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.material=null};
 var GeometryUtils={merge:function(a,b){var d=b instanceof THREE.Mesh,e=a.vertices.length,f=d?b.geometry:b,k=a.vertices,l=f.vertices,g=a.faces,j=f.faces,c=a.uvs;f=f.uvs;d&&b.updateMatrix();for(var t=0,x=l.length;t<x;t++){var q=new THREE.Vertex(l[t].position.clone());d&&b.matrix.multiplyVector3(q.position);k.push(q)}t=0;for(x=j.length;t<x;t++){l=j[t];var s,v=l.vertexNormals;if(l instanceof THREE.Face3)s=new THREE.Face3(l.a+e,l.b+e,l.c+e);else if(l instanceof THREE.Face4)s=new THREE.Face4(l.a+e,l.b+

+ 908 - 0
examples/geometry_minecraft_ao.html

@@ -0,0 +1,908 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js - geometry - minecraft - ao</title>
+		<meta charset="utf-8">
+		<style type="text/css">
+			body {
+				color: #61443e;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+
+				background-color: #bfd1e5;
+				margin: 0px;
+				overflow: hidden;
+			}
+			
+			a {	color: #a06851;	}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
+			}
+
+			#oldie {
+				font-family:monospace;
+				font-size:13px;
+				
+				text-align:center;
+				background:rgb(100,0,0);
+				color:#fff;
+				padding:1em;
+				
+				width:475px;
+				margin:5em auto 0;
+				
+				display:none;
+			}
+			#oldie a { color:#fff }
+			
+
+			button { border:0; background:rgba(0,0,0,0.5); color:orange; cursor:pointer }
+			button:hover { color:gold }
+		</style>
+	</head>
+	<body>
+
+		<div id="container"><br /><br /><br /><br /><br />Generating world...</div> 
+		<div id="info">
+			<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - <a href="http://www.minecraft.net/" target="_blank">minecraft</a> demo [ambient occlusion]. featuring <a href="http://painterlypack.net/" target="_blank">painterly pack</a><br />(left click: forward, right click: backward)
+			<br/><br/>
+			<button id="bt">texture</button>
+			<button id="bao">ao</button>
+			<button id="baot">texture + ao</button>
+		</div> 
+
+		<center>
+		<div id="oldie">
+			Sorry, your browser doesn't support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">WebGL</a><br/>
+			<br/>
+			Please try in 
+			<a href="http://www.chromium.org/getting-involved/dev-channel">Chrome 9+</a> / 
+			<a href="http://www.mozilla.com/en-US/firefox/all-beta.html">Firefox 4+</a> / 
+			<a href="http://nightly.webkit.org/">Safari OSX 10.6+</a>
+		</div>
+		</center>
+
+		<script type="text/javascript" src="js/Stats.js"></script>
+		<script type="text/javascript" src="js/ImprovedNoise.js"></script>
+
+		<script type="text/javascript" src="../build/Three.js"></script>
+		<script type="text/javascript" src="../src/extras/GeometryUtils.js"></script>
+		<script type="text/javascript" src="../src/extras/primitives/Cube.js"></script>
+
+		<script type="text/javascript">
+
+			if ( !is_browser_compatible() ) {
+			
+				document.getElementById( "oldie" ).style.display = "block";
+				
+			}
+
+			var container, stats;
+
+			var camera, scene, renderer;
+
+			var mesh;
+
+			var worldWidth = 128, worldDepth = 128,
+			worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2,
+			data = generateHeight( worldWidth, worldDepth );
+
+			var mouseX = 0, mouseY = 0,
+			lat = 0, lon = 0, phy = 0, theta = 0;
+
+			var direction = new THREE.Vector3(),
+			moveForward = false, moveBackward = false;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+
+			init();
+			setInterval( loop, 1000 / 60 );
+
+
+			function init() {
+
+				container = document.getElementById( 'container' );
+
+				camera = new THREE.Camera( 60, window.innerWidth / window.innerHeight, 1, 20000 );
+				camera.target.position.z = - 100;
+
+				camera.position.y = getY( worldHalfWidth, worldHalfDepth ) + 100;
+				camera.target.position.y = camera.position.y;
+
+				scene = new THREE.Scene();
+				
+				var debug_texture = false, 
+					debug_numbers = false,
+					debug_corner_colors = false,
+					strength = 2,
+				
+					textures = { side: 	 'textures/minecraft/grass_dirt.png',
+							     top:    'textures/minecraft/grass.png',
+							     bottom: 'textures/minecraft/dirt.png'														   
+								},
+							
+					m_aot = generateMegamaterialAO( textures, strength, debug_texture, debug_numbers, debug_corner_colors ),
+					m_ao  = generateMegamaterialAO( textures, strength, true, debug_numbers, debug_corner_colors ),
+					
+					m_t   = generateMegamaterialPlain( textures ),
+					//m_d   = generateMegamaterialDebug(),
+
+					mat   = generateMegamaterialAO( textures, strength, debug_texture, debug_numbers, debug_corner_colors ),
+
+					materials = [ mat, mat, mat, mat, mat, mat ];
+				
+				var i, j, x, z, h, uv,
+					px, nx, pz, nz, sides,
+					right, left, bottom, top,
+					nright, nleft, nback, nfront,
+					nleftup, nrightup, nbackup, nfrontup,
+					nrb, nrf, nlb, nlf,
+					nrbup, nrfup,
+					face_px, face_nx, face_py, face_ny, face_pz, face_nz,
+					ti, ri, li, bi, fi, ci, mi, mm, column, row,
+					cube,
+					
+					unit = 1/16 * 0.95, padding = 1/16 * 0.025, p, s, t, hash, N = -1,
+					
+					// map of UV indices for faces of partially defined cubes
+					
+					uv_index_map = {
+					0:	{ px: N, nx: N, py: 0, ny: N, pz: N, nz: N },
+					1:	{ px: N, nx: N, py: 0, ny: N, pz: N, nz: 1 },
+					2:	{ px: N, nx: N, py: 0, ny: N, pz: 1, nz: N },
+					3:	{ px: N, nx: N, py: 0, ny: N, pz: 1, nz: 2 },
+					4:	{ px: N, nx: 0, py: 1, ny: N, pz: N, nz: N },
+					5:	{ px: N, nx: 0, py: 1, ny: N, pz: N, nz: 2 },
+					6:	{ px: N, nx: 0, py: 1, ny: N, pz: 2, nz: N },
+					7:	{ px: N, nx: 0, py: 1, ny: N, pz: 2, nz: 3 },
+					8:	{ px: 0, nx: N, py: 1, ny: N, pz: N, nz: N },
+					9:	{ px: 0, nx: N, py: 1, ny: N, pz: N, nz: 2 },
+					10:	{ px: 0, nx: N, py: 1, ny: N, pz: 2, nz: N },
+					11:	{ px: 0, nx: N, py: 1, ny: N, pz: 2, nz: 3 },
+					12:	{ px: 0, nx: 1, py: 2, ny: N, pz: N, nz: N },
+					13:	{ px: 0, nx: 1, py: 2, ny: N, pz: N, nz: 3 },
+					14:	{ px: 0, nx: 1, py: 2, ny: N, pz: 3, nz: N },
+					15:	{ px: 0, nx: 1, py: 2, ny: N, pz: 3, nz: 4 }
+					},
+					
+					// all possible combinations of corners and sides
+					// mapped to mixed tiles
+					// 	(including corners overlapping sides)
+					// 	(excluding corner alone and sides alone)
+					
+					// looks ugly, but allows to squeeze all 
+					// combinations for one texture into just 3 rows 
+					// instead of 16
+					
+					mixmap = {
+					"1_1":  0,
+					"1_3":  0,
+					"1_9":  0,
+					"1_11": 0,
+					
+					"1_4":  1,
+					"1_6":  1,
+					"1_12": 1,
+					"1_14": 1,
+					
+					"2_2":  2,
+					"2_3":  2,
+					"2_6":  2,
+					"2_7":  2,
+					
+					"2_8":  3,
+					"2_9":  3,
+					"2_12": 3,
+					"2_13": 3,
+					
+					"4_1":  4,
+					"4_5":  4,
+					"4_9":  4,
+					"4_13": 4,
+					
+					"4_2":  5,
+					"4_6":  5,
+					"4_10": 5,
+					"4_14": 5,
+					
+					"8_4":  6,
+					"8_5":  6,
+					"8_6":  6,
+					"8_7":  6,
+					
+					"8_8":  7,
+					"8_9":  7,
+					"8_10": 7,
+					"8_11": 7,
+					
+					"1_5":  8,
+					"1_7":  8,
+					"1_13": 8,
+					"1_15": 8,
+					
+					"2_10": 9,
+					"2_11": 9,
+					"2_14": 9,
+					"2_15": 9,
+					
+					"4_3":  10,
+					"4_7":  10,
+					"4_11": 10,
+					"4_15": 10,
+					
+					"8_12": 11,
+					"8_13": 11,
+					"8_14": 11,
+					"8_15": 11,
+					
+					"5_1":  12,
+					"5_3":  12,
+					"5_7":  12,
+					"5_9":  12,
+					"5_11": 12,
+					"5_13": 12,
+					"5_15": 12,
+					
+					"6_2":  13,
+					"6_3":  13,
+					"6_6":  13,
+					"6_7":  13,
+					"6_10": 13,
+					"6_11": 13,
+					"6_14": 13,
+					"6_15": 13,
+					
+					"9_4":  14,
+					"9_5":  14,
+					"9_6":  14,
+					"9_7":  14,
+					"9_12": 14,
+					"9_13": 14,
+					"9_14": 14,
+					"9_15": 14,
+					
+					"10_8":  15,
+					"10_9":  15,
+					"10_10": 15,
+					"10_11": 15,
+					"10_12": 15,
+					"10_13": 15,
+					"10_14": 15,
+					"10_15": 15
+					},
+					
+					tilemap = {},
+					
+					top_row_corners = 0,
+					top_row_mixed = 1,
+					top_row_sides = 2,
+					sides_row = 3,
+					bottom_row = 4,
+
+					geometry = new THREE.Geometry();
+
+				
+				// mapping from 256 possible corners + sides combinations
+				// into 3 x 16 tiles
+				
+				for ( i = 0; i < 16; i++ ) {
+				
+					for ( j = 0; j < 16; j++ ) {
+					
+						mm = i + "_" + j;
+						
+						if ( i == 0 )
+							row = top_row_corners;
+						else if ( mixmap[ mm ] != undefined )
+							row = top_row_mixed;
+						else
+							row = top_row_sides;
+						
+						tilemap[ mm ] = row;
+						
+					}
+					
+				}
+				
+				function setUVTile( face, s, t ) {
+				
+					var j, uv = cube.uvs[ face ];
+					for ( j = 0; j < uv.length; j++ ) {
+					
+						uv[ j ].u += s * (unit+2*padding);
+						uv[ j ].v += t * (unit+2*padding);
+
+					}
+					
+				}
+				
+				for ( z = 0; z < worldDepth; z ++ ) {
+
+					for ( x = 0; x < worldWidth; x ++ ) {
+						
+						h = getY( x, z );
+						
+						// direct neighbors
+						
+						nleft  = getY( x - 1, z ) == h;
+						nright = getY( x + 1, z ) == h;
+						
+						nback  = getY( x, z + 1 ) == h;
+						nfront = getY( x, z - 1 ) == h;
+
+						// corner neighbors
+						
+						nrb = getY( x - 1, z + 1 ) == h && x > 0 && z < worldDepth - 1 ? 1 : 0;
+						nrf = getY( x - 1, z - 1 ) == h && x > 0 && z > 0 ? 1 : 0;
+
+						nlb = getY( x + 1, z + 1 ) == h && x < worldWidth - 1 && z < worldDepth - 1 ? 1 : 0;
+						nlf = getY( x + 1, z - 1 ) == h && x < worldWidth - 1 && z > 0 ? 1 : 0;
+
+						// up neighbors
+						
+						nleftup  = getY( x - 1, z ) > h && x > 0 ? 1 : 0;
+						nrightup = getY( x + 1, z ) > h && x < worldWidth - 1 ? 1 : 0;
+						
+						nbackup  = getY( x, z + 1 ) > h && z < worldDepth - 1 ? 1 : 0;
+						nfrontup = getY( x, z - 1 ) > h && z > 0 ? 1 : 0;
+
+						// up corner neighbors
+						
+						nrbup = getY( x - 1, z + 1 ) > h && x > 0 && z < worldDepth - 1 ? 1 : 0;
+						nrfup = getY( x - 1, z - 1 ) > h && x > 0 && z > 0 ? 1 : 0;
+
+						nlbup = getY( x + 1, z + 1 ) > h && x < worldWidth - 1 && z < worldDepth - 1 ? 1 : 0;
+						nlfup = getY( x + 1, z - 1 ) > h && x < worldWidth - 1 && z > 0 ? 1 : 0;
+
+						// textures
+						
+						ti = nleftup * 8 + nrightup * 4 + nfrontup * 2 + nbackup * 1;
+						
+						ri = nrf * 8 + nrb * 4 + 1;
+						li = nlb * 8 + nlf * 4 + 1;
+						bi = nrb * 8 + nlb * 4 + 1;
+						fi = nlf * 8 + nrf * 4 + 1;
+						
+						ci = nlbup * 8 + nlfup * 4 + nrbup * 2 + nrfup * 1;
+						
+						// cube sides
+						
+						px = nx = pz = nz = 0;
+						
+						px = !nleft  || x == 0 ? 1 : 0;
+						nx = !nright || x == worldWidth - 1 ? 1 : 0;
+						
+						pz = !nback  || z == worldDepth - 1 ? 1 : 0;
+						nz = !nfront || z == 0 ? 1 : 0;
+
+						sides = { px: px, nx: nx, py: true, ny: false, pz: pz, nz: nz };
+						
+						cube = new Cube( 100, 100, 100, 1, 1, materials, false, sides );
+						
+						// set UV tiles
+						
+						for ( i = 0; i < cube.uvs.length; i++ ) {
+							
+							uv = cube.uvs[ i ];
+							
+							for ( j = 0; j < uv.length; j++ ) {
+							
+								p = uv[j].u == 0 ? padding : -padding;
+								uv[j].u = uv[j].u * unit + p;
+
+								p = uv[j].v == 0 ? padding : -padding;
+								uv[j].v = uv[j].v * unit + p;
+								
+							}
+							
+						}
+						
+						
+						hash = px * 8 + nx * 4 + pz * 2 + nz;
+						
+						face_px = uv_index_map[ hash ].px;
+						face_nx = uv_index_map[ hash ].nx;
+
+						face_py = uv_index_map[ hash ].py;
+						face_ny = uv_index_map[ hash ].ny;
+
+						face_pz = uv_index_map[ hash ].pz;
+						face_nz = uv_index_map[ hash ].nz;
+								
+						
+						if( face_px != N ) setUVTile( face_px, ri, sides_row );
+						if( face_nx != N ) setUVTile( face_nx, li, sides_row );
+						
+						if( face_py != N ) {
+							
+							mm = ti + "_" + ci;
+							
+							switch ( tilemap[ mm ] ) {
+							case top_row_sides:   column = ti; break;
+							case top_row_corners: column = ci; break;
+							case top_row_mixed:   column = mixmap[ mm ]; break;
+							}
+							setUVTile( face_py, column, tilemap[ mm ] );
+								
+						}
+						if( face_ny != N ) setUVTile( face_ny, 0, bottom_row );
+						
+						if( face_pz != N ) setUVTile( face_pz, bi, sides_row );
+						if( face_nz != N ) setUVTile( face_nz, fi, sides_row );
+						
+						
+						mesh = new THREE.Mesh( cube );
+						
+						mesh.position.x = x * 100 - worldHalfWidth * 100;
+						mesh.position.y = h;
+						mesh.position.z = z * 100 - worldHalfDepth * 100;
+
+						GeometryUtils.merge( geometry, mesh );
+						
+					}
+
+				}
+				
+				geometry.sortFacesByMaterial();
+
+				mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );
+				scene.addObject( mesh );
+
+				var ambientLight = new THREE.AmbientLight( 0xcccccc );
+				scene.addLight( ambientLight );
+
+				var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.5 );
+				directionalLight.position.x = 1;
+				directionalLight.position.y = 1;
+				directionalLight.position.z = 0.5;
+				directionalLight.position.normalize();
+				scene.addLight( directionalLight );
+
+				renderer = new THREE.WebGLRenderer( scene );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				container.innerHTML = "";
+
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
+				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+				document.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
+
+				document.addEventListener( 'keydown', onDocumentKeyDown, false );
+				document.addEventListener( 'keyup', onDocumentKeyUp, false );
+				
+				document.getElementById( "bao" ).addEventListener( "click",  function() { mat.map = m_ao.map; }, false );
+				document.getElementById( "baot" ).addEventListener( "click", function() { mat.map = m_aot.map; }, false );
+				document.getElementById( "bt" ).addEventListener( "click",   function() { mat.map = m_t.map; }, false );
+
+			}
+
+			function generateMegamaterialAO( textures, strength, debug_texture, debug_numbers, debug_corner_colors  ) {
+			
+				var count = 0,
+					tex_side   = loadTexture( textures.side,   function() { count++; generateTexture() } ),
+					tex_top    = loadTexture( textures.top,    function() { count++; generateTexture() } ),
+					tex_bottom = loadTexture( textures.bottom, function() { count++; generateTexture() } ),
+					
+					canvas = document.createElement( 'canvas' ),
+					ctx = canvas.getContext( '2d' ),
+					size = 256, tile = 16;
+				
+				canvas.width = canvas.height = size;
+				
+				function generateTexture() {
+					
+					if( count == 3 ) {
+					
+						for( var i = 0; i < 16; i++ ) {
+
+							drawAOCorners( ctx, tex_top, 	0, i, i, tile, strength, debug_texture, debug_numbers, debug_corner_colors );
+							drawAOMixed  ( ctx, tex_top,    1, i, i, tile, strength, debug_texture, debug_numbers, debug_corner_colors );
+							drawAOSides  ( ctx, tex_top,    2, i, i, tile, strength, debug_texture, debug_numbers );
+							drawAOSides  ( ctx, tex_side,   3, i, i, tile, strength, debug_texture, debug_numbers );
+							drawAOSides  ( ctx, tex_bottom, 4, i, i, tile, strength, debug_texture, debug_numbers );
+							
+						}
+						
+						canvas.loaded = true;
+						
+					}
+					
+				}				
+				
+				return new THREE.MeshLambertMaterial( { map: new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter ) } );
+				
+			}
+
+			function generateMegamaterialPlain( textures ) {
+			
+				var count = 0,
+					tex_side   = loadTexture( textures.side,   function() { count++; generateTexture() } ),
+					tex_top    = loadTexture( textures.top,    function() { count++; generateTexture() } ),
+					tex_bottom = loadTexture( textures.bottom, function() { count++; generateTexture() } ),
+					
+					canvas = document.createElement( 'canvas' ),
+					ctx = canvas.getContext( '2d' ),
+					size = 256, tile = 16;
+				
+				canvas.width = canvas.height = size;
+				
+				function generateTexture() {
+					
+					if( count == 3 ) {
+					
+						var i, sx;
+						
+						for( i = 0; i < 16; i++ ) {
+
+							sx = i * tile;
+							
+							drawBase( ctx, tex_top,    sx, 0 * tile, tile, false );
+							drawBase( ctx, tex_top,    sx, 1 * tile, tile, false );
+							drawBase( ctx, tex_top,    sx, 2 * tile, tile, false );
+							drawBase( ctx, tex_side,   sx, 3 * tile, tile, false );
+							drawBase( ctx, tex_bottom, sx, 4 * tile, tile, false );
+							
+						}
+						
+						canvas.loaded = true;
+						
+					}
+					
+				}				
+				
+				return new THREE.MeshLambertMaterial( { map: new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter ) } );
+				
+			}
+			function generateMegamaterialDebug() {
+			
+				var canvas = document.createElement( 'canvas' ),
+					ctx = canvas.getContext( "2d" ),
+					size = 256, tile = 16,
+					i, j, h, s;
+					
+				canvas.width = size;
+				canvas.height = size;
+					
+				ctx.textBaseline = "top";
+				ctx.font = "8pt arial";
+				
+				for ( i = 0; i < tile; i++ ) {
+				
+					for ( j = 0; j < tile; j++ ) {
+					
+						h = i * tile + j;
+						ctx.fillStyle = "hsl(" + h + ",90%, 50%)";
+						ctx.fillRect( i * tile, j * tile, tile, tile );
+						
+						drawHex( ctx, h, i * tile + 2, j * tile + 2 );
+						
+					}
+					
+				}
+				
+				canvas.loaded = true;
+				
+				return new THREE.MeshLambertMaterial( { map: new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter ) } );
+				
+			}
+		
+			function drawHex( ctx, n, x, y ) {
+				
+				ctx.fillStyle = "black";
+				ctx.font = "8pt arial";
+				ctx.textBaseline = "top";
+				
+				var s = n.toString( 16 );
+				s = n < 16 ? "0" + s : s;
+				ctx.fillText( s, x, y );
+				
+			}
+
+			function drawBase( ctx, image, sx, sy, tile, debug_texture ) {
+			
+				if ( debug_texture ) {
+				
+					ctx.fillStyle = "#888";				
+					ctx.fillRect( sx, sy, tile, tile );
+					
+				} else {
+				
+					ctx.drawImage( image, sx, sy, tile, tile );
+					
+				}
+				
+			}
+
+			function drawCorner( ctx, sx, sy, sa, ea, color, step, n ) {
+			
+				for( var i = 0; i < n; i++ ) {
+				
+					ctx.strokeStyle = color + step * ( n - i ) + ")";
+					ctx.beginPath();
+					ctx.arc( sx, sy, i, sa, ea, 0 ) ;
+					ctx.stroke();
+					
+				}
+				
+			}
+
+			function drawSide( ctx, sx, sy, a, b, n, width, height, color, step ) {
+			
+				for( var i = 0; i < n; i++ ) {
+				
+					ctx.fillStyle = color + step * ( n - i ) + ")";
+					ctx.fillRect( sx + a * i, sy + b * i, width, height );
+					
+				}
+			}
+
+			function drawAOSides( ctx, image, row, column, sides, tile, strength, debug_texture, debug_numbers ) {
+			
+				var sx = column * tile, sy = row * tile;
+				
+				drawBase( ctx, image, sx, sy, tile, debug_texture );
+				drawAOSidesImp( ctx, image, row, column, sides, tile, strength );
+				
+				if ( debug_numbers ) drawHex( ctx, row * tile + sides, sx + 2, sy + 2 );
+				
+			}
+			
+			function drawAOCorners( ctx, image, row, column, corners, tile, strength, debug_texture, debug_numbers, debug_corner_colors ) {
+			
+				var sx = column * tile, sy = row * tile;
+				
+				drawBase( ctx, image, sx, sy, tile, debug_texture );
+				drawAOCornersImp( ctx, image, row, column, corners, tile, strength, debug_corner_colors );
+				
+				if ( debug_numbers ) drawHex( ctx, row * tile + corners, sx + 2, sy + 2 );
+				
+			}
+			
+			function drawAOMixed( ctx, image, row, column, elements, tile, strength, debug_texture, debug_numbers, debug_corner_colors ) {
+
+				var sx = column * tile, sy = row * tile,
+				
+					mmap = {
+					0:  [ 1, 1 ],
+					1:  [ 1, 4 ],
+					2:  [ 2, 2 ],
+					3:  [ 2, 8 ],
+					4:  [ 4, 1 ],
+					5:  [ 4, 2 ],
+					6:  [ 8, 4 ],
+					7:  [ 8, 8 ],
+					8:  [ 1, 5 ],
+					9:  [ 2, 10 ],
+					10: [ 4, 3 ],
+					11: [ 8, 12 ],
+					12: [ 5, 1 ],
+					13: [ 6, 2 ],
+					14: [ 9, 4 ],
+					15: [ 10, 8 ]
+					};
+
+				drawBase( ctx, image, sx, sy, tile, debug_texture );
+				drawAOCornersImp( ctx, image, row, column, mmap[ elements ][1], tile, strength, debug_corner_colors );
+				drawAOSidesImp( ctx, image, row, column, mmap[ elements ][0], tile, strength );
+				
+				if ( debug_numbers ) drawHex( ctx, row * tile + elements, sx + 2, sy + 2 );
+				
+			}
+			
+			function drawAOSidesImp( ctx, image, row, column, sides, tile, strength ) {
+			
+				var sx = column * tile, sy = row * tile,
+					full = tile, step = 1 / full, half = full / 2 + strength,
+					
+					color = "rgba(0, 0, 0, ",
+					
+					left   = (sides & 8) == 8,
+					right  = (sides & 4) == 4,
+					bottom = (sides & 2) == 2,
+					top    = (sides & 1) == 1;
+
+				if ( bottom ) drawSide( ctx, sx, sy, 0, 1, half, tile, 1, color, step );
+				if ( top )    drawSide( ctx, sx, sy + full - 1, 0, -1, half, tile, 1, color, step );
+				if ( left )   drawSide( ctx, sx, sy, 1, 0, half, 1, tile, color, step );
+				if ( right )  drawSide( ctx, sx + full - 1, sy, -1, 0, half, 1, tile, color, step );
+				
+			}
+			
+			function drawAOCornersImp( ctx, image, row, column, corners, tile, strength, debug_corner_colors ) {
+
+				var sx = column * tile, sy = row * tile,
+				
+					full = tile, step = 1 / full, half = full / 2 + strength,
+					
+					color = "rgba(0, 0, 0, ",
+					
+					bottomright = (corners & 8) == 8,
+					topright  	= (corners & 4) == 4,
+					bottomleft  = (corners & 2) == 2,
+					topleft     = (corners & 1) == 1;
+
+				if ( topleft ) {
+				
+					if ( debug_corner_colors ) color = "rgba(200, 0, 0, ";
+					drawCorner( ctx, sx, sy, 0, 1.57, color, step, half );
+					
+				}
+				
+				if ( bottomleft ) {
+
+					if ( debug_corner_colors ) color = "rgba(0, 200, 0, ";
+					drawCorner( ctx, sx, sy + full, 4.71, 6.28, color, step, half );
+					
+				}
+				
+				if ( bottomright ) {
+
+					if ( debug_corner_colors ) color = "rgba(0, 0, 200, ";
+					drawCorner( ctx, sx + full, sy + full, 3.14, 4.71, color, step, half );					
+					
+				}
+				
+				if ( topright ) {
+				
+					if ( debug_corner_colors ) color = "rgba(200, 0, 200, ";
+					drawCorner( ctx, sx + full, sy, 1.57, 3.14, color, step, half );
+					
+				}
+				
+			}
+			
+			function loadTexture( path, callback ) {
+
+				var image = new Image();
+					
+				image.onload = function () { this.loaded = true; callback(); };
+				image.src = path;
+
+				return image;
+
+			}
+
+			function generateHeight( width, height ) {
+
+				var data = [], perlin = new ImprovedNoise(),
+				size = width * height, quality = 2, z = Math.random() * 100;
+
+				for ( var j = 0; j < 4; j ++ ) {
+
+					if ( j == 0 ) for ( var i = 0; i < size; i ++ ) data[ i ] = 0;
+
+					for ( var i = 0; i < size; i ++ ) {
+
+						var x = i % width, y = ~~ ( i / width );
+						data[ i ] += perlin.noise( x / quality, y / quality, z ) * quality;
+
+					}
+
+					quality *= 4
+
+				}
+
+				return data;
+
+			}
+
+			function getY( x, z ) {
+
+				return ~~( data[ x + z * worldWidth ] * 0.2 ) * 100;
+
+			}
+
+			function onDocumentMouseDown( event ) {
+
+				event.preventDefault();
+				event.stopPropagation();
+
+				switch ( event.button ) {
+
+					case 0: moveForward = true; break;
+					case 2: moveBackward = true; break;
+
+				}
+
+			}
+
+			function onDocumentMouseUp( event ) {
+
+				event.preventDefault();
+				event.stopPropagation();
+
+				switch ( event.button ) {
+
+					case 0: moveForward = false; break;
+					case 2: moveBackward = false; break;
+
+				}
+
+			}
+
+			function onDocumentMouseMove(event) {
+
+				mouseX = event.clientX - windowHalfX;
+				mouseY = event.clientY - windowHalfY;
+
+			}
+
+			function onDocumentKeyDown( event ) {
+
+				switch( event.keyCode ) {
+
+					case 38: /*↑*/ moveForward = true; break;
+					case 40: /*↓*/ moveBackward = true; break;
+
+					case 87: /*W*/ moveForward = true; break;
+					case 83: /*S*/ moveBackward = true; break;
+
+				}
+
+			}
+
+			function onDocumentKeyUp( event ) {
+
+				switch( event.keyCode ) {
+
+					case 38: /*↑*/ moveForward = false; break;
+					case 40: /*↓*/ moveBackward = false; break;
+
+					case 87: /*W*/ moveForward = false; break;
+					case 83: /*S*/ moveBackward = false; break;
+
+				}
+
+			}
+
+			function loop() {
+
+				if ( moveForward ) camera.translateZ( - 15 );
+				if ( moveBackward ) camera.translateZ( 15 );
+
+				lon += mouseX * 0.005;
+				lat -= mouseY * 0.005;
+
+				lat = Math.max( - 85, Math.min( 85, lat ) );
+				phi = ( 90 - lat ) * Math.PI / 180;
+				theta = lon * Math.PI / 180;
+
+				camera.target.position.x = 100 * Math.sin( phi ) * Math.cos( theta ) + camera.position.x;
+				camera.target.position.y = 100 * Math.cos( phi ) + camera.position.y;
+				camera.target.position.z = 100 * Math.sin( phi ) * Math.sin( theta ) + camera.position.z;
+
+				renderer.render(scene, camera);
+				stats.update();
+
+			}
+
+			function is_browser_compatible() {
+				
+				// WebGL support
+				
+				try { var test = new Float32Array(1); } catch(e) { return false; }
+				
+				// Web workers
+				
+				return !!window.Worker;
+			
+			}
+
+		</script>
+
+	</body>
+</html>

+ 3 - 2
src/renderers/WebGLRenderer.js

@@ -645,6 +645,9 @@ THREE.WebGLRenderer = function ( scene ) {
 		}
 
 		camera.autoUpdateMatrix && camera.updateMatrix();
+		
+		_viewMatrixArray.set( camera.matrix.flatten() );
+		_projectionMatrixArray.set( camera.projectionMatrix.flatten() );
 
 		// opaque pass
 
@@ -783,9 +786,7 @@ THREE.WebGLRenderer = function ( scene ) {
 
 		_modelViewMatrix.multiply( camera.matrix, object.matrix );
 
-		_viewMatrixArray.set( camera.matrix.flatten() );
 		_modelViewMatrixArray.set( _modelViewMatrix.flatten() );
-		_projectionMatrixArray.set( camera.projectionMatrix.flatten() );
 
 		_normalMatrix = THREE.Matrix4.makeInvert3x3( _modelViewMatrix ).transpose();
 		_normalMatrixArray.set( _normalMatrix.m );