Prechádzať zdrojové kódy

Examples: Improved WebGPU PMREM examples.

Mr.doob 2 mesiacov pred
rodič
commit
9b0d0937c7

+ 1 - 0
examples/files.json

@@ -399,6 +399,7 @@
 		"webgpu_pmrem_cubemap",
 		"webgpu_pmrem_equirectangular",
 		"webgpu_pmrem_scene",
+		"webgpu_pmrem_test",
 		"webgpu_portal",
 		"webgpu_postprocessing_3dlut",
 		"webgpu_postprocessing_afterimage",

BIN
examples/screenshots/webgpu_pmrem_cubemap.jpg


BIN
examples/screenshots/webgpu_pmrem_equirectangular.jpg


BIN
examples/screenshots/webgpu_pmrem_test.jpg


+ 19 - 16
examples/webgpu_pmrem_cubemap.html

@@ -22,14 +22,12 @@
 		<script type="module">
 
 			import * as THREE from 'three/webgpu';
-			import { normalWorldGeometry, uniform, normalView, positionViewDirection, cameraViewMatrix, pmremTexture } from 'three/tsl';
+			import { normalWorldGeometry, uniform, pmremTexture } from 'three/tsl';
 
 			import { HDRCubeTextureLoader } from 'three/addons/loaders/HDRCubeTextureLoader.js';
 
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
-			import { Inspector } from 'three/addons/inspector/Inspector.js';
-
 			let camera, scene, renderer;
 
 			init();
@@ -40,7 +38,7 @@
 				document.body.appendChild( container );
 
 				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
-				camera.position.set( - 1.8, 0.6, 2.7 );
+				camera.position.set( 0, 0, 8 );
 
 				scene = new THREE.Scene();
 
@@ -51,14 +49,10 @@
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setAnimationLoop( render );
 				renderer.toneMapping = THREE.ACESFilmicToneMapping;
-				renderer.inspector = new Inspector();
-
-				//await renderer.init();
 
 				container.appendChild( renderer.domElement );
 
 				const controls = new OrbitControls( camera, renderer.domElement );
-				controls.addEventListener( 'change', render ); // use if there is no animation loop
 				controls.minDistance = 2;
 				controls.maxDistance = 10;
 				controls.update();
@@ -67,19 +61,28 @@
 					.setPath( './textures/cube/pisaHDR/' )
 					.load( [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ], function ( map ) {
 
-						const reflectVec = positionViewDirection.negate().reflect( normalView ).transformDirection( cameraViewMatrix );
+						scene.backgroundNode = pmremTexture( map, normalWorldGeometry, uniform( 0.5 ) );
+
+						const geometry = new THREE.SphereGeometry( 0.4, 64, 64 );
+
+						for ( let i = 0; i < 6; i ++ ) {
 
-						const pmremRoughness = uniform( .5 );
-						const pmremNode = pmremTexture( map, reflectVec, pmremRoughness );
+							for ( let j = 0; j < 5; j ++ ) {
 
-						scene.backgroundNode = pmremTexture( map, normalWorldGeometry, pmremRoughness );
+								const material = new THREE.MeshPhysicalNodeMaterial( {
+									roughness: i / 5,
+									metalness: j / 4,
+									envMap: map
+								} );
 
-						scene.add( new THREE.Mesh( new THREE.SphereGeometry( .5, 64, 64 ), new THREE.MeshBasicNodeMaterial( { colorNode: pmremNode } ) ) );
+								const mesh = new THREE.Mesh( geometry, material );
+								mesh.position.x = i - 2.5;
+								mesh.position.y = j - 2;
+								scene.add( mesh );
 
-						// gui
+							}
 
-						const gui = renderer.inspector.createParameters( 'Settings' );
-						gui.add( pmremRoughness, 'value', 0, 1, 0.001 ).name( 'roughness' ).onChange( () => render() );
+						}
 
 					} );
 

+ 19 - 16
examples/webgpu_pmrem_equirectangular.html

@@ -22,14 +22,12 @@
 		<script type="module">
 
 			import * as THREE from 'three/webgpu';
-			import { normalWorldGeometry, uniform, normalView, positionViewDirection, cameraViewMatrix, pmremTexture } from 'three/tsl';
+			import { normalWorldGeometry, uniform, pmremTexture } from 'three/tsl';
 
 			import { HDRLoader } from 'three/addons/loaders/HDRLoader.js';
 
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
-			import { Inspector } from 'three/addons/inspector/Inspector.js';
-
 			let camera, scene, renderer;
 
 			init();
@@ -40,7 +38,7 @@
 				document.body.appendChild( container );
 
 				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
-				camera.position.set( - 1.8, 0.6, 2.7 );
+				camera.position.set( 0, 0, 8 );
 
 				scene = new THREE.Scene();
 
@@ -51,14 +49,10 @@
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setAnimationLoop( render );
 				renderer.toneMapping = THREE.ACESFilmicToneMapping;
-				renderer.inspector = new Inspector();
-
-				//await renderer.init();
 
 				container.appendChild( renderer.domElement );
 
 				const controls = new OrbitControls( camera, renderer.domElement );
-				controls.addEventListener( 'change', render ); // use if there is no animation loop
 				controls.minDistance = 2;
 				controls.maxDistance = 10;
 				controls.update();
@@ -69,19 +63,28 @@
 
 						map.mapping = THREE.EquirectangularReflectionMapping;
 
-						const reflectVec = positionViewDirection.negate().reflect( normalView ).transformDirection( cameraViewMatrix );
+						scene.backgroundNode = pmremTexture( map, normalWorldGeometry, uniform( 0.5 ) );
+
+						const geometry = new THREE.SphereGeometry( 0.4, 64, 64 );
+
+						for ( let i = 0; i < 6; i ++ ) {
 
-						const pmremRoughness = uniform( .5 );
-						const pmremNode = pmremTexture( map, reflectVec, pmremRoughness );
+							for ( let j = 0; j < 5; j ++ ) {
 
-						scene.backgroundNode = pmremTexture( map, normalWorldGeometry, pmremRoughness );
+								const material = new THREE.MeshPhysicalNodeMaterial( {
+									roughness: i / 5,
+									metalness: j / 4,
+									envMap: map
+								} );
 
-						scene.add( new THREE.Mesh( new THREE.SphereGeometry( .5, 64, 64 ), new THREE.MeshBasicNodeMaterial( { colorNode: pmremNode } ) ) );
+								const mesh = new THREE.Mesh( geometry, material );
+								mesh.position.x = i - 2.5;
+								mesh.position.y = j - 2;
+								scene.add( mesh );
 
-						// gui
+							}
 
-						const gui = renderer.inspector.createParameters( 'Settings' );
-						gui.add( pmremRoughness, 'value', 0, 1, 0.001 ).name( 'roughness' ).onChange( () => render() );
+						}
 
 					} );
 

+ 204 - 0
examples/webgpu_pmrem_test.html

@@ -0,0 +1,204 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<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">
+	</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.
+				<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>
+		</div>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.webgpu.js",
+					"three/tsl": "../build/three.webgpu.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			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';
+
+			let scene, camera, controls, renderer;
+
+			async function init() {
+
+				const width = window.innerWidth;
+				const height = window.innerHeight;
+				const aspect = width / height;
+
+				// renderer
+
+				renderer = new THREE.WebGPURenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( width, height );
+
+				// tonemapping
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+				renderer.toneMappingExposure = 1;
+
+				document.body.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResize );
+
+				// scene
+
+				scene = new THREE.Scene();
+
+				// camera
+
+				camera = new THREE.PerspectiveCamera( 40, aspect, 1, 30 );
+				updateCamera();
+				camera.position.set( 0, 0, 16 );
+
+				// controls
+
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.addEventListener( 'change', render ); // use if there is no animation loop
+				controls.minDistance = 4;
+				controls.maxDistance = 20;
+
+				// light
+
+				const directionalLight = new THREE.DirectionalLight( 0xffffff, 0 ); // set intensity to 0 to start
+				const x = 597;
+				const y = 213;
+				const theta = ( x + 0.5 ) * Math.PI / 512;
+				const phi = ( y + 0.5 ) * Math.PI / 512;
+
+				directionalLight.position.setFromSphericalCoords( 100, - phi, Math.PI / 2 - theta );
+
+				scene.add( directionalLight );
+				// scene.add( new THREE.DirectionalLightHelper( directionalLight ) );
+
+				// The spot1Lux HDR environment map is expressed in nits (lux / sr). The directional light has units of lux,
+				// so to match a 1 lux light, we set a single pixel with a value equal to 1 divided by the solid
+				// 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();
+				gui.add( { enabled: true }, 'enabled' )
+					.name( 'PMREM' )
+					.onChange( value => {
+
+						directionalLight.intensity = value ? 0 : 1;
+
+						scene.traverse( function ( child ) {
+
+							if ( child.isMesh ) {
+
+								child.material.envMapIntensity = 1 - directionalLight.intensity;
+
+							}
+
+						} );
+
+						render();
+
+					} );
+
+			}
+
+			async function createObjects() {
+
+				let radianceMap = null;
+				new HDRLoader()
+					// .setDataType( THREE.FloatType )
+					.setPath( 'textures/equirectangular/' )
+					.load( 'spot1Lux.hdr', function ( texture ) {
+
+						radianceMap = pmremGenerator.fromEquirectangular( texture ).texture;
+						pmremGenerator.dispose();
+
+						scene.background = radianceMap;
+
+						const geometry = new THREE.SphereGeometry( 0.4, 32, 32 );
+
+						for ( let x = 0; x <= 10; x ++ ) {
+
+							for ( let y = 0; y <= 2; y ++ ) {
+
+								const material = new THREE.MeshPhysicalNodeMaterial( {
+									roughness: x / 10,
+									metalness: y < 1 ? 1 : 0,
+									color: y < 2 ? 0xffffff : 0x000000,
+									envMap: radianceMap,
+									envMapIntensity: 1
+								} );
+
+								const mesh = new THREE.Mesh( geometry, material );
+								mesh.position.x = x - 5;
+								mesh.position.y = 1 - y;
+								scene.add( mesh );
+
+							}
+
+						}
+
+						render();
+
+					} );
+
+				const pmremGenerator = new THREE.PMREMGenerator( renderer );
+				pmremGenerator.compileEquirectangularShader();
+
+			}
+
+			function onWindowResize() {
+
+				const width = window.innerWidth;
+				const height = window.innerHeight;
+
+				camera.aspect = width / height;
+				updateCamera();
+
+				renderer.setSize( width, height );
+
+				render();
+
+			}
+
+			function updateCamera() {
+
+				const horizontalFoV = 40;
+				const verticalFoV = 2 * Math.atan( Math.tan( horizontalFoV / 2 * Math.PI / 180 ) / camera.aspect ) * 180 / Math.PI;
+				camera.fov = verticalFoV;
+				camera.updateProjectionMatrix();
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+
+			}
+
+			Promise.resolve()
+				.then( init )
+				.then( createObjects )
+				.then( render );
+
+		</script>
+	</body>
+</html>

粤ICP备19079148号