Explorar o código

#7952 New Stencil Buffer Management

This commit enables three.js to manage the stencil buffer via material
properties.
Mugen87 %!s(int64=9) %!d(string=hai) anos
pai
achega
644d6a21d7

+ 1 - 0
examples/js/postprocessing/AdaptiveToneMappingPass.js

@@ -163,6 +163,7 @@ THREE.AdaptiveToneMappingPass.prototype = {
 		}
 
 		this.quad.material = this.materialToneMap;
+		this.quad.material.stencilTest = maskActive;
 		this.materialToneMap.uniforms.tDiffuse.value = readBuffer;
 		renderer.render( this.scene, this.camera, writeBuffer, this.clear );
 

+ 1 - 5
examples/js/postprocessing/BloomPass.js

@@ -78,8 +78,6 @@ THREE.BloomPass.prototype = {
 
 	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
-		if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
-
 		// Render quad with blured scene into texture (convolution pass 1)
 
 		this.quad.material = this.materialConvolution;
@@ -100,13 +98,11 @@ THREE.BloomPass.prototype = {
 		// Render original scene with superimposed blur to texture
 
 		this.quad.material = this.materialCopy;
+		this.quad.material.stencilTest = maskActive;
 
 		this.copyUniforms[ "tDiffuse" ].value = this.renderTargetY;
 
-		if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
-
 		renderer.render( this.scene, this.camera, readBuffer, this.clear );
-
 	}
 
 };

+ 5 - 5
examples/js/postprocessing/BokehPass.js

@@ -37,7 +37,7 @@ THREE.BokehPass = function ( scene, camera, params ) {
 		console.error( "THREE.BokehPass relies on THREE.BokehShader" );
 
 	}
-	
+
 	var bokehShader = THREE.BokehShader;
 	var bokehUniforms = THREE.UniformsUtils.clone( bokehShader.uniforms );
 
@@ -63,8 +63,8 @@ THREE.BokehPass = function ( scene, camera, params ) {
 	this.camera2 = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
 	this.scene2  = new THREE.Scene();
 
-	this.quad2 = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
-	this.scene2.add( this.quad2 );
+	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
+	this.scene2.add( this.quad );
 
 };
 
@@ -72,7 +72,8 @@ THREE.BokehPass.prototype = {
 
 	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
-		this.quad2.material = this.materialBokeh;
+		this.quad.material = this.materialBokeh;
+		this.quad.material.stencilTest = maskActive;
 
 		// Render depth into texture
 
@@ -99,4 +100,3 @@ THREE.BokehPass.prototype = {
 	}
 
 };
-

+ 4 - 1
examples/js/postprocessing/ClearPass.js

@@ -10,11 +10,14 @@ THREE.ClearPass = function () {
 
 THREE.ClearPass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer ) {
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 		renderer.setRenderTarget( readBuffer );
 		renderer.clear();
 
+		renderer.setRenderTarget( writeBuffer );
+		renderer.clear();
+
 	}
 
 };

+ 2 - 1
examples/js/postprocessing/DotScreenPass.js

