Bladeren bron

Add stenciling

Garrett Johnson 6 jaren geleden
bovenliggende
commit
b8f05809ce
1 gewijzigde bestanden met toevoegingen van 130 en 68 verwijderingen
  1. 130 68
      examples/webgl_clipping_stencil.html

+ 130 - 68
examples/webgl_clipping_stencil.html

@@ -22,20 +22,89 @@
 		<script>
 
 			var camera, scene, renderer, startTime, object, stats;
+			var planes, planeObjects;
+			var clock;
+
+			var params = {
+
+				animate: true
+
+			};
 
 			init();
 			animate();
 
+			function createStencilGroup( geometry, material, planes ) {
+
+				var group = new THREE.Group();
+				var baseMat = new THREE.MeshBasicMaterial();
+				baseMat.depthWrite = false;
+				baseMat.depthTest = false;
+				baseMat.colorWrite = false;
+				baseMat.clippingPlanes = planes;
+				baseMat.stencilWrite = true;
+				baseMat.stencilFail = THREE.AlwaysStencilFunc;
+
+				// // front faces no depth
+				// var mat0 = baseMat.clone();
+				// mat0.stencilFail = THREE.IncrementWrapStencilOp;
+				// mat0.stencilZFail = THREE.IncrementWrapStencilOp;
+				// mat0.stencilZPass = THREE.IncrementWrapStencilOp;
+				// var mesh0 = new THREE.Mesh( geometry, mat0 );
+				// group.add( mesh0 );
+
+				// // back faces no depth
+				// var mat1 = baseMat.clone();
+				// mat1.stencilFail = THREE.DecrementWrapStencilOp;
+				// mat1.stencilZFail = THREE.DecrementWrapStencilOp;
+				// mat1.stencilZPass = THREE.DecrementWrapStencilOp;
+				// var mesh1 = new THREE.Mesh( geometry, mat1 );
+				// group.add( mesh1 );
+
+				// back faces
+				var mat0 = baseMat.clone();
+				mat0.side = THREE.BackSide;
+				mat0.stencilFail = THREE.IncrementWrapStencilOp;
+				mat0.stencilZFail = THREE.IncrementWrapStencilOp;
+				mat0.stencilZPass = THREE.IncrementWrapStencilOp;
+
+				var mesh0 = new THREE.Mesh( geometry, mat0 );
+				mesh0.renderOrder = 1;
+				group.add( mesh0 );
+
+				// front faces
+				var mat1 = material.clone();
+				mat1.side = THREE.FrontSide;
+				mat1.clippingPlanes = planes;
+				mat1.stencilWrite = true;
+				mat1.stencilFail = THREE.AlwaysStencilFunc;
+				mat1.stencilFail = THREE.DecrementWrapStencilOp;
+				mat1.stencilZFail = THREE.DecrementWrapStencilOp;
+				mat1.stencilZPass = THREE.DecrementWrapStencilOp;
+
+				var mesh1 = new THREE.Mesh( geometry, mat1 );
+				mesh1.castShadow = true;
+				mesh1.receiveShadow = true;
+				mesh1.renderOrder = 1;
+
+				group.add( mesh1 );
+
+				console.log( mat0, mat1 )
+
+				return group;
+
+			}
+
 			function init() {
 
-				camera = new THREE.PerspectiveCamera( 36, window.innerWidth / window.innerHeight );
+				clock = new THREE.Clock();
+
+				camera = new THREE.PerspectiveCamera( 36, window.innerWidth / window.innerHeight, 1 );
 
 				camera.position.set( 0, 1.3, 3 );
 
 				scene = new THREE.Scene();
 
-				// Lights
-
 				scene.add( new THREE.AmbientLight( 0xffffff, 0.5 ) );
 
 				var dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
@@ -50,10 +119,38 @@
 				dirLight.shadow.mapSize.height = 1024;
 				scene.add( dirLight );
 
-				// ***** Clipping planes: *****
+				planes = [
+					new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 0 ),
+					new THREE.Plane( new THREE.Vector3( - 1, 0, 0 ), 0 ),
+					new THREE.Plane( new THREE.Vector3( 0, 0, - 1 ), 0 )
+				];
+
+				planeObjects = new Array( 3 );
+				var planeGeom = new THREE.PlaneBufferGeometry( 10, 10 );
+				for ( var i = 0; i < planes.length; i ++ ) {
+
+					var plane = planes[ i ];
+					var planeMat =
+						new THREE.MeshStandardMaterial( {
+							color: 0xE91E63,
+							metalness: 0.1,
+							roughness: 0.75,
+							side: THREE.DoubleSide,
+							clippingPlanes: planes.filter( p => p !== plane ),
+							clipShadows: true,
+
+							stencilWrite: true,
+							stencilRef: 0,
+							stencilFunc: THREE.NotEqualStencilFunc,
 
-				var localPlane = new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 0.8 );
-				var globalPlane = new THREE.Plane( new THREE.Vector3( - 1, 0, 0 ), 0.1 );
+						} );
+					var po = new THREE.Mesh( planeGeom, planeMat );
+					po.renderOrder = 2;
+
+					scene.add( po );
+					planeObjects[ i ] = po;
+
+				}
 
 				// Geometry
 
