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

webxr_vr_layers: fixes and cleanup (#22325)

* webxr_vr_layers: fix GUI bug

* webxr_vr_layers: cleanup

Co-authored-by: Felix Mariotto <[email protected]>
Felix Mariotto 4 жил өмнө
parent
commit
d57bbd9935

+ 57 - 67
examples/webxr_vr_layers.html

@@ -30,20 +30,16 @@
 			import { XRControllerModelFactory } from './jsm/webxr/XRControllerModelFactory.js';
 			import { XRControllerModelFactory } from './jsm/webxr/XRControllerModelFactory.js';
 			import { XRHandModelFactory } from './jsm/webxr/XRHandModelFactory.js';
 			import { XRHandModelFactory } from './jsm/webxr/XRHandModelFactory.js';
 
 
-			let container;
 			let camera, scene, renderer;
 			let camera, scene, renderer;
-			let hand1, hand2;
-			let controller1, controller2;
-			let controllerGrip1, controllerGrip2;
 			let video;
 			let video;
 
 
-			// Four eye charts are rendered to demonstrate the differences in text quality. The two
-			// charts on the bottom are rendered to the eye buffer while the two charts on the top are
-			// rendered into XRQuadLayers, and the latter pair are substantially more legible.
+			// Four eye charts are rendered to demonstrate the differences in text quality.
+			// The two charts on the top are rendered into XRQuadLayers ( substantially more legible ).
+			// The two charts on the bottom are rendered to the eye buffer.
 			//
 			//
-			// The two charts on the left are rendered without mipmaps and have aliasing artifacts while
-			// the two charts on the right are with mipmaps an don't twinkle but are blurrier. To
-			// maximize text legibility, it's important to choose a texture size optimized for the
+			// The two charts on the left are rendered without mipmaps and have aliasing artifacts.
+			// The two charts on the right are with mipmaps an don't twinkle but are blurrier.
+			// To maximize text legibility, it's important to choose a texture size optimized for the
 			// distance of the text. (This example intentionally uses incorrectly large textures to
 			// distance of the text. (This example intentionally uses incorrectly large textures to
 			// demonstrate this issue.) If the optimal text size can't be determined beforehand, then
 			// demonstrate this issue.) If the optimal text size can't be determined beforehand, then
 			// mipmaps are required to avoid aliasing.
 			// mipmaps are required to avoid aliasing.
@@ -105,26 +101,14 @@
 
 
 			function init() {
 			function init() {
 
 
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
-
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 
 
 				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 10 );
 				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 10 );
 				camera.position.set( 0, 1.6, 3 );
 				camera.position.set( 0, 1.6, 3 );
 
 
-
-				scene.add( new THREE.HemisphereLight( 0x808080, 0x606060 ) );
-
+				const hemLight = new THREE.HemisphereLight( 0x808080, 0x606060 );
 				const light = new THREE.DirectionalLight( 0xffffff );
 				const light = new THREE.DirectionalLight( 0xffffff );
-				light.position.set( 0, 6, 0 );
-				light.castShadow = true;
-				light.shadow.camera.top = 2;
-				light.shadow.camera.bottom = - 2;
-				light.shadow.camera.right = 2;
-				light.shadow.camera.left = - 2;
-				light.shadow.mapSize.set( 4096, 4096 );
-				scene.add( light );
+				scene.add( hemLight, light );
 
 
 				//
 				//
 
 
@@ -134,55 +118,45 @@
 				renderer.setClearColor( new THREE.Color( 0 ), 0 );
 				renderer.setClearColor( new THREE.Color( 0 ), 0 );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.outputEncoding = THREE.sRGBEncoding;
 				renderer.outputEncoding = THREE.sRGBEncoding;
-				renderer.shadowMap.enabled = true;
 				renderer.xr.enabled = true;
 				renderer.xr.enabled = true;
 
 
-				container.appendChild( renderer.domElement );
-
+				document.body.appendChild( renderer.domElement );
 				document.body.appendChild( VRButton.createButton( renderer ) );
 				document.body.appendChild( VRButton.createButton( renderer ) );
 
 
 				// controllers
 				// controllers
 
 
-				controller1 = renderer.xr.getController( 0 );
-				scene.add( controller1 );
-
-				controller2 = renderer.xr.getController( 1 );
-				scene.add( controller2 );
+				const lineGeometry = new THREE.BufferGeometry().setFromPoints( [
+					new THREE.Vector3( 0, 0, 0 ),
+					new THREE.Vector3( 0, 0, - 10 )
+				] );
+				const line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: 0x5555ff } ) );
 
 
 				const controllerModelFactory = new XRControllerModelFactory();
 				const controllerModelFactory = new XRControllerModelFactory();
 				const handModelFactory = new XRHandModelFactory().setPath( "./models/fbx/" );
 				const handModelFactory = new XRHandModelFactory().setPath( "./models/fbx/" );
 
 
