Jelajahi Sumber

Examples: Refactor blending examples. (#23246)

* Examples: Refactor blending examples.

* WebGLState: Update subtractive blending equation.
Michael Herzog 3 tahun lalu
induk
melakukan
da14c33181

TEMPAT SAMPAH
examples/screenshots/webgl_materials_blending.jpg


TEMPAT SAMPAH
examples/screenshots/webgl_materials_blending_custom.jpg


+ 7 - 20
examples/webgl_materials_blending.html

@@ -45,9 +45,9 @@
 
 				// BACKGROUND
 
-				const canvasBackground = document.createElement( 'canvas' );
-				const ctx = canvasBackground.getContext( '2d' );
-				canvasBackground.width = canvasBackground.height = 128;
+				const canvas = document.createElement( 'canvas' );
+				const ctx = canvas.getContext( '2d' );
+				canvas.width = canvas.height = 128;
 				ctx.fillStyle = '#ddd';
 				ctx.fillRect( 0, 0, 128, 128 );
 				ctx.fillStyle = '#555';
@@ -59,21 +59,11 @@
 				ctx.fillStyle = '#777';
 				ctx.fillRect( 96, 96, 32, 32 );
 
-				mapBg = new THREE.CanvasTexture( canvasBackground );
-				mapBg.wrapS = mapBg.wrapT = THREE.RepeatWrapping;
-				mapBg.repeat.set( 128, 64 );
-
-				/*
-				let mapBg = textureLoader.load( 'textures/disturb.jpg' );
+				mapBg = new THREE.CanvasTexture( canvas );
 				mapBg.wrapS = mapBg.wrapT = THREE.RepeatWrapping;
-				mapBg.repeat.set( 8, 4 );
-				*/
+				mapBg.repeat.set( 64, 32 );
 
-				const materialBg = new THREE.MeshBasicMaterial( { map: mapBg } );
-
-				const meshBg = new THREE.Mesh( new THREE.PlaneGeometry( 4000, 2000 ), materialBg );
-				meshBg.position.set( 0, 0, - 1 );
-				scene.add( meshBg );
+				scene.background = mapBg;
 
 				// OBJECTS
 
@@ -125,12 +115,9 @@
 
 				}
 
-				const canvas = document.createElement( 'canvas' );
-				const context = canvas.getContext( 'webgl2', { alpha: false } ); // TODO Remove workaround
-
 				// RENDERER
 