@@ -62,23 +159,23 @@
 					metalness: 0.1,
 					roughness: 0.75,
 					side: THREE.DoubleSide,
-					clippingPlanes: [ localPlane ],
+					clippingPlanes: planes,
 					clipShadows: true
-
 				} );
 
 				var geometry = new THREE.TorusKnotBufferGeometry( 0.4, 0.15, 220, 60 );
-
-				object = new THREE.Mesh( geometry, material );
-				object.castShadow = true;
+				object = createStencilGroup( geometry, material, planes );
 				scene.add( object );
 
+
+
 				var ground = new THREE.Mesh(
 					new THREE.PlaneBufferGeometry( 9, 9, 1, 1 ),
 					new THREE.ShadowMaterial( { color: 0, opacity: 0.25, side: THREE.DoubleSide } )
 				);
 
 				ground.rotation.x = - Math.PI / 2; // rotates X/Y to X/Z
+				ground.position.y = - 1;
 				ground.receiveShadow = true;
 				scene.add( ground );
 
@@ -97,66 +194,17 @@
 				window.addEventListener( 'resize', onWindowResize, false );
 				document.body.appendChild( renderer.domElement );
 
-				// ***** Clipping setup (renderer): *****
-				var globalPlanes = [ globalPlane ],
-					Empty = Object.freeze( [] );
-				renderer.clippingPlanes = Empty; // GUI sets it to globalPlanes
 				renderer.localClippingEnabled = true;
 
 				// Controls
 
 				var controls = new THREE.OrbitControls( camera, renderer.domElement );
-				controls.target.set( 0, 1, 0 );
 				controls.update();
 
 				// GUI
 
-				var gui = new dat.GUI(),
-					folderLocal = gui.addFolder( 'Local Clipping' ),
-					propsLocal = {
-
-						get 'Enabled'() {
-
-							return renderer.localClippingEnabled;
-
-						},
-						set 'Enabled'( v ) {
-
-							renderer.localClippingEnabled = v;
-
-						},
-
-						get 'Shadows'() {
-
-							return material.clipShadows;
-
-						},
-						set 'Shadows'( v ) {
-
-							material.clipShadows = v;
-
-						},
-
-						get 'Plane'() {
-
-							return localPlane.constant;
-
-						},
-						set 'Plane'( v ) {
-
-							localPlane.constant = v;
-
-						}
-
-					};
-
-				folderLocal.add( propsLocal, 'Enabled' );
-				folderLocal.add( propsLocal, 'Shadows' );
-				folderLocal.add( propsLocal, 'Plane', 0.3, 1.25 );
-
-				// Start
-
-				startTime = Date.now();
+				var gui = new dat.GUI();
+				gui.add( params, 'animate' );
 
 			}
 
@@ -171,15 +219,29 @@
 
 			function animate() {
 
-				var currentTime = Date.now();
-				var time = ( currentTime - startTime ) / 1000;
+				var delta = clock.getDelta();
 
 				requestAnimationFrame( animate );
 
-				object.position.y = 0.8;
-				object.rotation.x = time * 0.5;
-				object.rotation.y = time * 0.2;
-				object.scale.setScalar( Math.cos( time ) * 0.125 + 0.875 );
+				if ( params.animate ) {
+
+					object.rotation.x += delta * 0.5;
+					object.rotation.y += delta * 0.2;
+
+				}
+
+				for ( var i = 0; i < planes.length; i ++ ) {
+
+					var plane = planes[ i ];
+					var po = planeObjects[ i ];
+					plane.coplanarPoint( po.position );
+					po.lookAt(
+						po.position.x + plane.normal.x,
+						po.position.y + plane.normal.y,
+						po.position.z + plane.normal.z,
+					);
+
+				}
 
 				stats.begin();
 				renderer.render( scene, camera );