-				// Hand 1
-				controllerGrip1 = renderer.xr.getControllerGrip( 0 );
-				controllerGrip1.add( controllerModelFactory.createControllerModel( controllerGrip1 ) );
-				scene.add( controllerGrip1 );
-
-				hand1 = renderer.xr.getHand( 0 );
-				hand1.add( handModelFactory.createHandModel( hand1 ) );
-
-				scene.add( hand1 );
+				//
 
 
-				// Hand 2
-				controllerGrip2 = renderer.xr.getControllerGrip( 1 );
-				controllerGrip2.add( controllerModelFactory.createControllerModel( controllerGrip2 ) );
-				scene.add( controllerGrip2 );
+				const controllers = [
+					renderer.xr.getController( 0 ),
+					renderer.xr.getController( 1 )
+				];
 
 
-				hand2 = renderer.xr.getHand( 1 );
-				hand2.add( handModelFactory.createHandModel( hand2 ) );
-				scene.add( hand2 );
+				controllers.forEach( ( controller, i ) => {
 
 
-				//
+					const controllerGrip = renderer.xr.getControllerGrip( i );
+					controllerGrip.add( controllerModelFactory.createControllerModel( controllerGrip ) );
+					scene.add( controllerGrip );
 
 
-				const geometry = new THREE.BufferGeometry().setFromPoints( [ new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, - 1 ) ] );
+					const hand = renderer.xr.getHand( i );
+					hand.add( handModelFactory.createHandModel( hand ) );
 
 
-				const line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x5555ff } ) );
-				line.name = 'line';
-				line.scale.z = 10;
+					controller.add( line.clone() );
+					scene.add( controller, controllerGrip, hand );
 
 
-				controller1.add( line.clone() );
-				controller2.add( line.clone() );
+				} );
 
 
 				// Eye charts
 				// Eye charts
+
 				const eyeCharts = new THREE.Group();
 				const eyeCharts = new THREE.Group();
 				eyeCharts.position.z = snellenConfig.z;
 				eyeCharts.position.z = snellenConfig.z;
 				scene.add( eyeCharts );
 				scene.add( eyeCharts );
@@ -235,6 +209,7 @@
 				function onChange() {
 				function onChange() {
 
 
 					eyeCharts.position.z = - parameters.eyeChartDistanceFt * 0.3048;
 					eyeCharts.position.z = - parameters.eyeChartDistanceFt * 0.3048;
+					snellenConfig.z = eyeCharts.position.z;
 
 
 					if ( quadLayerPlain ) {
 					if ( quadLayerPlain ) {
 
 
@@ -264,9 +239,7 @@
 				scene.add( group );
 				scene.add( group );
 
 
 				guiMesh = new HTMLMesh( gui.domElement );
 				guiMesh = new HTMLMesh( gui.domElement );
-				guiMesh.position.x = 1.0;
-				guiMesh.position.y = 1.5;
-				guiMesh.position.z = - 1.0;
+				guiMesh.position.set( 1.0, 1.5, - 1.0 );
 				guiMesh.rotation.y = - Math.PI / 4;
 				guiMesh.rotation.y = - Math.PI / 4;
 				guiMesh.scale.setScalar( 2 );
 				guiMesh.scale.setScalar( 2 );
 				guiMesh.material.opacity = 0;
 				guiMesh.material.opacity = 0;
@@ -329,7 +302,12 @@
 
 
 				}
 				}
 
 
-				if ( session && session.renderState.layers !== undefined && session.hasMediaLayer === undefined && video.readyState >= 2 ) {
+				if (
+					session &&
+					session.renderState.layers !== undefined &&
+					session.hasMediaLayer === undefined &&
+					video.readyState >= 2
+				) {
 
 
 					session.hasMediaLayer = true;
 					session.hasMediaLayer = true;
 					session.requestReferenceSpace( 'local-floor' ).then( ( refSpace ) => {
 					session.requestReferenceSpace( 'local-floor' ).then( ( refSpace ) => {
@@ -342,19 +320,19 @@
 							viewPixelWidth: snellenConfig.textureSizePx,
 							viewPixelWidth: snellenConfig.textureSizePx,
 							viewPixelHeight: snellenConfig.textureSizePx,
 							viewPixelHeight: snellenConfig.textureSizePx,
 							isStatic: true,
 							isStatic: true,
-							space: refSpace, layout: "mono",
+							space: refSpace,
+							layout: "mono",
 							transform: new XRRigidTransform( {
 							transform: new XRRigidTransform( {
 								x: snellenConfig.x - snellenConfig.widthMeters,
 								x: snellenConfig.x - snellenConfig.widthMeters,
 								y: snellenConfig.y + snellenConfig.heightMeters,
 								y: snellenConfig.y + snellenConfig.heightMeters,
 								z: snellenConfig.z
 								z: snellenConfig.z
 							} )
 							} )
-
 						};
 						};
 
 
 						quadLayerPlain = glBinding.createQuadLayer( quadLayerConfig );
 						quadLayerPlain = glBinding.createQuadLayer( quadLayerConfig );
 
 
 						quadLayerConfig.mipLevels = 3;
 						quadLayerConfig.mipLevels = 3;
-						quadLayerConfig.transform = new XRRigidTransform(	{
+						quadLayerConfig.transform = new XRRigidTransform( {
 							x: snellenConfig.x + snellenConfig.widthMeters,
 							x: snellenConfig.x + snellenConfig.widthMeters,
 							y: snellenConfig.y + snellenConfig.heightMeters,
 							y: snellenConfig.y + snellenConfig.heightMeters,
 							z: snellenConfig.z
 							z: snellenConfig.z
@@ -381,12 +359,23 @@
 								// Rotate by 45 deg to avoid stereo conflict with the 3D geometry.
 								// Rotate by 45 deg to avoid stereo conflict with the 3D geometry.
 								transform: new XRRigidTransform(
 								transform: new XRRigidTransform(
 									{},
 									{},
-									{ x: 0, y: .28, z: 0, w: .96 } )
+									{ x: 0, y: .28, z: 0, w: .96 }
+								)
 							}
 							}
 						);
 						);
 
 
 						errorMesh.visible = false;
 						errorMesh.visible = false;
-						session.updateRenderState( { layers: [ equirectLayer, quadLayerPlain, quadLayerMips, guiLayer, session.renderState.layers[ 0 ] ] } );
+
+						session.updateRenderState( {
+							layers: [
+								equirectLayer,
+								quadLayerPlain,
+								quadLayerMips,
+								guiLayer,
+								session.renderState.layers[ 0 ]
+							]
+						} );
+						
 						video.play();
 						video.play();
 
 
 					} );
 					} );
@@ -395,7 +384,7 @@
 
 
 				// Copy image to layers as required.
 				// Copy image to layers as required.
 				// needsRedraw is set on creation or if the underlying GL resources of a layer are lost.
 				// needsRedraw is set on creation or if the underlying GL resources of a layer are lost.
-				if ( quadLayerPlain && quadLayerPlain.needsRedraw ) {
+				if ( session && quadLayerPlain && quadLayerPlain.needsRedraw ) {
 
 
 					const glayer = xr.getBinding().getSubImage( quadLayerPlain, frame );
 					const glayer = xr.getBinding().getSubImage( quadLayerPlain, frame );
 					renderer.state.bindTexture( gl.TEXTURE_2D, glayer.colorTexture );
 					renderer.state.bindTexture( gl.TEXTURE_2D, glayer.colorTexture );
@@ -409,7 +398,7 @@
 				}
 				}
 
 
 				// Same as above but also gl.generateMipmap.
 				// Same as above but also gl.generateMipmap.
-				if ( quadLayerMips && quadLayerMips.needsRedraw ) {
+				if ( session && quadLayerMips && quadLayerMips.needsRedraw ) {
 
 
 					const glayer = xr.getBinding().getSubImage( quadLayerMips, frame );
 					const glayer = xr.getBinding().getSubImage( quadLayerMips, frame );
 					renderer.state.bindTexture( gl.TEXTURE_2D, glayer.colorTexture );
 					renderer.state.bindTexture( gl.TEXTURE_2D, glayer.colorTexture );
@@ -424,13 +413,14 @@
 				}
 				}
 
 
 				// Same as above, but guiLayer.needsUpdate is set when the user interacts with the GUI.
 				// Same as above, but guiLayer.needsUpdate is set when the user interacts with the GUI.
-				if ( guiLayer && ( guiLayer.needsRedraw || guiLayer.needsUpdate ) ) {
+				if ( session && guiLayer && ( guiLayer.needsRedraw || guiLayer.needsUpdate ) ) {
 
 
 					const glayer = xr.getBinding().getSubImage( guiLayer, frame );
 					const glayer = xr.getBinding().getSubImage( guiLayer, frame );
 					renderer.state.bindTexture( gl.TEXTURE_2D, glayer.colorTexture );
 					renderer.state.bindTexture( gl.TEXTURE_2D, glayer.colorTexture );
 					gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true );
 					gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true );
 					const canvas = guiMesh.material.map.image;
 					const canvas = guiMesh.material.map.image;
 					gl.texSubImage2D( gl.TEXTURE_2D, 0, 0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, canvas );
 					gl.texSubImage2D( gl.TEXTURE_2D, 0, 0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, canvas );
+					guiLayer.needsUpdate = false;
 
 
 				}
 				}