-				renderer = new THREE.WebGLRenderer( { canvas: canvas, context: context } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				document.body.appendChild( renderer.domElement );

+ 50 - 278
examples/webgl_materials_blending_custom.html

@@ -4,78 +4,10 @@
 		<title>three.js webgl - materials - custom blending</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<style>
-			body {
-				margin: 0px;
-				background-color: #111;
-				overflow: hidden;
-				font-family: arial;
-			}
-
-			.menu { color: #fff; font-weight: bold; font-size: 12px; z-index: 100; width: 75px; position: absolute; top: 0px; padding: 16px; }
-			.menu img, .menu canvas { width: 75px; margin: 10px 0 }
-
-			#images { background: rgba(0,0,0,0); left: 0px; }
-			#backgrounds { background: rgba(0,0,0,0.0); left: 107px; }
-			#labels { background: rgba(0,0,0,0.75); left: 214px; width: 100px }
-
-			.lbl { color: #fff; z-index: 150; float:left; padding: 0.25em; width: 75px; display: block  }
-			#lbl_dst { background:#800; }
-			#lbl_src { background:green; }
-
-			.btn { background: darkorange; width: 100px; cursor: pointer }
-
-			#btn_sub { background: transparent }
-			#btn_rsub { background: transparent }
-			#btn_min { background: transparent }
-			#btn_max { background: transparent }
-
-			#btn_pre { background: transparent }
-
-			#btn_max, #btn_nopre { margin-bottom: 2em }
-		</style>
+		<link type="text/css" rel="stylesheet" href="main.css">
 	</head>
 	<body>
 
-		<div id="images" class="menu">
-			Foreground
-			<a id="img_0" href="#"><img src="textures/disturb.jpg" /></a>
-			<a id="img_1" href="#"><img src="textures/sprite0.jpg" /></a>
-			<a id="img_2" href="#"><img src="textures/sprite0.png" /></a>
-			<a id="img_3" href="#"><img src="textures/lensflare/lensflare0.png" /></a>
-			<a id="img_4" href="#"><img src="textures/lensflare/lensflare0_alpha.png" /></a>
-			<a id="img_5" href="#"><img src="textures/sprites/ball.png" /></a>
-			<a id="img_6" href="#"><img src="textures/sprites/snowflake7_alpha.png" /></a>
-		</div>
-
-		<div id="backgrounds" class="menu">
-			Background
-			<a id="bg_0" href="#"><img src="textures/disturb.jpg" /></a>
-			<a id="bg_1" href="#"></a>
-			<a id="bg_2" href="#"></a>
-			<a id="bg_3" href="#"><img src="textures/crate.gif" /></a>
-			<a id="bg_4" href="#"><img src="textures/lava/lavatile.jpg" /></a>
-			<a id="bg_5" href="#"><img src="textures/water.jpg" /></a>
-			<a id="bg_6" href="#"><img src="textures/lava/cloud.png" /></a>
-		</div>
-
-		<div id="labels" class="menu">
-			Equation<br/><br/>
-			<div class="lbl btn" id="btn_add">Add</div>
-			<div class="lbl btn" id="btn_sub">Subtract</div>
-			<div class="lbl btn" id="btn_rsub">ReverseSubtract</div>
-			<div class="lbl btn" id="btn_min">Min</div>
-			<div class="lbl btn" id="btn_max">Max</div>
-
-			Premultiply alpha<br/><br/>
-			<div class="lbl btn" id="btn_pre">On</div>
-			<div class="lbl btn" id="btn_nopre">Off</div>
-
-			Labels<br/><br/>
-			<div class="lbl" id="lbl_src">Source</div>
-			<div class="lbl" id="lbl_dst">Destination</div>
-		</div>
-
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
 		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
@@ -92,16 +24,18 @@
 
 			import * as THREE from 'three';
 
+			import { GUI } from './jsm/libs/lil-gui.module.min.js';
+
 			let camera, scene, renderer;
 
-			let materialBg;
+			let mapBg;
 			const materials = [];
 
-			const mapsPre = [];
-			const mapsNoPre = [];
+			const params = {
+				blendEquation: THREE.AddEquation
+			};
 
-			let currentMaps = mapsNoPre;
-			let currentIndex = 4;
+			const equations = { Add: THREE.AddEquation, Subtract: THREE.SubtractEquation, ReverseSubtract: THREE.ReverseSubtractEquation, Min: THREE.MinEquation, Max: THREE.MaxEquation };
 
 			init();
 			animate();
@@ -117,103 +51,30 @@
 
 				scene = new THREE.Scene();
 
-				// TEXTURE LOADER
-
-				const textureLoader = new THREE.TextureLoader();
-
-				// BACKGROUND IMAGES
-
-				const canvas1 = document.createElement( 'canvas' );
-				const ctx1 = canvas1.getContext( '2d' );
-				canvas1.width = canvas1.height = 128;
-				ctx1.fillStyle = '#eee';
-				ctx1.fillRect( 0, 0, 128, 128 );
-				ctx1.fillStyle = '#999';
-				ctx1.fillRect( 0, 0, 64, 64 );
-				ctx1.fillStyle = '#aaa';
-				ctx1.fillRect( 32, 32, 32, 32 );
-				ctx1.fillStyle = '#999';
-				ctx1.fillRect( 64, 64, 64, 64 );
-				ctx1.fillStyle = '#bbb';
-				ctx1.fillRect( 96, 96, 32, 32 );
-
-				document.getElementById( 'bg_1' ).appendChild( canvas1 );
-
-				const canvas2 = document.createElement( 'canvas' );
-				const ctx2 = canvas2.getContext( '2d' );
-				canvas2.width = canvas2.height = 128;
-				ctx2.fillStyle = '#444';
-				ctx2.fillRect( 0, 0, 128, 128 );
-				ctx2.fillStyle = '#000';
-				ctx2.fillRect( 0, 0, 64, 64 );
-				ctx2.fillStyle = '#111';
-				ctx2.fillRect( 32, 32, 32, 32 );
-				ctx2.fillStyle = '#000';
-				ctx2.fillRect( 64, 64, 64, 64 );
-				ctx2.fillStyle = '#222';
-				ctx2.fillRect( 96, 96, 32, 32 );
-
-				document.getElementById( 'bg_2' ).appendChild( canvas2 );
-
-				const mapBg0 = new THREE.CanvasTexture( canvas1 );
-				mapBg0.wrapS = mapBg0.wrapT = THREE.RepeatWrapping;
-				mapBg0.repeat.set( 128, 64 );
-
-				const mapBg1 = new THREE.CanvasTexture( canvas2 );
-				mapBg1.wrapS = mapBg1.wrapT = THREE.RepeatWrapping;
-				mapBg1.repeat.set( 128, 64 );
-
-				const mapBg2 = textureLoader.load( 'textures/disturb.jpg' );
-				mapBg2.wrapS = mapBg2.wrapT = THREE.RepeatWrapping;
-				mapBg2.repeat.set( 8, 4 );
-
-				const mapBg3 = textureLoader.load( 'textures/crate.gif' );
-				mapBg3.wrapS = mapBg3.wrapT = THREE.RepeatWrapping;
-				mapBg3.repeat.set( 32, 16 );
-
-				const mapBg4 = textureLoader.load( 'textures/lava/lavatile.jpg' );
-				mapBg4.wrapS = mapBg4.wrapT = THREE.RepeatWrapping;
-				mapBg4.repeat.set( 8, 4 );
-
-				const mapBg5 = textureLoader.load( 'textures/water.jpg' );
-				mapBg5.wrapS = mapBg5.wrapT = THREE.RepeatWrapping;
-				mapBg5.repeat.set( 8, 4 );
-
-				const mapBg6 = textureLoader.load( 'textures/lava/cloud.png' );
-				mapBg6.wrapS = mapBg6.wrapT = THREE.RepeatWrapping;
-				mapBg6.repeat.set( 2, 1 );
-
 				// BACKGROUND
 
-				materialBg = new THREE.MeshBasicMaterial( { map: mapBg1 } );
-
-				const meshBg = new THREE.Mesh( new THREE.PlaneGeometry( 4000, 2000 ), materialBg );
-				meshBg.position.set( 0, 0, - 1 );
-				scene.add( meshBg );
-
-				// FOREGROUND IMAGES
-
-				const images = [ 'textures/disturb.jpg',
-					'textures/sprite0.jpg',
-					'textures/sprite0.png',
-					'textures/lensflare/lensflare0.png',
-					'textures/lensflare/lensflare0_alpha.png',
-					'textures/sprites/ball.png',
-					'textures/sprites/snowflake7_alpha.png' ];
-
-				for ( let i = 0; i < images.length; i ++ ) {
-
-					const map = textureLoader.load( images[ i ] );
-					mapsNoPre.push( map );
-
-					const mapPre = textureLoader.load( images[ i ] );
-					mapPre.premultiplyAlpha = true;
-					mapPre.needsUpdate = true;
-					mapsPre.push( mapPre );
-
-				}
+				const canvas = document.createElement( 'canvas' );
+				const ctx = canvas.getContext( '2d' );
+				canvas.width = canvas.height = 128;
+				ctx.fillStyle = '#ddd';
+				ctx.fillRect( 0, 0, 128, 128 );
+				ctx.fillStyle = '#555';
+				ctx.fillRect( 0, 0, 64, 64 );
+				ctx.fillStyle = '#999';
+				ctx.fillRect( 32, 32, 32, 32 );
+				ctx.fillStyle = '#555';
+				ctx.fillRect( 64, 64, 64, 64 );
+				ctx.fillStyle = '#777';
+				ctx.fillRect( 96, 96, 32, 32 );
+
+				mapBg = new THREE.CanvasTexture( canvas );
+				mapBg.wrapS = mapBg.wrapT = THREE.RepeatWrapping;
+				mapBg.repeat.set( 64, 32 );
+
+				scene.background = mapBg;
 
 				// FOREGROUND OBJECTS
+
 				const src = [
 					{ name: 'Zero', constant: THREE.ZeroFactor },
 					{ name: 'One', constant: THREE.OneFactor },
@@ -244,6 +105,8 @@
 				const geo1 = new THREE.PlaneGeometry( 100, 100 );
 				const geo2 = new THREE.PlaneGeometry( 100, 25 );
 
+				const texture = new THREE.TextureLoader().load( 'textures/lensflare/lensflare0_alpha.png' );
+
 				for ( let i = 0; i < dst.length; i ++ ) {
 
 					const blendDst = dst[ i ];
@@ -252,7 +115,7 @@
 
 						const blendSrc = src[ j ];
 
-						const material = new THREE.MeshBasicMaterial( { map: currentMaps[ currentIndex ] } );
+						const material = new THREE.MeshBasicMaterial( { map: texture } );
 						material.transparent = true;
 
 						material.blending = THREE.CustomBlending;
@@ -310,123 +173,22 @@
 
 				// RENDERER
 
-				const canvas = document.createElement( 'canvas' );
-				const context = canvas.getContext( 'webgl2', { alpha: false } ); // TODO Remove workaround
-
-				renderer = new THREE.WebGLRenderer( { canvas: canvas, context: context } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				renderer.domElement.style.position = 'absolute';
-				renderer.domElement.style.left = '215px';
-
 				document.body.appendChild( renderer.domElement );
 
 				// EVENTS
 
 				window.addEventListener( 'resize', onWindowResize );
 
-				addImgHandler( 'img_0', 0 );
-				addImgHandler( 'img_1', 1 );
-				addImgHandler( 'img_2', 2 );
-				addImgHandler( 'img_3', 3 );
-				addImgHandler( 'img_4', 4 );
-				addImgHandler( 'img_5', 5 );
-				addImgHandler( 'img_6', 6 );
-
-				addBgHandler( 'bg_0', mapBg2 );
-				addBgHandler( 'bg_1', mapBg0 );
-				addBgHandler( 'bg_2', mapBg1 );
-				addBgHandler( 'bg_3', mapBg3 );
-				addBgHandler( 'bg_4', mapBg4 );
-				addBgHandler( 'bg_5', mapBg5 );
-				addBgHandler( 'bg_6', mapBg6 );
-
-				addEqHandler( 'btn_add', THREE.AddEquation );
-				addEqHandler( 'btn_sub', THREE.SubtractEquation );
-				addEqHandler( 'btn_rsub', THREE.ReverseSubtractEquation );
-				addEqHandler( 'btn_min', THREE.MinEquation );
-				addEqHandler( 'btn_max', THREE.MaxEquation );
-
-				addPreHandler( 'btn_pre', mapsPre );
-				addPreHandler( 'btn_nopre', mapsNoPre );
-
-			}
-
-			//
-
-			function addImgHandler( id, index ) {
-
-				const el = document.getElementById( id );
-
-				el.addEventListener( 'click', function () {
-
-					for ( let i = 0; i < materials.length; i ++ ) {
-
-						materials[ i ].map = currentMaps[ index ];
-
-					}
+				// GUI
 
-					currentIndex = index;
+				//
+				const gui = new GUI( { width: 300 } );
 
-				} );
-
-			}
-
-			function addEqHandler( id, eq ) {
-
-				const el = document.getElementById( id );
-
-				el.addEventListener( 'click', function () {
-
-					for ( let i = 0; i < materials.length; i ++ ) {
-
-						materials[ i ].blendEquation = eq;
-
-					}
-
-					document.getElementById( 'btn_add' ).style.backgroundColor = 'transparent';
-					document.getElementById( 'btn_sub' ).style.backgroundColor = 'transparent';
-					document.getElementById( 'btn_rsub' ).style.backgroundColor = 'transparent';
-					document.getElementById( 'btn_min' ).style.backgroundColor = 'transparent';
-					document.getElementById( 'btn_max' ).style.backgroundColor = 'transparent';
-
-					el.style.backgroundColor = 'darkorange';
-
-				} );
-
-			}
-
-			function addBgHandler( id, map ) {
-
-				const el = document.getElementById( id );
-				el.addEventListener( 'click', function () {
-
-					materialBg.map = map;
-
-				}	);
-
-			}
-
-			function addPreHandler( id, marray ) {
-
-				const el = document.getElementById( id );
-				el.addEventListener( 'click', function () {
-
-					currentMaps = marray;
-
-					for ( let i = 0; i < materials.length; i ++ ) {
-
-						materials[ i ].map = currentMaps[ currentIndex ];
-
-					}
-
-					document.getElementById( 'btn_pre' ).style.backgroundColor = 'transparent';
-					document.getElementById( 'btn_nopre' ).style.backgroundColor = 'transparent';
-
-					el.style.backgroundColor = 'darkorange';
-
-				} );
+				gui.add( params, 'blendEquation', equations ).onChange( updateBlendEquation );
+				gui.open();
 
 			}
 
@@ -464,15 +226,25 @@
 
 			}
 
+			function updateBlendEquation( value ) {
+
+				for ( const material of materials ) {
+
+					material.blendEquation = value;
+
+				}
+
+			}
+
 			function animate() {
 
 				requestAnimationFrame( animate );
 
 				const time = Date.now() * 0.00025;
-				const ox = ( time * - 0.01 * materialBg.map.repeat.x ) % 1;
-				const oy = ( time * - 0.01 * materialBg.map.repeat.y ) % 1;
+				const ox = ( time * - 0.01 * mapBg.repeat.x ) % 1;
+				const oy = ( time * - 0.01 * mapBg.repeat.y ) % 1;
 
-				materialBg.map.offset.set( ox, oy );
+				mapBg.offset.set( ox, oy );
 
 				renderer.render( scene, camera );
 

+ 2 - 2
src/renderers/webgl/WebGLState.js

@@ -641,7 +641,7 @@ function WebGLState( gl, extensions, capabilities ) {
 							break;
 
 						case SubtractiveBlending:
-							gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );
+							gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
 							break;
 
 						case MultiplyBlending:
@@ -667,7 +667,7 @@ function WebGLState( gl, extensions, capabilities ) {
 							break;
 
 						case SubtractiveBlending:
-							gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );
+							gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
 							break;
 
 						case MultiplyBlending: