Browse Source

WebGPURenderer: DFG LUT instead of Analytical approximation. (#32061)

* Update DFGApprox.js

* add `webgpu_pmrem_test`

* Create webgpu_pmrem_test.jpg

---------

Co-authored-by: Mr.doob <info@mrdoob.com>
sunag 2 months ago
parent
commit
34f3fa6493

BIN
examples/screenshots/webgl_pmrem_test.jpg


+ 23 - 26
examples/webgpu_pmrem_test.html

@@ -4,26 +4,31 @@
 		<title>three.js webgpu - PMREM directional light test</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<link type="text/css" rel="stylesheet" href="main.css">
+		<link type="text/css" rel="stylesheet" href="example.css">
 	</head>
 	<body>
 
-		<div id="container">
-			<div id="info">
-				<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgpu -
-				PMREM test by <a href="https://github.com/elalish" target="_blank" rel="noopener">Emmett Lalish</a>
-				<br>
-				<br>1: white metal. 2: white dielectric. 3: black dielectric.
+		<div id="info">
+			<a href="https://threejs.org/" target="_blank" rel="noopener" class="logo-link"></a>
+
+			<div class="title-wrapper">
+				<a href="https://threejs.org/" target="_blank" rel="noopener">three.js</a><span>PMREM Directional Light Test</span>
+			</div>
+
+			<small>
+				1: white metal. 2: white dielectric. 3: black dielectric.
 				<br>PMREM on: HDR with a single bright pixel. PMREM off: DirectionalLight.
 				<br>The difference between these renders indicates the error in the PMREM approximations.
-			</div>
+				<br>PMREM test by <a href="https://github.com/elalish" target="_blank" rel="noopener">Emmett Lalish</a>
+			</small>
 		</div>
 
 		<script type="importmap">
 			{
 				"imports": {
 					"three": "../build/three.webgpu.js",
-					"three/tsl": "../build/three.webgpu.js",
+					"three/webgpu": "../build/three.webgpu.js",
+					"three/tsl": "../build/three.tsl.js",
 					"three/addons/": "./jsm/"
 				}
 			}
@@ -36,9 +41,7 @@
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 			import { HDRLoader } from 'three/addons/loaders/HDRLoader.js';
 
-			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
-
-			import WebGPU from 'three/addons/capabilities/WebGPU.js';
+			import { Inspector } from 'three/addons/inspector/Inspector.js';
 
 			let scene, camera, controls, renderer;
 
@@ -53,17 +56,19 @@
 				renderer = new THREE.WebGPURenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( width, height );
+				renderer.setAnimationLoop( render );
+				renderer.inspector = new Inspector();
 
 				// tonemapping
 				renderer.toneMapping = THREE.ACESFilmicToneMapping;
 				renderer.toneMappingExposure = 1;
 
-				await renderer.init();
-
 				document.body.appendChild( renderer.domElement );
 
 				window.addEventListener( 'resize', onWindowResize );
 
+				await renderer.init();
+
 				// scene
 
 				scene = new THREE.Scene();
@@ -77,7 +82,6 @@
 				// controls
 
 				controls = new OrbitControls( camera, renderer.domElement );
-				controls.addEventListener( 'change', render ); // use if there is no animation loop
 				controls.minDistance = 4;
 				controls.maxDistance = 20;
 
@@ -99,7 +103,7 @@
 				// angle of the pixel in steradians. This image is 1024 x 512,
 				// so the value is 1 / ( sin( phi ) * ( pi / 512 ) ^ 2 ) = 27,490 nits.
 
-				const gui = new GUI();
+				const gui = renderer.inspector.createParameters( 'Settings' );
 				gui.add( { enabled: true }, 'enabled' )
 					.name( 'PMREM' )
 					.onChange( value => {
@@ -116,13 +120,11 @@
 
 						} );
 
-						render();
-
 					} );
 
 			}
 
-			async function createObjects() {
+			function createObjects() {
 
 				let radianceMap = null;
 				new HDRLoader()
@@ -141,7 +143,7 @@
 
 							for ( let y = 0; y <= 2; y ++ ) {
 
-								const material = new THREE.MeshPhysicalNodeMaterial( {
+								const material = new THREE.MeshPhysicalMaterial( {
 									roughness: x / 10,
 									metalness: y < 1 ? 1 : 0,
 									color: y < 2 ? 0xffffff : 0x000000,
@@ -158,8 +160,6 @@
 
 						}
 
-						render();
-
 					} );
 
 				const pmremGenerator = new THREE.PMREMGenerator( renderer );
@@ -177,8 +177,6 @@
 
 				renderer.setSize( width, height );
 
-				render();
-
 			}
 
 			function updateCamera() {
@@ -198,8 +196,7 @@
 
 			Promise.resolve()
 				.then( init )
-				.then( createObjects )
-				.then( render );
+				.then( createObjects );
 
 		</script>
 	</body>

+ 17 - 19
src/nodes/functions/BSDF/DFGApprox.js

@@ -1,30 +1,28 @@
-import { Fn, vec2, vec4 } from '../../tsl/TSLBase.js';
+import { Fn, vec2 } from '../../tsl/TSLBase.js';
+import { texture } from '../../accessors/TextureNode.js';
+import { getDFGLUT } from '../../../renderers/shaders/DFGLUTData.js';
 
-// Analytical approximation of the DFG LUT, one half of the
-// split-sum approximation used in indirect specular lighting.
-// via 'environmentBRDF' from "Physically Based Shading on Mobile"
-// https://www.unrealengine.com/blog/physically-based-shading-on-mobile
-const DFGApprox = /*@__PURE__*/ Fn( ( { roughness, dotNV } ) => {
+// Cached DFG LUT texture
+
+let dfgLUT = null;
 
-	const c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );
+// DFG LUT sampling for physically-based rendering.
+// Uses a precomputed lookup table for the split-sum approximation
+// used in indirect specular lighting.
+// Reference: "Real Shading in Unreal Engine 4" by Brian Karis
+
+const DFGApprox = /*@__PURE__*/ Fn( ( { roughness, dotNV } ) => {
 
-	const c1 = vec4( 1, 0.0425, 1.04, - 0.04 );
+	if ( dfgLUT === null ) {
 
-	const r = roughness.mul( c0 ).add( c1 );
+		dfgLUT = getDFGLUT();
 
-	const a004 = r.x.mul( r.x ).min( dotNV.mul( - 9.28 ).exp2() ).mul( r.x ).add( r.y );
+	}
 
-	const fab = vec2( - 1.04, 1.04 ).mul( a004 ).add( r.zw );
+	const uv = vec2( roughness, dotNV );
 
-	return fab;
+	return texture( dfgLUT, uv ).rg;
 
-} ).setLayout( {
-	name: 'DFGApprox',
-	type: 'vec2',
-	inputs: [
-		{ name: 'roughness', type: 'float' },
-		{ name: 'dotNV', type: 'vec3' }
-	]
 } );
 
 export default DFGApprox;

粤ICP备19079148号