Browse Source

BatchedMesh: Enable per-instance opacity (#32725)

Co-authored-by: Garrett Johnson <garrett.kjohnson@gmail.com>
Raoul v. R. 1 month ago
parent
commit
9d91428d24

BIN
examples/screenshots/webgl_mesh_batch.jpg


+ 72 - 24
examples/webgl_mesh_batch.html

@@ -39,7 +39,7 @@
 
 		let stats, gui, guiStatsEl;
 		let camera, controls, scene, renderer;
-		let geometries, mesh, material;
+		let geometries, mesh;
 		const ids = [];
 		const matrix = new THREE.Matrix4();
 
@@ -64,9 +64,9 @@
 			count: 256,
 			dynamic: 16,
 
+			transparent: true,
 			sortObjects: true,
 			perObjectFrustumCulled: true,
-			opacity: 1,
 			useCustomSort: true,
 		};
 
@@ -103,25 +103,51 @@
 
 		}
 
-		function initGeometries() {
+		function randomizeColor( color ) {
 
-			geometries = [
-				new THREE.ConeGeometry( 1.0, 2.0 ),
-				new THREE.BoxGeometry( 2.0, 2.0, 2.0 ),
-				new THREE.SphereGeometry( 1.0, 16, 8 ),
-			];
+			return color.setHSL( Math.random() * 0.5, 0.6, 0.5 );
 
 		}
 
-		function createMaterial() {
+		function randomizeAlpha() {
+
+			// make ~20% of all objects transparent
+			return Math.random() > 0.8 ? 0.5 : 1.0;
+
+		}
+
+		function initGeometries() {
 
-			if ( ! material ) {
+			const cone = new THREE.ConeGeometry( 1.0, 2.0 );
+			const box = new THREE.BoxGeometry( 2.0, 2.0, 2.0 );
+			const sphere = new THREE.SphereGeometry( 1.0, 16, 8 );
 
-				material = new THREE.MeshNormalMaterial();
+			geometries = [ cone, box, sphere ];
+
+			for ( const geometry of geometries ) {
+
+				// add vertex colors for testing
+				const count = geometry.getAttribute( 'position' ).count;
+				const attribute = new THREE.BufferAttribute( new Float32Array( count * 3 ), 3 );
+				geometry.setAttribute( 'color', attribute );
+
+				for ( let i = 0, l = attribute.array.length; i < l; ++ i ) {
+
+					attribute.array[ i ] = 1.0;
+
+				}
 
 			}
 
-			return material;
+		}
+
+		function createMaterial() {
+
+			return new THREE.MeshPhongMaterial( {
+				vertexColors: true,
+				transparent: api.transparent,
+				depthWrite: ! api.transparent
+			} );
 
 		}
 
@@ -129,6 +155,16 @@
 
 			if ( mesh ) {
 
+				mesh.traverse( node => {
+
+					if ( node instanceof THREE.Mesh ) {
+
+						node.material.dispose();
+
+					}
+
+				} );
+
 				mesh.parent.remove( mesh );
 
 				if ( mesh.dispose ) {
@@ -160,10 +196,13 @@
 		function initRegularMesh() {
 
 			mesh = new THREE.Group();
-			const material = createMaterial();
 
 			for ( let i = 0; i < api.count; i ++ ) {
 
+				const material = createMaterial();
+				randomizeColor( material.color );
+				material.opacity = randomizeAlpha();
+
 				const child = new THREE.Mesh( geometries[ i % geometries.length ], material );
 				randomizeMatrix( child.matrix );
 				child.matrix.decompose( child.position, child.quaternion, child.scale );
@@ -184,6 +223,8 @@
 
 			const euler = new THREE.Euler();
 			const matrix = new THREE.Matrix4();
+			const color = new THREE.Color();
+			const colorWithAlpha = new THREE.Vector4();
 			mesh = new THREE.BatchedMesh( geometryCount, vertexCount, indexCount, createMaterial() );
 			mesh.userData.rotationSpeeds = [];
 
@@ -200,8 +241,12 @@
 
 			for ( let i = 0; i < api.count; i ++ ) {
 
+				randomizeColor( color );
+				colorWithAlpha.set( color.r, color.g, color.b, randomizeAlpha() );
+
 				const id = mesh.addInstance( geometryIds[ i % geometryIds.length ] );
 				mesh.setMatrixAt( id, randomizeMatrix( matrix ) );
+				mesh.setColorAt( id, colorWithAlpha );
 
 				const rotationMatrix = new THREE.Matrix4();
 				rotationMatrix.makeRotationFromEuler( randomizeRotationSpeed( euler ) );
@@ -244,6 +289,13 @@
 			controls.autoRotate = true;
 			controls.autoRotateSpeed = 1.0;
 
+			// light
+
+			const ambientLight = new THREE.AmbientLight( 0xffffff, 2 );
+			const directionalLight = new THREE.DirectionalLight( 0xffffff, 2 );
+			directionalLight.position.set( 1, 1, 1 );
+			scene.add( directionalLight, ambientLight );
+
 			// stats
 
 			stats = new Stats();
@@ -255,24 +307,20 @@
 			gui.add( api, 'count', 1, MAX_GEOMETRY_COUNT ).step( 1 ).onChange( initMesh );
 			gui.add( api, 'dynamic', 0, MAX_GEOMETRY_COUNT ).step( 1 );
 			gui.add( api, 'method', Method ).onChange( initMesh );
-			gui.add( api, 'opacity', 0, 1 ).onChange( v => {
-
-				if ( v < 1 ) {
 
-					material.transparent = true;
-					material.depthWrite = false;
+			gui.add( api, 'transparent' ).onChange( v => mesh.traverse( node => {
 
-				} else {
+				if ( node instanceof THREE.Mesh ) {
 
-					material.transparent = false;
-					material.depthWrite = true;
+					const material = node.material;
+					material.transparent = v;
+					material.depthWrite = ! v;
+					material.needsUpdate = true;
 
 				}
 
-				material.opacity = v;
-				material.needsUpdate = true;
+			} ) );
 
-			} );
 			gui.add( api, 'sortObjects' );
 			gui.add( api, 'perObjectFrustumCulled' );
 			gui.add( api, 'useCustomSort' );

+ 3 - 3
src/objects/BatchedMesh.js

@@ -1103,7 +1103,7 @@ class BatchedMesh extends Mesh {
 	 * Sets the given color to the defined instance.
 	 *
 	 * @param {number} instanceId - The ID of an instance to set the color of.
-	 * @param {Color} color - The color to set the instance to.
+	 * @param {Color|Vector4} color - The color to set the instance to. Use a `Vector4` to also define alpha.
 	 * @return {BatchedMesh} A reference to this batched mesh.
 	 */
 	setColorAt( instanceId, color ) {
@@ -1127,8 +1127,8 @@ class BatchedMesh extends Mesh {
 	 * Returns the color of the defined instance.
 	 *
 	 * @param {number} instanceId - The ID of an instance to get the color of.
-	 * @param {Color} color - The target object that is used to store the method's result.
-	 * @return {Color} The instance's color.
+	 * @param {Color|Vector4} color - The target object that is used to store the method's result.
+	 * @return {Color|Vector4} The instance's color.  Use a `Vector4` to also retrieve alpha.
 	 */
 	getColorAt( instanceId, color ) {
 

+ 2 - 2
src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js

@@ -35,13 +35,13 @@ export default /* glsl */`
 #ifdef USE_BATCHING_COLOR
 
 	uniform sampler2D batchingColorTexture;
-	vec3 getBatchingColor( const in float i ) {
+	vec4 getBatchingColor( const in float i ) {
 
 		int size = textureSize( batchingColorTexture, 0 ).x;
 		int j = int( i );
 		int x = j % size;
 		int y = j / size;
-		return texelFetch( batchingColorTexture, ivec2( x, y ), 0 ).rgb;
+		return texelFetch( batchingColorTexture, ivec2( x, y ), 0 );
 
 	}
 

+ 1 - 5
src/renderers/shaders/ShaderChunk/color_fragment.glsl.js

@@ -1,11 +1,7 @@
 export default /* glsl */`
-#if defined( USE_COLOR_ALPHA )
+#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA )
 
 	diffuseColor *= vColor;
 
-#elif defined( USE_COLOR )
-
-	diffuseColor.rgb *= vColor;
-
 #endif
 `;

+ 1 - 5
src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl.js

@@ -1,11 +1,7 @@
 export default /* glsl */`
-#if defined( USE_COLOR_ALPHA )
+#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA )
 
 	varying vec4 vColor;
 
-#elif defined( USE_COLOR )
-
-	varying vec3 vColor;
-
 #endif
 `;

+ 1 - 5
src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl.js

@@ -1,11 +1,7 @@
 export default /* glsl */`
-#if defined( USE_COLOR_ALPHA )
+#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )
 
 	varying vec4 vColor;
 
-#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )
-
-	varying vec3 vColor;
-
 #endif
 `;

+ 8 - 10
src/renderers/shaders/ShaderChunk/color_vertex.glsl.js

@@ -1,31 +1,29 @@
 export default /* glsl */`
-#if defined( USE_COLOR_ALPHA )
+#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )
 
 	vColor = vec4( 1.0 );
 
-#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )
-
-	vColor = vec3( 1.0 );
-
 #endif
 
-#ifdef USE_COLOR
+#ifdef USE_COLOR_ALPHA
 
 	vColor *= color;
 
+#elif defined( USE_COLOR )
+
+	vColor.rgb *= color;
+
 #endif
 
 #ifdef USE_INSTANCING_COLOR
 
-	vColor.xyz *= instanceColor.xyz;
+	vColor.rgb *= instanceColor.rgb;
 
 #endif
 
 #ifdef USE_BATCHING_COLOR
 
-	vec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) );
-
-	vColor.xyz *= batchingColor.xyz;
+	vColor *= getBatchingColor( getIndirectIndex( gl_DrawID ) );
 
 #endif
 `;

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

@@ -732,8 +732,8 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
 
 			parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
-			parameters.vertexColors || parameters.instancingColor || parameters.batchingColor ? '#define USE_COLOR' : '',
-			parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
+			parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
+			parameters.vertexAlphas || parameters.batchingColor ? '#define USE_COLOR_ALPHA' : '',
 			parameters.vertexUv1s ? '#define USE_UV1' : '',
 			parameters.vertexUv2s ? '#define USE_UV2' : '',
 			parameters.vertexUv3s ? '#define USE_UV3' : '',

粤ICP备19079148号