2
0
Эх сурвалжийг харах

GTAONode: Bring `getTextureNode()` back. (#28883)

* GTAONode: Bring `getTextureNode()` back.

* E2E: Update screenshot.
Michael Herzog 1 жил өмнө
parent
commit
8a102ea21d

BIN
examples/screenshots/webgpu_postprocessing_ao.jpg


+ 69 - 18
examples/webgpu_postprocessing_ao.html

@@ -20,27 +20,28 @@
 		<script type="module">
 
 			import * as THREE from 'three';
-			import { pass, mrt, output, transformedNormalView } from 'three/tsl';
+			import { pass, mrt, output, transformedNormalView, texture, ao } from 'three/tsl';
 
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 			import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
 			import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
 			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
+			import { SimplexNoise } from 'three/addons/math/SimplexNoise.js';
 
 			import Stats from 'three/addons/libs/stats.module.js';
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 			let camera, scene, renderer, postProcessing, controls, clock, stats, mixer;
 
-			let aoPass;
+			let aoPass, blendPassAO, blendPassDenoise, scenePassColor;
 
 			const params = {
-				blendIntensity: 1,
 				distanceExponent: 1,
 				distanceFallOff: 1,
 				radius: 0.25,
 				scale: 1,
 				thickness: 1,
+				denoised: true,
 				enabled: true
 			};
 
@@ -57,10 +58,10 @@
 				clock = new THREE.Clock();
 
 				const hdrloader = new RGBELoader();
-				const texture = await hdrloader.loadAsync( 'textures/equirectangular/quarry_01_1k.hdr' );
-				texture.mapping = THREE.EquirectangularReflectionMapping;
+				const envMap = await hdrloader.loadAsync( 'textures/equirectangular/quarry_01_1k.hdr' );
+				envMap.mapping = THREE.EquirectangularReflectionMapping;
 
-				scene.environment = texture;
+				scene.environment = envMap;
 
 				renderer = new THREE.WebGPURenderer();
 				renderer.setSize( window.innerWidth, window.innerHeight );
@@ -86,13 +87,22 @@
 					normal: transformedNormalView
 				} ) );
 
-				const scenePassColor = scenePass.getTextureNode( 'output' );
+				scenePassColor = scenePass.getTextureNode( 'output' );
 				const scenePassNormal = scenePass.getTextureNode( 'normal' );
 				const scenePassDepth = scenePass.getTextureNode( 'depth' );
 
-				aoPass = scenePassColor.ao( scenePassDepth, scenePassNormal, camera );
+				// ao
 
-				postProcessing.outputNode = aoPass;
+				aoPass = ao( scenePassDepth, scenePassNormal, camera );
+				blendPassAO = aoPass.getTextureNode().mul( scenePassColor );
+
+				// denoise (optional)
+
+				const noiseTexture = texture( generateNoise() );
+				const denoisePass = aoPass.getTextureNode().denoise( scenePassDepth, scenePassNormal, noiseTexture, camera );
+				blendPassDenoise = denoisePass.mul( scenePassColor );
+
+				postProcessing.outputNode = blendPassDenoise;
 
 				//
 
@@ -119,34 +129,43 @@
 
 				const gui = new GUI();
 				gui.title( 'AO settings' );
-				gui.add( params, 'blendIntensity' ).min( 0 ).max( 1 ).onChange( updateParameters );
 				gui.add( params, 'distanceExponent' ).min( 1 ).max( 4 ).onChange( updateParameters );
 				gui.add( params, 'distanceFallOff' ).min( 0.01 ).max( 1 ).onChange( updateParameters );
 				gui.add( params, 'radius' ).min( 0.01 ).max( 1 ).onChange( updateParameters );
 				gui.add( params, 'scale' ).min( 0.01 ).max( 2 ).onChange( updateParameters );
 				gui.add( params, 'thickness' ).min( 0.01 ).max( 2 ).onChange( updateParameters );
+				gui.add( params, 'denoised' ).onChange( updatePassChain );
+				gui.add( params, 'enabled' ).onChange( updatePassChain );
+
+			}
+
+			function updatePassChain() {
+
+				if ( params.enabled === true ) {
 
-				gui.add( params, 'enabled' ).onChange( ( value ) => {
-			
-					if ( value === true ) {
+					if ( params.denoised === true ) {
 
-						postProcessing.outputNode = aoPass;
+						postProcessing.outputNode = blendPassDenoise;
 
 					} else {
 
-						postProcessing.outputNode = scenePassColor;
+						postProcessing.outputNode = blendPassAO;
 
 					}
 
-					postProcessing.needsUpdate = true;
+				} else {
+
+					postProcessing.outputNode = scenePassColor;
+
+				}
+
+				postProcessing.needsUpdate = true;
 
-				} );
 
 			}
 
 			function updateParameters() {
 
-				aoPass.blendIntensity.value = params.blendIntensity;
 				aoPass.distanceExponent.value = params.distanceExponent;
 				aoPass.distanceFallOff.value = params.distanceFallOff;
 				aoPass.radius.value = params.radius;
@@ -155,6 +174,38 @@
 
 			}
 
+			function generateNoise( size = 64 ) {
+
+				const simplex = new SimplexNoise();
+
+				const arraySize = size * size * 4;
+				const data = new Uint8Array( arraySize );
+
+				for ( let i = 0; i < size; i ++ ) {
+
+					for ( let j = 0; j < size; j ++ ) {
+
+						const x = i;
+						const y = j;
+
+						data[ ( i * size + j ) * 4 ] = ( simplex.noise( x, y ) * 0.5 + 0.5 ) * 255;
+						data[ ( i * size + j ) * 4 + 1 ] = ( simplex.noise( x + size, y ) * 0.5 + 0.5 ) * 255;
+						data[ ( i * size + j ) * 4 + 2 ] = ( simplex.noise( x, y + size ) * 0.5 + 0.5 ) * 255;
+						data[ ( i * size + j ) * 4 + 3 ] = ( simplex.noise( x + size, y + size ) * 0.5 + 0.5 ) * 255;
+
+					}
+
+				}
+
+				const noiseTexture = new THREE.DataTexture( data, size, size );
+				noiseTexture.wrapS = THREE.RepeatWrapping;
+				noiseTexture.wrapT = THREE.RepeatWrapping;
+				noiseTexture.needsUpdate = true;
+
+				return noiseTexture;
+
+			}
+
 			function onWindowResize() {
 
 				const width = window.innerWidth;

+ 13 - 30
src/nodes/display/GTAONode.js

@@ -19,14 +19,14 @@ import { Color } from '../../math/Color.js';
 
 const _quadMesh = new QuadMesh();
 const _currentClearColor = new Color();
+const _size = new Vector2();
 
 class GTAONode extends TempNode {
 
-	constructor( textureNode, depthNode, normalNode, camera ) {
+	constructor( depthNode, normalNode, camera ) {
 
 		super();
 
-		this.textureNode = textureNode;
 		this.depthNode = depthNode;
 		this.normalNode = normalNode;
 
@@ -36,7 +36,6 @@ class GTAONode extends TempNode {
 		this.distanceExponent = uniform( 1 );
 		this.distanceFallOff = uniform( 1 );
 		this.scale = uniform( 1 );
-		this.blendIntensity = uniform( 1 );
 		this.noiseNode = texture( generateMagicSquareNoise() );
 
 		this.cameraProjectionMatrix = uniform( camera.projectionMatrix );
@@ -50,7 +49,13 @@ class GTAONode extends TempNode {
 		this._material = null;
 		this._textureNode = passTexture( this, this._aoRenderTarget.texture );
 
-		this.updateBeforeType = NodeUpdateType.RENDER;
+		this.updateBeforeType = NodeUpdateType.FRAME;
+
+	}
+
+	getTextureNode() {
+
+		return this._textureNode;
 
 	}
 
@@ -65,25 +70,16 @@ class GTAONode extends TempNode {
 
 		const { renderer } = frame;
 
-		const textureNode = this.textureNode;
-		const map = textureNode.value;
+		const size = renderer.getSize( _size );
 
 		const currentRenderTarget = renderer.getRenderTarget();
 		const currentMRT = renderer.getMRT();
 		renderer.getClearColor( _currentClearColor );
 		const currentClearAlpha = renderer.getClearAlpha();
 
-
-		const currentTexture = textureNode.value;
-
 		_quadMesh.material = this._material;
 
-		this.setSize( map.image.width, map.image.height );
-
-
-		const textureType = map.type;
-
-		this._aoRenderTarget.texture.type = textureType;
+		this.setSize( size.width, size.height );
 
 		// clear
 
@@ -100,17 +96,13 @@ class GTAONode extends TempNode {
 		renderer.setRenderTarget( currentRenderTarget );
 		renderer.setMRT( currentMRT );
 		renderer.setClearColor( _currentClearColor, currentClearAlpha );
-		textureNode.value = currentTexture;
 
 	}
 
 	setup( builder ) {
 
-		const { textureNode } = this;
-
 		const uvNode = uv();
 
-		const sampleTexture = ( uv ) => textureNode.uv( uv );
 		const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x;
 		const sampleNoise = ( uv ) => this.noiseNode.uv( uv );
 
@@ -223,22 +215,13 @@ class GTAONode extends TempNode {
 
 		} );
 
-		const composite = tslFn( () => {
-
-			const beauty = sampleTexture( uvNode );
-			const ao = this._textureNode.uv( uvNode );
-
-			return beauty.mul( mix( vec3( 1.0 ), ao, this.blendIntensity ) );
-
-		} );
-
 		const material = this._material || ( this._material = builder.createNodeMaterial() );
 		material.fragmentNode = ao().context( builder.getSharedContext() );
 		material.needsUpdate = true;
 
 		//
 
-		return composite();
+		return this._textureNode;
 
 	}
 
@@ -328,7 +311,7 @@ function generateMagicSquare( size ) {
 
 }
 
-export const ao = ( node, depthNode, normalNode, camera ) => nodeObject( new GTAONode( nodeObject( node ).toTexture(), nodeObject( depthNode ), nodeObject( normalNode ), camera ) );
+export const ao = ( depthNode, normalNode, camera ) => nodeObject( new GTAONode( nodeObject( depthNode ), nodeObject( normalNode ), camera ) );
 
 addNodeElement( 'ao', ao );