Browse Source

WebGLRenderer: Render transmissiveObjects in two passes. (#25502)

* WebGLRenderer: Render transmissiveObjects in two passes.

* Updated transmission screenshots.

* WebGLRenderer: Add forceSinglePass toggle for double pass transmission.

* WebGLRenderer: Clean up.

* WebGLRenderer: Update material in transmission pass.

* WebGLRenderer: Added commented out debug code.

* Examples: Updated webxr_vr_sandbox.

* WebGLRenderer: Only render DoubleSide transmissive objects in two passes.

* Updated examples.
mrdoob 2 years ago
parent
commit
7b6c0cbde8

BIN
examples/screenshots/webgl_loader_gltf_iridescence.jpg


BIN
examples/screenshots/webgl_loader_gltf_transmission.jpg


BIN
examples/screenshots/webgl_nodes_loader_gltf_transmission.jpg


BIN
examples/screenshots/webxr_vr_sandbox.jpg


+ 3 - 3
examples/webxr_vr_sandbox.html

@@ -75,7 +75,7 @@
 
 
 				const torusGeometry = new THREE.TorusKnotGeometry( ...Object.values( parameters ) );
 				const torusGeometry = new THREE.TorusKnotGeometry( ...Object.values( parameters ) );
 				const torusMaterial = new THREE.MeshPhysicalMaterial( {
 				const torusMaterial = new THREE.MeshPhysicalMaterial( {
-					transmission: 1.0, roughness: 0, metalness: 0.25, thickness: 0.5
+					transmission: 1.0, roughness: 0, metalness: 0.25, thickness: 0.5, side: THREE.DoubleSide
 				} );
 				} );
 				const torus = new THREE.Mesh( torusGeometry, torusMaterial );
 				const torus = new THREE.Mesh( torusGeometry, torusMaterial );
 				torus.name = 'torus';
 				torus.name = 'torus';
@@ -232,8 +232,8 @@
 
 
 				const time = performance.now() * 0.0002;
 				const time = performance.now() * 0.0002;
 				const torus = scene.getObjectByName( 'torus' );
 				const torus = scene.getObjectByName( 'torus' );
-				torus.rotation.x = time * 2;
-				torus.rotation.y = time * 5;
+				torus.rotation.x = time * 0.4;
+				torus.rotation.y = time;
 
 
 				renderer.render( scene, camera );
 				renderer.render( scene, camera );
 				stats.update();
 				stats.update();

+ 52 - 6
src/renderers/WebGLRenderer.js

@@ -1210,7 +1210,7 @@ function WebGLRenderer( parameters = {} ) {
 
 
 		if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );
 		if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );
 
 
-		if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, scene, camera );
+		if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera );
 
 
 		if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );
 		if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );
 
 
@@ -1228,12 +1228,12 @@ function WebGLRenderer( parameters = {} ) {
 
 
 	}
 	}
 
 
-	function renderTransmissionPass( opaqueObjects, scene, camera ) {
-
-		const isWebGL2 = capabilities.isWebGL2;
+	function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {
 
 
 		if ( _transmissionRenderTarget === null ) {
 		if ( _transmissionRenderTarget === null ) {
 
 
+			const isWebGL2 = capabilities.isWebGL2;
+
 			_transmissionRenderTarget = new WebGLRenderTarget( 1024, 1024, {
 			_transmissionRenderTarget = new WebGLRenderTarget( 1024, 1024, {
 				generateMipmaps: true,
 				generateMipmaps: true,
 				type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType,
 				type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType,
@@ -1241,6 +1241,16 @@ function WebGLRenderer( parameters = {} ) {
 				samples: ( isWebGL2 && _antialias === true ) ? 4 : 0
 				samples: ( isWebGL2 && _antialias === true ) ? 4 : 0
 			} );
 			} );
 
 
+			// debug
+
+			/*
+			const geometry = new PlaneGeometry();
+			const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );
+
+			const mesh = new Mesh( geometry, material );
+			scene.add( mesh );
+			*/
+
 		}
 		}
 
 
 		//
 		//
@@ -1256,13 +1266,49 @@ function WebGLRenderer( parameters = {} ) {
 
 
 		renderObjects( opaqueObjects, scene, camera );
 		renderObjects( opaqueObjects, scene, camera );
 
 
-		_this.toneMapping = currentToneMapping;
-
 		textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
 		textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
 		textures.updateRenderTargetMipmap( _transmissionRenderTarget );
 		textures.updateRenderTargetMipmap( _transmissionRenderTarget );
 
 
+		let renderTargetNeedsUpdate = false;
+
+		for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) {
+
+			const renderItem = transmissiveObjects[ i ];
+
+			const object = renderItem.object;
+			const geometry = renderItem.geometry;
+			const material = renderItem.material;
+			const group = renderItem.group;
+
+			if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {
+
+				const currentSide = material.side;
+
+				material.side = BackSide;
+				material.needsUpdate = true;
+
+				renderObject( object, scene, camera, geometry, material, group );
+
+				material.side = currentSide;
+				material.needsUpdate = true;
+
+				renderTargetNeedsUpdate = true;
+
+			}
+
+		}
+
+		if ( renderTargetNeedsUpdate === true ) {
+
+			textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
+			textures.updateRenderTargetMipmap( _transmissionRenderTarget );
+
+		}
+
 		_this.setRenderTarget( currentRenderTarget );
 		_this.setRenderTarget( currentRenderTarget );
 
 
+		_this.toneMapping = currentToneMapping;
+
 	}
 	}
 
 
 	function renderObjects( renderList, scene, camera ) {
 	function renderObjects( renderList, scene, camera ) {