@@ -38,12 +38,13 @@ THREE.DotScreenPass = function ( center, angle, scale ) {
 
 THREE.DotScreenPass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 		this.uniforms[ "tDiffuse" ].value = readBuffer;
 		this.uniforms[ "tSize" ].value.set( readBuffer.width, readBuffer.height );
 
 		this.quad.material = this.material;
+		this.quad.material.stencilTest = maskActive;
 
 		if ( this.renderToScreen ) {
 

+ 5 - 20
examples/js/postprocessing/EffectComposer.js

@@ -24,13 +24,10 @@ THREE.EffectComposer = function ( renderer, renderTarget ) {
 	this.writeBuffer = this.renderTarget1;
 	this.readBuffer = this.renderTarget2;
 
-	this.passes = [];
-
-	if ( THREE.CopyShader === undefined )
-		console.error( "THREE.EffectComposer relies on THREE.CopyShader" );
-
-	this.copyPass = new THREE.ShaderPass( THREE.CopyShader );
+	if ( THREE.MaskPass === undefined )
+		console.error( "THREE.EffectComposer relies on THREE.MaskPass" );
 
+	this.passes = [];
 };
 
 THREE.EffectComposer.prototype = {
@@ -57,11 +54,11 @@ THREE.EffectComposer.prototype = {
 
 	render: function ( delta ) {
 
+		var maskActive = false;
+
 		this.writeBuffer = this.renderTarget1;
 		this.readBuffer = this.renderTarget2;
 
-		var maskActive = false;
-
 		var pass, i, il = this.passes.length;
 
 		for ( i = 0; i < il; i ++ ) {
@@ -74,18 +71,6 @@ THREE.EffectComposer.prototype = {
 
 			if ( pass.needsSwap ) {
 
-				if ( maskActive ) {
-
-					var context = this.renderer.context;
-
-					context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
-
-					this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );
-
-					context.stencilFunc( context.EQUAL, 1, 0xffffffff );
-
-				}
-
 				this.swapBuffers();
 
 			}

+ 2 - 1
examples/js/postprocessing/FilmPass.js

@@ -39,12 +39,13 @@ THREE.FilmPass = function ( noiseIntensity, scanlinesIntensity, scanlinesCount,
 
 THREE.FilmPass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 		this.uniforms[ "tDiffuse" ].value = readBuffer;
 		this.uniforms[ "time" ].value += delta;
 
 		this.quad.material = this.material;
+		this.quad.material.stencilTest = maskActive;
 
 		if ( this.renderToScreen ) {
 

+ 14 - 12
examples/js/postprocessing/GlitchPass.js

@@ -1,19 +1,19 @@
 /**
- 
+
  */
 
 THREE.GlitchPass = function ( dt_size ) {
 
 	if ( THREE.DigitalGlitch === undefined ) console.error( "THREE.GlitchPass relies on THREE.DigitalGlitch" );
-	
+
 	var shader = THREE.DigitalGlitch;
 	this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
 
 	if ( dt_size == undefined ) dt_size = 64;
-	
-	
+
+
 	this.uniforms[ "tDisp" ].value = this.generateHeightmap( dt_size );
-	
+
 
 	this.material = new THREE.ShaderMaterial( {
 		uniforms: this.uniforms,
@@ -31,21 +31,21 @@ THREE.GlitchPass = function ( dt_size ) {
 
 	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
 	this.scene.add( this.quad );
-	
+
 	this.goWild = false;
 	this.curF = 0;
 	this.generateTrigger();
-	
+
 };
 
 THREE.GlitchPass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 		this.uniforms[ "tDiffuse" ].value = readBuffer;
 		this.uniforms[ 'seed' ].value = Math.random();//default seeding
 		this.uniforms[ 'byp' ].value = 0;
-		
+
 		if ( this.curF % this.randX == 0 || this.goWild == true ) {
 
 			this.uniforms[ 'amount' ].value = Math.random() / 30;
@@ -72,8 +72,10 @@ THREE.GlitchPass.prototype = {
 
 		}
 		this.curF ++;
-		
+
 		this.quad.material = this.material;
+    this.quad.material.stencilTest = maskActive;
+    
 		if ( this.renderToScreen ) {
 
 			renderer.render( this.scene, this.camera );
@@ -94,7 +96,7 @@ THREE.GlitchPass.prototype = {
 
 		var data_arr = new Float32Array( dt_size * dt_size * 3 );
 		var length = dt_size * dt_size;
-		
+
 		for ( var i = 0; i < length; i ++ ) {
 
 			var val = THREE.Math.randFloat( 0, 1 );
@@ -103,7 +105,7 @@ THREE.GlitchPass.prototype = {
 			data_arr[ i * 3 + 2 ] = val;
 
 		}
-		
+
 		var texture = new THREE.DataTexture( data_arr, dt_size, dt_size, THREE.RGBFormat, THREE.FloatType );
 		texture.needsUpdate = true;
 		return texture;

+ 22 - 28
examples/js/postprocessing/MaskPass.js

@@ -8,7 +8,7 @@ THREE.MaskPass = function ( scene, camera ) {
 	this.camera = camera;
 
 	this.enabled = true;
-	this.clear = true;
+	this.clear = false;
 	this.needsSwap = false;
 
 	this.inverse = false;
@@ -17,20 +17,16 @@ THREE.MaskPass = function ( scene, camera ) {
 
 THREE.MaskPass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
-		var context = renderer.context;
-
-		// don't update color or depth
-
-		context.colorMask( false, false, false, false );
-		context.depthMask( false );
+		var writeValue, clearValue;
 
-		// set up stencil
+		var context = renderer.context;
+		var state = renderer.state;
 
-		var writeValue, clearValue;
+		// check inverse masking
 
-		if ( this.inverse ) {
+		if ( this.inverse === true ) {
 
 			writeValue = 0;
 			clearValue = 1;
@@ -42,26 +38,28 @@ THREE.MaskPass.prototype = {
 
 		}
 
-		context.enable( context.STENCIL_TEST );
-		context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE );
-		context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff );
-		context.clearStencil( clearValue );
+		// setup WebGL state to prepare the stencil test
+
+		state.clearStencil( clearValue );
+
+		state.setStencilFunc( context.ALWAYS, writeValue, 0xffffffff );
+		state.setStencilOp( context.REPLACE, context.REPLACE, context.REPLACE );
+
+		// clear the stencil buffer before drawing
+
+		renderer.clearTarget( readBuffer, false, false, true );
+		renderer.clearTarget( writeBuffer, false, false, true );
 
 		// draw into the stencil buffer
 
 		renderer.render( this.scene, this.camera, readBuffer, this.clear );
 		renderer.render( this.scene, this.camera, writeBuffer, this.clear );
 
-		// re-enable update of color and depth
-
-		context.colorMask( true, true, true, true );
-		context.depthMask( true );
-
+		// setup WebGL state for upcoming stencil tests.
 		// only render where stencil is set to 1
 
-		context.stencilFunc( context.EQUAL, 1, 0xffffffff );  // draw if == 1
-		context.stencilOp( context.KEEP, context.KEEP, context.KEEP );
-
+		state.setStencilFunc( context.EQUAL, 1, 0xffffffff );  // draw if == 1
+		state.setStencilOp( context.KEEP, context.KEEP, context.KEEP );
 	}
 
 };
@@ -75,11 +73,7 @@ THREE.ClearMaskPass = function () {
 
 THREE.ClearMaskPass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
-
-		var context = renderer.context;
-
-		context.disable( context.STENCIL_TEST );
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 	}
 

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

@@ -23,7 +23,7 @@ THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clear
 
 THREE.RenderPass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 		this.scene.overrideMaterial = this.overrideMaterial;
 

+ 2 - 1
examples/js/postprocessing/SavePass.js

@@ -45,7 +45,7 @@ THREE.SavePass = function ( renderTarget ) {
 
 THREE.SavePass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 		if ( this.uniforms[ this.textureID ] ) {
 
@@ -54,6 +54,7 @@ THREE.SavePass.prototype = {
 		}
 
 		this.quad.material = this.material;
+		this.quad.material.stencilTest = maskActive;
 
 		renderer.render( this.scene, this.camera, this.renderTarget, this.clear );
 

+ 2 - 1
examples/js/postprocessing/ShaderPass.js

@@ -45,7 +45,7 @@ THREE.ShaderPass = function( shader, textureID ) {
 
 THREE.ShaderPass.prototype = {
 
-	render: function( renderer, writeBuffer, readBuffer, delta ) {
+	render: function( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 		if ( this.uniforms[ this.textureID ] ) {
 
@@ -54,6 +54,7 @@ THREE.ShaderPass.prototype = {
 		}
 
 		this.quad.material = this.material;
+		this.quad.material.stencilTest = maskActive;
 
 		if ( this.renderToScreen ) {
 

+ 2 - 2
examples/js/postprocessing/TexturePass.js

@@ -25,7 +25,6 @@ THREE.TexturePass = function ( texture, opacity ) {
 	this.enabled = true;
 	this.needsSwap = false;
 
-
 	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
 	this.scene  = new THREE.Scene();
 
@@ -36,9 +35,10 @@ THREE.TexturePass = function ( texture, opacity ) {
 
 THREE.TexturePass.prototype = {
 
-	render: function ( renderer, writeBuffer, readBuffer, delta ) {
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
 
 		this.quad.material = this.material;
+		this.quad.material.stencilTest = maskActive;
 
 		renderer.render( this.scene, this.camera, readBuffer );
 

+ 17 - 13
examples/webgl_postprocessing_advanced.html

@@ -61,6 +61,7 @@
 		<script src="js/postprocessing/TexturePass.js"></script>
 		<script src="js/postprocessing/ShaderPass.js"></script>
 		<script src="js/postprocessing/MaskPass.js"></script>
+		<script src="js/postprocessing/ClearPass.js"></script>
 
 		<script src="js/Detector.js"></script>
 		<script src="js/libs/stats.min.js"></script>
@@ -157,7 +158,7 @@
 				stats = new Stats();
 				stats.domElement.style.position = 'absolute';
 				stats.domElement.style.top = '0px';
-				//container.appendChild( stats.domElement );
+				container.appendChild( stats.domElement );
 
 				//
 
@@ -193,18 +194,16 @@
 				effectColorify1.uniforms[ 'color' ].value.setRGB( 1, 0.8, 0.8 );
 				effectColorify2.uniforms[ 'color' ].value.setRGB( 1, 0.75, 0.5 );
 
+				effectColorify1.needsSwap = false;
+
+				var clear = new THREE.ClearPass();
 				var clearMask = new THREE.ClearMaskPass();
 				var renderMask = new THREE.MaskPass( sceneModel, cameraPerspective );
 				var renderMaskInverse = new THREE.MaskPass( sceneModel, cameraPerspective );
 
 				renderMaskInverse.inverse = true;
 
-				//effectFilm.renderToScreen = true;
-				//effectFilmBW.renderToScreen = true;
-				//effectDotScreen.renderToScreen = true;
-				//effectBleach.renderToScreen = true;
 				effectVignette.renderToScreen = true;
-				//effectCopy.renderToScreen = true;
 
 				//
 
@@ -227,6 +226,7 @@
 
 				composerScene = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtWidth * 2, rtHeight * 2, rtParameters ) );
 
+				composerScene.addPass( clear );
 				composerScene.addPass( renderBackground );
 				composerScene.addPass( renderModel );
 				composerScene.addPass( renderMaskInverse );
@@ -238,20 +238,22 @@
 
 				renderScene = new THREE.TexturePass( composerScene.renderTarget2 );
 
-				//
+				// bottom left
 
 				composer1 = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtWidth, rtHeight, rtParameters ) );
 
+				composer1.addPass( clear );
 				composer1.addPass( renderScene );
 				//composer1.addPass( renderMask );
 				composer1.addPass( effectFilmBW );
 				//composer1.addPass( clearMask );
 				composer1.addPass( effectVignette );
 
-				//
+				// bottom right
 
 				composer2 = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtWidth, rtHeight, rtParameters ) );
 
+				composer2.addPass( clear );
 				composer2.addPass( renderScene );
 				composer2.addPass( effectDotScreen );
 				composer2.addPass( renderMask );
@@ -262,10 +264,11 @@
 				composer2.addPass( clearMask );
 				composer2.addPass( effectVignette );
 
-				//
+				// top left
 
 				composer3 = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtWidth, rtHeight, rtParameters ) );
 
+				composer3.addPass( clear );
 				composer3.addPass( renderScene );
 				//composer3.addPass( renderMask );
 				composer3.addPass( effectSepia );
@@ -273,10 +276,11 @@
 				//composer3.addPass( clearMask );
 				composer3.addPass( effectVignette );
 
-				//
+				// top right
 
 				composer4 = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtWidth, rtHeight, rtParameters ) );
 
+				composer4.addPass( clear );
 				composer4.addPass( renderScene );
 				//composer4.addPass( renderMask );
 				composer4.addPass( effectBloom );
@@ -287,8 +291,6 @@
 
 				//
 
-				//onWindowResize();
-
 				renderScene.uniforms[ "tDiffuse" ].value = composerScene.renderTarget2;
 
 				window.addEventListener( 'resize', onWindowResize, false );
@@ -341,7 +343,9 @@
 					shininess: 20,
 					map: new THREE.TextureLoader().load( "obj/leeperrysmith/Map-COL.jpg" ),
 					normalMap: new THREE.TextureLoader().load("obj/leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg" ),
-					normalScale: new THREE.Vector2( 0.75, 0.75 )
+					normalScale: new THREE.Vector2( 0.75, 0.75 ),
+					stencilTest: true,
+					stencilWrite: true
 
 				} );
 

+ 4 - 2
examples/webgl_postprocessing_masking.html

@@ -47,10 +47,12 @@
 				var scene1 = new THREE.Scene();
 				var scene2 = new THREE.Scene();
 
-				box = new THREE.Mesh( new THREE.BoxGeometry( 4, 4, 4 ) );
+				var maskMaterial = new THREE.MeshBasicMaterial( { stencilTest: true, stencilWrite: true, colorWrite: false, depthWrite: false } );
+
+				box = new THREE.Mesh( new THREE.BoxGeometry( 4, 4, 4 ), maskMaterial );
 				scene1.add( box );
 
-				torus = new THREE.Mesh( new THREE.TorusGeometry( 3, 1, 16, 32 ) );
+				torus = new THREE.Mesh( new THREE.TorusGeometry( 3, 1, 16, 32 ), maskMaterial );
 				scene2.add( torus );
 
 				renderer = new THREE.WebGLRenderer( { antialias: false } );

+ 2 - 0
src/loaders/Loader.js

@@ -229,6 +229,8 @@ THREE.Loader.prototype = {
 						break;
 					case 'depthTest':
 					case 'depthWrite':
+					case 'stencilTest':
+					case 'stencilWrite':
 					case 'colorWrite':
 					case 'opacity':
 					case 'reflectivity':

+ 2 - 0
src/loaders/MaterialLoader.js

@@ -70,6 +70,8 @@ THREE.MaterialLoader.prototype = {
 		if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
 		if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
 		if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
+		if ( json.stencilTest !== undefined ) material.stencilTest = json.stencilTest;
+		if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;
 		if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
 		if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
 		if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;

+ 6 - 0
src/materials/Material.js

@@ -30,6 +30,9 @@ THREE.Material = function () {
 	this.depthTest = true;
 	this.depthWrite = true;
 
+	this.stencilTest = false;
+	this.stencilWrite = false;
+
 	this.colorWrite = true;
 
 	this.precision = null; // override the renderer's default precision for this material
@@ -257,6 +260,9 @@ THREE.Material.prototype = {
 		this.depthTest = source.depthTest;
 		this.depthWrite = source.depthWrite;
 
+		this.stencilTest = source.stencilTest;
+		this.stencilWrite = source.stencilWrite;
+
 		this.colorWrite = source.colorWrite;
 
 		this.precision = source.precision;

+ 5 - 1
src/renderers/WebGLRenderer.js

@@ -1196,10 +1196,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
-		// Ensure depth buffer writing is enabled so it can be cleared on next render
+		// Ensure buffer writing is enabled so they can be cleared on next render
 
 		state.setDepthTest( true );
 		state.setDepthWrite( true );
+		state.setStencilTest( true );
+		state.setStencilWrite( true );
 		state.setColorWrite( true );
 
 		// _gl.finish();
@@ -1562,6 +1564,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 		state.setDepthFunc( material.depthFunc );
 		state.setDepthTest( material.depthTest );
 		state.setDepthWrite( material.depthWrite );
+		state.setStencilTest( material.stencilTest );
+		state.setStencilWrite( material.stencilWrite );
 		state.setColorWrite( material.colorWrite );
 		state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );