Răsfoiți Sursa

Merge remote branch 'empaempa/master' into experimental

Mr.doob 14 ani în urmă
părinte
comite
0ccf06f593

Fișier diff suprimat deoarece este prea mare
+ 234 - 222
build/Three.js


+ 174 - 0
examples/webgl_stencil.html

@@ -0,0 +1,174 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js - webgl</title>
+		<meta charset="utf-8">
+		<style type="text/css">
+			body {
+				background:#fff;
+				padding:0;
+				margin:0;
+				font-weight: bold;
+				overflow:hidden;
+			}
+		</style>
+	</head>
+
+	<body>
+		<script type="text/javascript" src="../build/Three.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
+
+
+		<script type="text/javascript">
+			var statsEnabled = true;
+
+			var container, stats;
+
+			var camera, scene, renderer;
+
+			var mesh, boxMesh, light, lightCube, light2, lightCube2, zmesh, lightMesh, geometry;
+
+			var mouseX = 0, mouseY = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+
+			init();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.Camera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera.position.z = 250;
+
+				scene = new THREE.Scene();
+	
+
+				// world
+
+				var cube = new Cube( 300, 300, 10 );
+				var material0 = new THREE.MeshPhongMaterial( { color:0xff00ff } );
+				var material1 = new THREE.MeshLambertMaterial( { color:0x00ff00 } );
+				var material2 = new THREE.MeshLambertMaterial( { color:0x0000ff } );
+
+				var mesh1 = new THREE.Mesh( cube, material0 );
+				mesh1.position.z = -150;
+				scene.addChild( mesh1 );
+
+				var mesh2 = new THREE.Mesh( cube, material1 );
+				mesh2.position.x = -150;
+				mesh2.rotation.y = 90 * Math.PI / 180;
+				scene.addChild( mesh2 );
+
+				var mesh3 = new THREE.Mesh( cube, material2 );
+				mesh3.position.y = -150;
+				mesh3.rotation.x = 90 * Math.PI / 180;
+				scene.addChild( mesh3 );
+
+				new THREE.ShadowVolume( mesh1 )
+				new THREE.ShadowVolume( mesh2 )
+				new THREE.ShadowVolume( mesh3 )
+	
+	
+				// moving objects
+
+				var cube = new Cube( 40, 40, 40 );
+				var torus = new Torus( 40, 10 );
+				var sphere = new Sphere( 40 );
+				var cylinder = new Cylinder( 10, 10, 20, 40, 0, 0 );
+				mesh = new THREE.Mesh( torus, material1 );
+				scene.addChild( mesh );
+
+				boxMesh = new THREE.Mesh( cube, material2 );
+				scene.addChild( boxMesh );
+				
+				new THREE.ShadowVolume( mesh );
+				new THREE.ShadowVolume( boxMesh );
+
+
+				// lights
+
+				light = new THREE.DirectionalLight( 0xffffff );
+				light.position.set( 0, 1, 0 );
+				scene.addChild( light );
+
+				var cube = new Sphere( 5 );
+				lightCube = new THREE.Mesh( cube, material2 );
+				scene.addChild( lightCube );
+
+
+				// renderer
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setClearColorHex( 0xaaaaaa, 1 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( renderer.domElement );
+
+				if ( statsEnabled ) {
+
+					stats = new Stats();
+					stats.domElement.style.position = 'absolute';
+					stats.domElement.style.top = '0px';
+					stats.domElement.style.zIndex = 100;
+					container.appendChild( stats.domElement );
+
+				}
+
+				setInterval( loop, 1000 / 60 );
+			}
+
+
+			function onDocumentMouseMove(event) {
+
+				mouseX = ( event.clientX - windowHalfX );
+				mouseY = ( event.clientY - windowHalfY );
+
+			}
+
+			var t = 0;
+
+			function loop() {
+
+				mesh.position.x = Math.sin( t ) * 100;
+				mesh.position.y = Math.cos( t ) * 100;
+
+				mesh.rotation.x += 0.5 * Math.PI / 180;
+				mesh.rotation.y += 1.0 * Math.PI / 180;
+				mesh.rotation.z += 1.5 * Math.PI / 180;
+
+				boxMesh.position.z = Math.sin( t ) * 100;
+				boxMesh.rotation.x = Math.sin( t ) * 180 * Math.PI / 180;
+
+				light.position.x = Math.sin( t );
+				light.position.y = 1.5;
+				light.position.z = Math.cos( t );
+
+				lightCube.position.copy( light.position );
+				lightCube.position.multiplyScalar( 200 );
+
+
+				t += 0.02;
+
+				camera.position.x += ( mouseX - camera.position.x ) * .05;
+				camera.position.y += ( - mouseY - camera.position.y ) * .05;
+
+				renderer.render( scene, camera );
+
+				if ( statsEnabled ) stats.update();
+
+			}
+
+			function log( text ) {
+
+				var e = document.getElementById("log");
+				e.innerHTML = text + "<br/>" + e.innerHTML;
+
+			}
+		</script>
+
+	</body>
+</html>

+ 59 - 0
src/materials/ShadowVolumeDynamicMaterial.js

@@ -0,0 +1,59 @@
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ *  color: <hex>,
+ *  opacity: <float>,
+ *  map: new THREE.Texture( <Image> ),
+ 
+ *  lightMap: new THREE.Texture( <Image> ),
+ 
+ *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
+ *  combine: THREE.Multiply,
+ *  reflectivity: <float>,
+ *  refractionRatio: <float>,
+ 
+ *  shading: THREE.SmoothShading,
+ *  blending: THREE.NormalBlending,
+ *  depthTest: <bool>,
+ 
+ *  wireframe: <boolean>,
+ *  wireframeLinewidth: <float>,
+ 
+ *  vertexColors: <bool>,
+ *  skinning: <bool>
+ * }
+ */
+
+THREE.ShadowVolumeDynamicMaterial = function ( parameters ) {
+
+	this.id = THREE.MaterialCounter.value ++;
+
+	this.color = new THREE.Color( 0xffffff );
+	this.opacity = 1.0;
+	this.map = null;
+
+	this.lightMap = null;
+
+	this.envMap = null;
+	this.combine = THREE.MultiplyOperation;
+	this.reflectivity = 1.0;
+	this.refractionRatio = 0.98;
+
+	this.fog = true; // implemented just in WebGLRenderer2
+
+	this.shading = THREE.FlatShading;
+	this.blending = THREE.NormalBlending;
+	this.depthTest = true;
+
+	this.wireframe = false;
+	this.wireframeLinewidth = 1.0;
+	this.wireframeLinecap = 'round'; // implemented just in CanvasRenderer
+	this.wireframeLinejoin = 'round'; // implemented just in CanvasRenderer
+
+	this.vertexColors = false;
+	this.skinning = false;
+	this.morphTargets = false;
+
+};

+ 200 - 0
src/objects/ShadowVolume.js

@@ -0,0 +1,200 @@
+/*
+ * Shadow Volume
+ */
+
+THREE.ShadowVolume = function( mesh, isStatic ) {
+	
+	THREE.Mesh.call( this, mesh.geometry, isStatic ? [ new THREE.ShadowVolumeDynamicMaterial() ] : [ new THREE.ShadowVolumeDynamicMaterial() ] );
+	mesh.addChild( this );
+
+	this.calculateShadowVolumeGeometry( mesh.geometry );
+}
+
+THREE.ShadowVolume.prototype             = new THREE.Mesh();
+THREE.ShadowVolume.prototype.constructor = THREE.ShadowVolume;
+THREE.ShadowVolume.prototype.supr        = THREE.Mesh.prototype;
+
+
+/*
+ * Calculate Geometry
+ */
+
+THREE.ShadowVolume.prototype.calculateShadowVolumeGeometry = function( originalGeometry ) {
+	
+	// create geometry
+	
+	this.geometry = new THREE.Geometry();
+	this.geometry.boundingSphere = originalGeometry.boundingSphere;
+	this.geometry.edgeFaces = [];
+		
+	// copy vertices / faces from original mesh
+	
+	var vertexTypes = this.geometry.vertexTypes;
+	var vertices    = this.geometry.vertices;
+	var	faces       = this.geometry.faces;
+	var edgeFaces   = this.geometry.edgeFaces;
+
+	var originalFaces    = originalGeometry.faces;	
+	var originalVertices = originalGeometry.vertices;
+	var	fl               = originalFaces.length;
+	
+	var	originalFace, face, i, f, n, vertex, numVertices;
+	var indices = [ "a", "b", "c", "d" ];
+
+
+	for( f = 0; f < fl; f++ ) {
+		
+		numVertices = vertices.length;
+		originalFace = originalFaces[ f ];
+
+		if ( originalFace instanceof THREE.Face4 ) {
+			
+			n = 4;
+			face = new THREE.Face4( numVertices, numVertices + 1, numVertices + 2, numVertices + 3 );
+		
+		} else {
+			
+          	n = 3;
+			face = new THREE.Face3( numVertices, numVertices + 1, numVertices + 2 );
+		}
+
+		face.normal.copy( originalFace.normal );
+		faces.push( face );
+
+
+		for( i = 0; i < n; i++ ) {
+			
+			vertex = originalVertices[ originalFace[ indices[ i ]]];
+			vertices.push( new THREE.Vertex( vertex.position.clone()));
+		
+		}
+
+	}
+	
+
+	// calculate edge faces
+
+	var result, faceA, faceB, v, vl;
+	
+	for( var fa = 0; fa < originalFaces.length - 1; fa++ ) {
+		
+		faceA = faces[ fa ];
+		
+		for( var fb = fa + 1; fb < originalFaces.length; fb++ ) {
+			
+			faceB = faces[ fb ];
+			result = this.facesShareEdge( vertices, faceA, faceB );
+			
+			if( result !== undefined ) {
+
+				numVertices = vertices.length;
+				face = new THREE.Face4( result.indices[ 0 ], result.indices[ 3 ], result.indices[ 2 ], result.indices[ 1 ] );
+				face.normal.set( 1, 0, 0 );
+				edgeFaces.push( face );
+
+			}
+
+		}
+
+	}
+
+}
+
+
+
+/*
+ * Faces share edge?
+ */
+
+THREE.ShadowVolume.prototype.facesShareEdge = function( vertices, faceA, faceB ) {
+
+	var indicesA,
+		indicesB,
+		indexA,
+		indexB,
+		vertexA,
+		vertexB,
+		savedVertexA,
+		savedVertexB,
+		savedIndexA,
+		savedIndexB,
+		indexLetters,
+		a, b,
+		numMatches = 0,
+		indices = [ "a", "b", "c", "d" ];
+	
+	if( faceA instanceof THREE.Face4 ) indicesA = 4;
+	else                               indicesA = 3;
+	
+	if( faceB instanceof THREE.Face4 ) indicesB = 4;
+	else                               indicesB = 3;
+	
+	
+	for( a = 0; a < indicesA; a++ ) {
+		
+		indexA  = faceA[ indices[ a ] ];
+		vertexA = vertices[ indexA ];
+	
+		for( b = 0; b < indicesB; b++ ) {
+
+			indexB  = faceB[ indices[ b ] ];
+			vertexB = vertices[ indexB ];
+			
+			if( Math.abs( vertexA.position.x - vertexB.position.x ) < 0.0001 &&
+				Math.abs( vertexA.position.y - vertexB.position.y ) < 0.0001 &&
+				Math.abs( vertexA.position.z - vertexB.position.z ) < 0.0001 ) {
+			
+				numMatches++;
+				
+				if( numMatches === 1 ) {
+					
+ 					savedVertexA = vertexA;
+ 					savedVertexB = vertexB;
+					savedIndexA  = indexA;
+					savedIndexB  = indexB;
+					indexLetters = indices[ a ];
+
+				}
+				
+				if( numMatches === 2 ) {
+
+					indexLetters += indices[ a ];
+					
+					if( indexLetters === "ad" || indexLetters === "ac" ) {
+						
+						return {
+							
+							faces   	: [ faceA, faceB ],
+							vertices	: [ savedVertexA, savedVertexB, vertexB, vertexA  ],
+							indices		: [ savedIndexA,  savedIndexB,  indexB,  indexA   ],
+							vertexTypes	: [ 1, 2, 2, 1 ],
+							extrudable	: true
+
+						};
+
+					} else {
+						
+						return {
+							
+							faces   	: [ faceA, faceB ],
+							vertices	: [ savedVertexA, vertexA, vertexB, savedVertexB ],
+							indices		: [ savedIndexA,  indexA,  indexB,  savedIndexB  ],
+							vertexTypes	: [ 1, 1, 2, 2 ],
+							extrudable	: true
+
+						};
+
+					}
+					
+				}
+				
+			}
+			
+		}
+		
+	}
+
+	return undefined;
+
+}
+

+ 245 - 10
src/renderers/WebGLRenderer.js

@@ -32,6 +32,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 	_oldFlipSided = null,
 	_oldBlending = null,
 	_oldDepth = null,
+	_cullEnabled = true,
 
 	_viewportX = 0,
 	_viewportY = 0,
@@ -88,7 +89,42 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	this.context = _gl;
 
-	// alert( dumpObject( getGLParams() ) );
+
+	// create shadow polygons
+
+	var _shadow   = {};
+	var vertices = [];
+	var faces    = [];
+	
+	vertices[ 0 * 3 + 0 ] = -2; vertices[ 0 * 3 + 1 ] = -1; vertices[ 0 * 3 + 2 ] = -1;
+	vertices[ 1 * 3 + 0 ] =  2; vertices[ 1 * 3 + 1 ] = -1; vertices[ 1 * 3 + 2 ] = -1;
+	vertices[ 2 * 3 + 0 ] =  2; vertices[ 2 * 3 + 1 ] =  1; vertices[ 2 * 3 + 2 ] = -1;
+	vertices[ 3 * 3 + 0 ] = -2; vertices[ 3 * 3 + 1 ] =  1; vertices[ 3 * 3 + 2 ] = -1;
+	
+	faces[ 0 ] = 0; faces[ 1 ] = 1; faces[ 2 ] = 2;
+	faces[ 3 ] = 0; faces[ 4 ] = 2; faces[ 5 ] = 3;
+
+
+	_shadow.vertexBuffer  = _gl.createBuffer();
+	_shadow.elementBuffer = _gl.createBuffer();
+	
+	_gl.bindBuffer( _gl.ARRAY_BUFFER, _shadow.vertexBuffer );
+	_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( vertices ), _gl.STATIC_DRAW );
+
+	_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _shadow.elementBuffer );
+	_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( faces ), _gl.STATIC_DRAW );
+	
+
+	_shadow.program = _gl.createProgram();
+
+	_gl.attachShader( _shadow.program, getShader( "fragment", THREE.ShaderLib.shadowPost.fragmentShader ));
+	_gl.attachShader( _shadow.program, getShader( "vertex",   THREE.ShaderLib.shadowPost.vertexShader   ));
+
+	_gl.linkProgram( _shadow.program );
+
+	_shadow.vertexLocation     = _gl.getAttribLocation ( _shadow.program, "position"         );
+	_shadow.projectionLocation = _gl.getUniformLocation( _shadow.program, "projectionMatrix" );
+
 
 	this.setSize = function ( width, height ) {
 
@@ -147,7 +183,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	this.clear = function () {
 
-		_gl.clear( _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT );
+		_gl.clear( _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT | _gl.STENCIL_BUFFER_BIT );
 
 	};
 
@@ -321,7 +357,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function initMeshBuffers ( geometryGroup, object ) {
 
-		var f, fl, 
+		var f, fl, fi, face,
 		
 			nvertices = 0, ntris = 0, nlines = 0,
 			
@@ -408,7 +444,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
-		geometryGroup.__faceArray = new Uint16Array( ntris * 3 );
+		geometryGroup.__faceArray = new Uint16Array( ntris * 3 + ( object.geometry.edgeFaces ? object.geometry.edgeFaces.length * 2 * 3 : 0 ));
 		geometryGroup.__lineArray = new Uint16Array( nlines * 2 );
 
 		if( geometryGroup.numMorphTargets ) {
@@ -429,7 +465,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		geometryGroup.__vertexColorType = vertexColorType;
 		geometryGroup.__normalType = normalType;
 
-		geometryGroup.__webGLFaceCount = ntris * 3;
+		geometryGroup.__webGLFaceCount = ntris * 3 + ( object.geometry.edgeFaces ? object.geometry.edgeFaces.length * 2 * 3 : 0 );
 		geometryGroup.__webGLLineCount = nlines * 2;		
 
 	};
@@ -510,6 +546,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		obj_skinVerticesB = geometry.skinVerticesB,
 		obj_skinIndices = geometry.skinIndices,
 		obj_skinWeights = geometry.skinWeights,
+		obj_edgeFaces = geometry.edgeFaces,
 
 		morphTargets = geometry.morphTargets;
 		
@@ -1163,6 +1200,24 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
+		if( obj_edgeFaces ) {
+			
+			for( f = 0, fl = obj_edgeFaces.length; f < fl; f++ ) {
+				
+				faceArray[ offset_face ]     = obj_edgeFaces[ f ].a;
+				faceArray[ offset_face + 1 ] = obj_edgeFaces[ f ].b;
+				faceArray[ offset_face + 2 ] = obj_edgeFaces[ f ].c;
+
+				faceArray[ offset_face + 3 ] = obj_edgeFaces[ f ].a;
+				faceArray[ offset_face + 4 ] = obj_edgeFaces[ f ].c;
+				faceArray[ offset_face + 5 ] = obj_edgeFaces[ f ].d;
+
+				offset_face += 6;
+			}
+			
+		}
+
+
 		if ( dirtyVertices ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer );
@@ -1556,6 +1611,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			setMaterialShaders( material, THREE.ShaderLib[ 'depth' ] );
 
+		} else if ( material instanceof THREE.ShadowVolumeDynamicMaterial ) {
+
+			setMaterialShaders( material, THREE.ShaderLib[ 'shadowVolumeDynamic' ] );
+
 		} else if ( material instanceof THREE.MeshNormalMaterial ) {
 
 			setMaterialShaders( material, THREE.ShaderLib[ 'normal' ] );
@@ -1791,6 +1850,20 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
+		if( material instanceof THREE.ShadowVolumeDynamicMaterial ) {
+			
+			var dirLight = m_uniforms.directionalLightDirection.value;
+			
+			dirLight[ 0 ] = -lights.position.x;
+			dirLight[ 1 ] = -lights.position.y;
+			dirLight[ 2 ] = -lights.position.z;
+			
+			_gl.uniform3fv( p_uniforms.directionalLightDirection, dirLight );
+			_gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray );
+			_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, _viewMatrixArray );
+		}
+
+
 		if ( material.skinning ) {
 
 			loadUniformsSkinning( p_uniforms, object );
@@ -2270,6 +2343,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			this.clear();
 
 		}
+		
 
 		// set matrices
 
@@ -2459,6 +2533,150 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
+
+
+		//////////////////////// stencil shadows begin //////////////////////
+		// method: we're rendering the world in light, then the shadow
+		//         volumes into the stencil and last a big darkening 
+		//         quad over the whole thing. This is NOT how you're
+		//         supposed to do stencil shadows but is much faster
+		//
+
+		if( scene.__webglShadowVolumes.length && scene.lights.length ) {
+			
+			// setup stencil
+	
+			_gl.enable( _gl.POLYGON_OFFSET_FILL );
+			_gl.polygonOffset( 0.1, 1.0 );
+			_gl.enable( _gl.STENCIL_TEST );
+			_gl.depthMask( false );
+			_gl.colorMask( false, false, false, false );
+		
+			_gl.stencilFunc( _gl.ALWAYS, 1, 0xFF );
+			_gl.stencilOpSeparate( _gl.BACK,  _gl.KEEP, _gl.INCR, _gl.KEEP );
+			_gl.stencilOpSeparate( _gl.FRONT, _gl.KEEP, _gl.DECR, _gl.KEEP );
+	
+	
+			
+			// loop through all directional lights
+			
+			var l, ll = scene.lights.length;
+			var p;
+			var light, geometryGroup;
+			var dirLight = [];			
+			var	program;
+			var p_uniforms;
+		    var m_uniforms;
+		    var attributes;
+	
+			ol = scene.__webglShadowVolumes.length;
+			
+			for( l = 0; l < ll; l++ ) {
+				
+				light = scene.lights[ l ];
+				
+				if( light instanceof THREE.DirectionalLight ) {
+
+					dirLight[ 0 ] = -light.position.x;
+					dirLight[ 1 ] = -light.position.y;
+					dirLight[ 2 ] = -light.position.z;
+
+					
+					// render all volumes
+					
+					for ( o = 0; o < ol; o++ ) {
+			
+						object        = scene.__webglShadowVolumes[ o ].object;
+						geometryGroup = scene.__webglShadowVolumes[ o ].buffer;
+						material      = object.materials[ 0 ];
+
+
+						if ( !material.program ) _this.initMaterial( material, lights, fog, object );
+	
+						program = material.program,
+			  			p_uniforms = program.uniforms,
+		                m_uniforms = material.uniforms,
+		                attributes = program.attributes;
+
+
+						if( _oldProgram !== program ) {
+							
+							_gl.useProgram( program );
+							_oldProgram = program;
+
+							_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, _projectionMatrixArray );
+							_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, _viewMatrixArray );
+							_gl.uniform3fv( p_uniforms.directionalLightDirection, dirLight );
+						}
+
+
+						object.matrixWorld.flattenToArray( object._objectMatrixArray );
+						//object._modelViewMatrix.multiplyToArray( camera.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray );
+
+						_gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray );
+						//_gl.uniformMatrix4fv( p_uniforms.modelViewMatrix, false, object._modelViewMatrixArray );
+
+	
+						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer );
+						_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+
+						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLNormalBuffer );
+						_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
+
+						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLFaceBuffer );
+
+						_gl.cullFace( _gl.FRONT );
+						_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 );
+
+						_gl.cullFace( _gl.BACK );
+						_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 );
+				
+					}
+	
+				}
+	
+			}
+	
+	
+			// draw darkening polygon	
+	
+			_gl.disable( _gl.POLYGON_OFFSET_FILL );
+			_gl.colorMask( true, true, true, true );
+			_gl.stencilFunc( _gl.NOTEQUAL, 0, 0xFF );
+			_gl.stencilOp( _gl.KEEP, _gl.KEEP, _gl.KEEP );
+		    _gl.disable( _gl.DEPTH_TEST );
+			
+			_gl.enable( _gl.BLEND );
+			_gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
+			_gl.blendEquation( _gl.FUNC_ADD );
+	
+	
+			_oldBlending = "";
+			_oldProgram = _shadow.program;
+	
+			_gl.useProgram( _shadow.program );
+			_gl.uniformMatrix4fv( _shadow.projectionLocation, false, _projectionMatrixArray );
+			
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, _shadow.vertexBuffer );
+			_gl.vertexAttribPointer( _shadow.vertexLocation, 3, _gl.FLOAT, false, 0, 0 );
+			_gl.enableVertexAttribArray( _shadow.vertexLocation );
+				
+			_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _shadow.elementBuffer );
+			_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
+	
+	
+			// disable stencil
+	
+		    _gl.disable	 ( _gl.STENCIL_TEST );
+		    _gl.enable	 ( _gl.DEPTH_TEST );
+			_gl.disable  ( _gl.BLEND );
+		    _gl.depthMask( true );
+		}
+
+
+		//////////////////////// stencil shadows end //////////////////////
+
+
 		// Generate mipmap if we're using any kind of mipmap filtering
 
 		if ( renderTarget && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
@@ -2482,7 +2700,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			scene.__webglObjects = [];
 			scene.__webglObjectsImmediate = [];
-
+			scene.__webglShadowVolumes = [];
 		}
 
 		while ( scene.__objectsAdded.length ) {
@@ -2506,6 +2724,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 			updateObject( scene.__webglObjects[ o ].object, scene );
 
 		}
+		
+		for ( var o = 0, ol = scene.__webglShadowVolumes.length; o < ol; o ++ ) {
+
+			updateObject( scene.__webglShadowVolumes[ o ].object, scene );
+
+		}
+		
 
 	};
 
@@ -2560,8 +2785,15 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				// create separate wrapper per each use of VBO
 
-				addBuffer( scene.__webglObjects, geometryGroup, object );
-
+				if( object instanceof THREE.ShadowVolume ) {
+					
+					addBuffer( scene.__webglShadowVolumes, geometryGroup, object );
+					
+				} else {
+					
+					addBuffer( scene.__webglObjects, geometryGroup, object );
+					
+				}
 			}
 
 		} else if ( object instanceof THREE.Ribbon ) {
@@ -2870,7 +3102,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		try {
 
-			if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { antialias: antialias } ) ) ) {
+			if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { antialias: antialias, stencil:true } ) ) ) {
 
 				throw 'Error creating WebGL context.';
 
@@ -3363,7 +3595,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			case THREE.LinearFilter:
 			case THREE.LinearMipMapNearestFilter:
-			case THREE.LinearMipMapLinearFilter: return _gl.LINEAR; break;
+			case THREE.LinearMipMapLinearFilter: 
+			default:
+				
+				return _gl.LINEAR; break;
 
 		}
 		

+ 61 - 0
src/renderers/WebGLShaders.js

@@ -6,6 +6,7 @@
 
 THREE.ShaderChunk = {
 
+
 	// FOG
 
 	fog_pars_fragment: [
@@ -555,6 +556,66 @@ THREE.UniformsLib = {
 
 THREE.ShaderLib = {
 
+	'shadowPost': {
+		
+		vertexShader: [
+		
+			"uniform 	mat4 	projectionMatrix;",
+			"attribute 	vec3 	position;",
+	
+			"void main(void)",
+			"{",
+				"gl_Position = projectionMatrix * vec4( position, 1.0 );",
+			"}"
+
+		].join( "\n" ),
+		
+		fragmentShader: [
+		
+			"#ifdef GL_ES",
+				"precision highp float;",
+			"#endif",		
+	
+			"void main( void )",
+			"{",
+				"gl_FragColor = vec4( 0, 0, 0, 0.5 );",
+			"}"
+
+		].join( "\n" )
+		
+	},
+
+
+	'shadowVolumeDynamic': {
+		
+		uniforms: { "directionalLightDirection": { type: "fv", value: [] }},
+
+		vertexShader: [
+
+			"uniform 	vec3 	directionalLightDirection;",
+	
+			"void main() {",
+
+				"vec4 pos      = objectMatrix * vec4( position, 1.0 );",
+				"vec3 norm     = mat3( objectMatrix[0].xyz, objectMatrix[1].xyz, objectMatrix[2].xyz ) * normal;",
+				"vec4 extruded = vec4( directionalLightDirection * 5000.0 * step( 0.0, dot( directionalLightDirection, norm )), 0.0 );",
+				"gl_Position   = projectionMatrix * viewMatrix * ( pos + extruded );",
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"void main() {",
+
+				"gl_FragColor = vec4( 1, 1, 1, 1 );",
+
+			"}"
+
+		].join( "\n" )
+	},		
+
+
 	'depth': {
 
 		uniforms: { "mNear": { type: "f", value: 1.0 },

+ 2 - 0
utils/build.py

@@ -46,6 +46,7 @@ COMMON_FILES = [
 'materials/MeshNormalMaterial.js',
 'materials/MeshFaceMaterial.js',
 'materials/MeshShaderMaterial.js',
+'materials/ShadowVolumeDynamicMaterial.js',
 'materials/ParticleBasicMaterial.js',
 'materials/ParticleCanvasMaterial.js',
 'materials/ParticleDOMMaterial.js',
@@ -61,6 +62,7 @@ COMMON_FILES = [
 'objects/Ribbon.js',
 'objects/Sound.js',
 'objects/LOD.js',
+'objects/ShadowVolume.js',
 'scenes/Scene.js',
 'scenes/Fog.js',
 'scenes/FogExp2.js',

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff