Browse Source

WebGPURenderer: Reuse Meshes in PMREMGenerator and pmremVersion logic (#27988)

* PMREMGenerator: Reuse Meshes

* TextureNode: Introduce `referenceNode`

* PMREMNode: Added pmremVersion logic

* update screenshot

* fix webgl backend

* cleanup example

* fix webgl pmrem node

* PMREMGenerator: Reuse PerspectiveCamera
sunag 1 year ago
parent
commit
b5d53e5dc4

+ 23 - 7
examples/jsm/nodes/pmrem/PMREMNode.js

@@ -4,7 +4,8 @@ import { texture } from '../accessors/TextureNode.js';
 import { textureCubeUV } from './PMREMUtils.js';
 import { uniform } from '../core/UniformNode.js';
 import { NodeUpdateType } from '../core/constants.js';
-import { nodeProxy } from '../shadernode/ShaderNode.js';
+import { nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
+import { WebGLCoordinateSystem } from 'three';
 
 let _generator = null;
 
@@ -26,7 +27,9 @@ function _getPMREMFromTexture( texture ) {
 
 	let cacheTexture = _cache.get( texture );
 
-	if ( cacheTexture === undefined ) {
+	const pmremVersion = cacheTexture !== undefined ? cacheTexture.pmremVersion : - 1;
+
+	if ( pmremVersion !== texture.pmremVersion ) {
 
 		if ( texture.isCubeTexture ) {
 
@@ -36,7 +39,7 @@ function _getPMREMFromTexture( texture ) {
 
 			}
 
-			cacheTexture = _generator.fromCubemap( texture );
+			cacheTexture = _generator.fromCubemap( texture, cacheTexture );
 
 		} else {
 
@@ -46,10 +49,12 @@ function _getPMREMFromTexture( texture ) {
 
 			}
 
-			cacheTexture = _generator.fromEquirectangular( texture );
+			cacheTexture = _generator.fromEquirectangular( texture, cacheTexture );
 
 		}
 
+		cacheTexture.pmremVersion = texture.pmremVersion;
+
 		_cache.set( texture, cacheTexture );
 
 	}
@@ -104,13 +109,14 @@ class PMREMNode extends TempNode {
 
 	}
 
-	updateBefore( frame ) {
+	updateBefore() {
 
 		let pmrem = this._pmrem;
 
-		if ( pmrem === null ) {
+		const pmremVersion = pmrem ? pmrem.pmremVersion : - 1;
+		const texture = this._value;
 
-			const texture = this._value;
+		if ( pmremVersion !== texture.pmremVersion ) {
 
 			if ( texture.isPMREMTexture === true ) {
 
@@ -154,6 +160,16 @@ class PMREMNode extends TempNode {
 
 		//
 
+		const texture = this.value;
+
+		if ( builder.renderer.coordinateSystem === WebGLCoordinateSystem && texture.isPMREMTexture !== true && texture.isRenderTargetTexture === true ) {
+
+			uvNode = vec3( uvNode.x.negate(), uvNode.yz );
+
+		}
+
+		//
+
 		let levelNode = this.levelNode;
 
 		if ( levelNode === null && builder.context.getTextureLevel ) {

+ 43 - 23
examples/jsm/renderers/common/extras/PMREMGenerator.js

@@ -44,6 +44,7 @@ const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
 const MAX_SAMPLES = 20;
 
 const _flatCamera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+const _cubeCamera = /*@__PURE__*/ new PerspectiveCamera( 90, 1 );
 const _clearColor = /*@__PURE__*/ new Color();
 let _oldTarget = null;
 let _oldActiveCubeFace = 0;
@@ -106,10 +107,12 @@ class PMREMGenerator {
 		this._lodPlanes = [];
 		this._sizeLods = [];
 		this._sigmas = [];
+		this._lodMeshes = [];
 
 		this._blurMaterial = null;
 		this._cubemapMaterial = null;
 		this._equirectMaterial = null;
+		this._backgroundBox = null;
 
 	}
 
@@ -210,6 +213,12 @@ class PMREMGenerator {
 
 		if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
 		if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();
+		if ( this._backgroundBox !== null ) {
+
+			this._backgroundBox.geometry.dispose();
+			this._backgroundBox.material.dispose();
+
+		}
 
 	}
 
@@ -297,7 +306,7 @@ class PMREMGenerator {
 			this._pingPongRenderTarget = _createRenderTarget( width, height, params );
 
 			const { _lodMax } = this;
-			( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );
+			( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas, lodMeshes: this._lodMeshes } = _createPlanes( _lodMax ) );
 
 			this._blurMaterial = _getBlurShader( _lodMax, width, height );
 
@@ -309,16 +318,18 @@ class PMREMGenerator {
 
 	_compileMaterial( material ) {
 
-		const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );
+		const tmpMesh = this._lodMeshes[ 0 ];
+		tmpMesh.material = material;
+
 		this._renderer.compile( tmpMesh, _flatCamera );
 
 	}
 
 	_sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
 
-		const fov = 90;
-		const aspect = 1;
-		const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
+		const cubeCamera = _cubeCamera;
+		cubeCamera.near = near;
+		cubeCamera.far = far;
 
 		// px, py, pz, nx, ny, nz
 		const upSign = [ - 1, 1, - 1, - 1, - 1, - 1 ];
@@ -333,14 +344,20 @@ class PMREMGenerator {
 		renderer.toneMapping = NoToneMapping;
 		renderer.autoClear = false;
 
-		const backgroundMaterial = new MeshBasicMaterial( {
-			name: 'PMREM.Background',
-			side: BackSide,
-			depthWrite: false,
-			depthTest: false
-		} );
+		let backgroundBox = this._backgroundBox;
 
-		const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );
+		if ( backgroundBox === null ) {
+
+			const backgroundMaterial = new MeshBasicMaterial( {
+				name: 'PMREM.Background',
+				side: BackSide,
+				depthWrite: false,
+				depthTest: false
+			} );
+
+			backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );
+
+		}
 
 		let useSolidColor = false;
 		const background = scene.background;
@@ -349,7 +366,7 @@ class PMREMGenerator {
 
 			if ( background.isColor ) {
 
-				backgroundMaterial.color.copy( background );
+				backgroundBox.material.color.copy( background );
 				scene.background = null;
 				useSolidColor = true;
 
@@ -357,7 +374,7 @@ class PMREMGenerator {
 
 		} else {
 
-			backgroundMaterial.color.copy( _clearColor );
+			backgroundBox.material.color.copy( _clearColor );
 			useSolidColor = true;
 
 		}
@@ -401,9 +418,6 @@ class PMREMGenerator {
 
 		}
 
-		backgroundBox.geometry.dispose();
-		backgroundBox.material.dispose();
-
 		renderer.toneMapping = toneMapping;
 		renderer.autoClear = originalAutoClear;
 		scene.background = background;
@@ -435,10 +449,11 @@ class PMREMGenerator {
 		}
 
 		const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;
-		const mesh = new Mesh( this._lodPlanes[ 0 ], material );
-
 		material.fragmentNode.value = texture;
 
+		const mesh = this._lodMeshes[ 0 ];
+		mesh.material = material;
+
 		const size = this._cubeSize;
 
 		_setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );
@@ -506,15 +521,16 @@ class PMREMGenerator {
 
 		if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
 
-			console.error(
-				'blur direction must be either latitudinal or longitudinal!' );
+			console.error( 'blur direction must be either latitudinal or longitudinal!' );
 
 		}
 
 		// Number of standard deviations at which to cut off the discrete approximation.
 		const STANDARD_DEVIATIONS = 3;
 
-		const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );
+		const blurMesh = this._lodMeshes[ lodOut ];
+		blurMesh.material = blurMaterial;
+
 		const blurUniforms = blurMaterial.uniforms;
 
 		const pixels = this._sizeLods[ lodIn ] - 1;
@@ -557,6 +573,8 @@ class PMREMGenerator {
 
 		}
 
+		targetIn.texture.frame = ( targetIn.texture.frame || 0 ) + 1;
+
 		blurUniforms.envMap.value = targetIn.texture;
 		blurUniforms.samples.value = samples;
 		blurUniforms.weights.array = weights;
@@ -589,6 +607,7 @@ function _createPlanes( lodMax ) {
 	const lodPlanes = [];
 	const sizeLods = [];
 	const sigmas = [];
+	const lodMeshes = [];
 
 	let lod = lodMax;
 
@@ -653,6 +672,7 @@ function _createPlanes( lodMax ) {
 		planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
 		planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
 		lodPlanes.push( planes );
+		lodMeshes.push( new Mesh( planes, null ) );
 
 		if ( lod > LOD_MIN ) {
 
@@ -662,7 +682,7 @@ function _createPlanes( lodMax ) {
 
 	}
 
-	return { lodPlanes, sizeLods, sigmas };
+	return { lodPlanes, sizeLods, sigmas, lodMeshes };
 
 }
 

BIN
examples/screenshots/webgpu_cubemap_dynamic.jpg


+ 9 - 10
examples/webgpu_cubemap_dynamic.html

@@ -60,15 +60,6 @@
 
 				}
 
-				renderer = new WebGPURenderer( { antialias: true } );
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				renderer.setAnimationLoop( animation );
-				renderer.toneMapping = THREE.ACESFilmicToneMapping;
-				document.body.appendChild( renderer.domElement );
-
-				window.addEventListener( 'resize', onWindowResized );
-
 				stats = new Stats();
 				document.body.appendChild( stats.dom );
 
@@ -134,6 +125,15 @@
 
 				//
 
+				renderer = new WebGPURenderer( { antialias: true, forceWebGL: false } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setAnimationLoop( animation );
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+				document.body.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResized );
+
 				controls = new OrbitControls( camera, renderer.domElement );
 				controls.autoRotate = true;
 
@@ -159,7 +159,6 @@
 
 				const time = msTime / 1000;
 
-				if ( ! cube ) return;
 				cube.position.x = Math.cos( time ) * 30;
 				cube.position.y = Math.sin( time ) * 30;
 				cube.position.z = Math.sin( time ) * 30;