ソースを参照

WebGPURenderer: Fix native WebGPU XR camera selection (#34112)

Rik Cabanier 8 時間 前
コミット
bb24effff0

+ 2 - 1
examples/files.json

@@ -523,7 +523,8 @@
 		"webgpu_water",
 		"webgpu_xr_rollercoaster",
 		"webgpu_xr_cubes",
-		"webgpu_xr_native_layers"
+		"webgpu_xr_native_layers",
+		"webgpu_xr_shadows"
 	],
 	"webaudio": [
 		"webaudio_orientation",

BIN
examples/screenshots/webgpu_xr_shadows.jpg


+ 218 - 0
examples/webgpu_xr_shadows.html

@@ -0,0 +1,218 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js vr - shadows</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+		<meta property="og:title" content="three.js vr - shadows">
+		<meta property="og:type" content="website">
+		<meta property="og:url" content="https://threejs.org/examples/webgpu_xr_shadows.html">
+		<meta property="og:image" content="https://threejs.org/examples/screenshots/webgpu_xr_shadows.jpg">
+		<link type="text/css" rel="stylesheet" href="main.css">
+	</head>
+	<body>
+
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> vr - shadows
+		</div>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.webgpu.js",
+					"three/webgpu": "../build/three.webgpu.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three/webgpu';
+
+			import { VRButton } from 'three/addons/webxr/VRButton.js';
+			import { setupWebGLXRFallback } from 'three/addons/webxr/WebGLXRFallback.js';
+
+			const rendererParameters = { antialias: true, outputBufferType: THREE.UnsignedByteType, multiview: false };
+			const timer = new THREE.Timer();
+			timer.connect( document );
+
+			let camera, cameraRig, scene, renderer;
+			let directionalLight, torusKnot, box, icosahedron, cone;
+
+			init();
+
+			function init() {
+
+				scene = new THREE.Scene();
+				scene.background = new THREE.Color( 0x24282f );
+				scene.fog = new THREE.Fog( 0x24282f, 8, 16 );
+
+				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 30 );
+				camera.position.y = 1.6;
+
+				cameraRig = new THREE.Group();
+				cameraRig.position.z = 4;
+				cameraRig.add( camera );
+				scene.add( cameraRig );
+
+				// lights
+
+				scene.add( new THREE.HemisphereLight( 0xb8c5df, 0x3c3028, 1.5 ) );
+
+				directionalLight = new THREE.DirectionalLight( 0xfff1d6, 4 );
+				directionalLight.position.set( - 4, 6, 2 );
+				directionalLight.castShadow = true;
+				directionalLight.shadow.camera.near = 0.1;
+				directionalLight.shadow.camera.far = 15;
+				directionalLight.shadow.camera.left = - 5;
+				directionalLight.shadow.camera.right = 5;
+				directionalLight.shadow.camera.top = 5;
+				directionalLight.shadow.camera.bottom = - 5;
+				directionalLight.shadow.mapSize.set( 2048, 2048 );
+				directionalLight.shadow.bias = - 0.0005;
+				scene.add( directionalLight );
+				scene.add( directionalLight.target );
+
+				// environment
+
+				const floor = new THREE.Mesh(
+					new THREE.PlaneGeometry( 14, 14 ),
+					new THREE.MeshStandardMaterial( { color: 0x73786f, roughness: 0.9 } )
+				);
+				floor.rotation.x = - Math.PI / 2;
+				floor.receiveShadow = true;
+				scene.add( floor );
+
+				const platform = new THREE.Mesh(
+					new THREE.CylinderGeometry( 1.25, 1.4, 0.3, 64 ),
+					new THREE.MeshStandardMaterial( { color: 0x40464d, roughness: 0.6, metalness: 0.2 } )
+				);
+				platform.position.y = 0.15;
+				platform.castShadow = true;
+				platform.receiveShadow = true;
+				scene.add( platform );
+
+				// shadow casters
+
+				torusKnot = new THREE.Mesh(
+					new THREE.TorusKnotGeometry( 0.55, 0.18, 128, 24 ),
+					new THREE.MeshStandardMaterial( { color: 0xe7ad52, roughness: 0.25, metalness: 0.35 } )
+				);
+				torusKnot.position.y = 1.35;
+				torusKnot.castShadow = true;
+				torusKnot.receiveShadow = true;
+				scene.add( torusKnot );
+
+				box = new THREE.Mesh(
+					new THREE.BoxGeometry( 0.7, 0.7, 0.7 ),
+					new THREE.MeshStandardMaterial( { color: 0xd85f50, roughness: 0.5 } )
+				);
+				box.position.set( - 1.8, 0.6, 0.25 );
+				box.rotation.set( 0.2, 0.4, 0.1 );
+				box.castShadow = true;
+				box.receiveShadow = true;
+				scene.add( box );
+
+				icosahedron = new THREE.Mesh(
+					new THREE.IcosahedronGeometry( 0.5, 2 ),
+					new THREE.MeshStandardMaterial( { color: 0x4f91b8, roughness: 0.35, metalness: 0.15 } )
+				);
+				icosahedron.position.set( 1.8, 0.7, 0.1 );
+				icosahedron.castShadow = true;
+				icosahedron.receiveShadow = true;
+				scene.add( icosahedron );
+
+				cone = new THREE.Mesh(
+					new THREE.ConeGeometry( 0.5, 1.1, 48 ),
+					new THREE.MeshStandardMaterial( { color: 0x68a66b, roughness: 0.65 } )
+				);
+				cone.position.set( 0, 0.55, - 2 );
+				cone.castShadow = true;
+				cone.receiveShadow = true;
+				scene.add( cone );
+
+				// renderer
+
+				renderer = createRenderer();
+				setRenderer( renderer );
+				setupWebGLXRFallback( renderer, () => createRenderer( true ), setRenderer );
+
+				document.body.appendChild( VRButton.createButton( renderer, { optionalFeatures: [ 'webgpu' ] } ) );
+
+				window.addEventListener( 'resize', onWindowResize );
+
+			}
+
+			function createRenderer( forceWebGL = false ) {
+
+				const parameters = { ...rendererParameters };
+
+				if ( forceWebGL === true ) parameters.forceWebGL = true;
+
+				const renderer = new THREE.WebGPURenderer( parameters );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setAnimationLoop( animate );
+				renderer.shadowMap.enabled = true;
+				renderer.shadowMap.type = THREE.PCFShadowMap;
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+				renderer.toneMappingExposure = 1.2;
+				renderer.xr.enabled = true;
+
+				return renderer;
+
+			}
+
+			function setRenderer( newRenderer, oldRenderer = null ) {
+
+				if ( oldRenderer === null ) {
+
+					document.body.appendChild( newRenderer.domElement );
+
+				} else {
+
+					document.body.replaceChild( newRenderer.domElement, oldRenderer.domElement );
+					oldRenderer.dispose();
+
+				}
+
+				renderer = newRenderer;
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				timer.update();
+
+				const elapsed = timer.getElapsed();
+				const delta = timer.getDelta();
+
+				torusKnot.position.y = 1.35 + Math.sin( elapsed * 1.5 ) * 0.15;
+				torusKnot.rotation.x += delta * 0.35;
+				torusKnot.rotation.y += delta * 0.7;
+
+				box.rotation.y += delta * 0.4;
+				icosahedron.rotation.x += delta * 0.3;
+				icosahedron.rotation.y -= delta * 0.5;
+				cone.rotation.y -= delta * 0.35;
+
+				directionalLight.position.x = Math.cos( elapsed * 0.25 ) * 4;
+				directionalLight.position.z = Math.sin( elapsed * 0.25 ) * 4;
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+	</body>
+</html>

+ 2 - 2
src/renderers/common/Renderer.js

@@ -934,7 +934,7 @@ class Renderer {
 		// Match render()'s logic: use frameBufferTarget when needsFrameBufferTarget is true
 		const useFrameBufferTarget = this.needsFrameBufferTarget && this._renderTarget === null;
 		const outputRenderTarget = this._renderTarget || this._outputRenderTarget;
-		const useXRCamera = outputRenderTarget !== null && outputRenderTarget.isXRRenderTarget === true;
+		const useXRCamera = this.xr.isPresenting === true && this.isOutputTarget;
 		const renderTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : outputRenderTarget;
 		const renderContext = this._renderContexts.get( renderTarget, this._mrt );
 		const activeMipmapLevel = this._activeMipmapLevel;
@@ -1680,7 +1680,7 @@ class Renderer {
 		const sceneRef = ( scene.isScene === true ) ? scene : _scene;
 
 		const outputRenderTarget = this._renderTarget || this._outputRenderTarget;
-		const useXRCamera = outputRenderTarget !== null && outputRenderTarget.isXRRenderTarget === true;
+		const useXRCamera = this.xr.isPresenting === true && this.isOutputTarget;
 
 		const activeCubeFace = this._activeCubeFace;
 		const activeMipmapLevel = this._activeMipmapLevel;

粤ICP备19079148号