Browse Source

Examples: Refactored webxr_vr_haptics.

Mr.doob 8 months ago
parent
commit
1859806c1f
1 changed files with 68 additions and 90 deletions
  1. 68 90
      examples/webxr_xr_haptics.html

+ 68 - 90
examples/webxr_xr_haptics.html

@@ -30,45 +30,17 @@
 
 			let container;
 			let camera, scene, renderer;
+
+			let listener;
 			let controller1, controller2;
 			let controllerGrip1, controllerGrip2;
+
 			const box = new THREE.Box3();
 
-			const controllers = [];
-			const oscillators = [];
 			let controls, group;
-			let audioCtx = null;
-
-			// minor pentatonic scale, so whichever notes is stricken would be more pleasant
-			const musicScale = [ 0, 3, 5, 7, 10 ];
 
 			init();
 
-			function initAudio() {
-
-				if ( audioCtx !== null ) {
-
-					return;
-
-				}
-
-				audioCtx = new ( window.AudioContext || window.webkitAudioContext )();
-				function createOscillator() {
-
-					// creates oscillator
-					const oscillator = audioCtx.createOscillator();
-					oscillator.type = 'sine'; // possible values: sine, triangle, square
-					oscillator.start();
-					return oscillator;
-
-				}
-
-				oscillators.push( createOscillator() );
-				oscillators.push( createOscillator() );
-				window.oscillators = oscillators;
-
-			}
-
 			function init() {
 
 				container = document.createElement( 'div' );
@@ -80,6 +52,9 @@
 				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 10 );
 				camera.position.set( 0, 1.6, 3 );
 
+				listener = new THREE.AudioListener();
+				camera.add( listener );
+
 				controls = new OrbitControls( camera, container );
 				controls.target.set( 0, 1.6, 0 );
 				controls.update();
@@ -140,7 +115,6 @@
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setAnimationLoop( animate );
-				renderer.xr.addEventListener( 'sessionstart', () => initAudio() );
 				renderer.shadowMap.enabled = true;
 				renderer.xr.enabled = true;
 				container.appendChild( renderer.domElement );
@@ -175,25 +149,31 @@
 
 			}
 
-			function controllerConnected( evt ) {
+			function controllerConnected( event ) {
 
-				controllers.push( {
-					gamepad: evt.data.gamepad,
-					grip: evt.target,
-					colliding: false,
-					playing: false
-				} );
+				const oscillator = listener.context.createOscillator();
+				oscillator.type = 'sine';
+				oscillator.start()
 
-			}
+				const audio = new THREE.PositionalAudio( listener );
+				audio.setNodeSource( oscillator );
+				audio.setRefDistance( 20 );
+				audio.setVolume( 0 );
 
-			function controllerDisconnected( evt ) {
+				this.userData.gamepad = event.data.gamepad;
+				this.userData.colliding = false;
+				this.userData.audio = audio;
 
-				const index = controllers.findIndex( o => o.controller === evt.target );
-				if ( index !== - 1 ) {
+				this.add( audio );
 
-					controllers.splice( index, 1 );
+			}
 
-				}
+			function controllerDisconnected( event ) {
+
+				const audio = this.userData.audio;
+				audio.source.stop();
+				
+				this.remove( audio );
 
 			}
 
@@ -206,9 +186,8 @@
 
 			}
 
-			//
 
-			function handleCollisions() {
+			function handleCollisions( controller ) {
 
 				for ( let i = 0; i < group.children.length; i ++ ) {
 
@@ -216,78 +195,77 @@
 
 				}
 
-				for ( let g = 0; g < controllers.length; g ++ ) {
-
-					const controller = controllers[ g ];
-					controller.colliding = false;
-
-					const { grip, gamepad } = controller;
-					const sphere = {
-						radius: 0.03,
-						center: grip.position
-					};
+				handleController( controllerGrip1 );
+				handleController( controllerGrip2 );
 
-					const supportHaptic = 'hapticActuators' in gamepad && gamepad.hapticActuators != null && gamepad.hapticActuators.length > 0;
+				for ( let i = 0; i < group.children.length; i ++ ) {
 
-					for ( let i = 0; i < group.children.length; i ++ ) {
+					const child = group.children[ i ];
+					if ( ! child.collided ) {
 
-						const child = group.children[ i ];
-						box.setFromObject( child );
-						if ( box.intersectsSphere( sphere ) ) {
+						// reset uncollided boxes
+						child.material.emissive.b = 0;
+						child.scale.setScalar( 1 );
 
-							child.material.emissive.b = 1;
-							const intensity = child.userData.index / group.children.length;
-							child.scale.setScalar( 1 + Math.random() * 0.1 * intensity );
+					}
 
-							if ( supportHaptic ) {
+				}
 
-								gamepad.hapticActuators[ 0 ].pulse( intensity, 100 );
+			}
 
-							}
+			// minor pentatonic scale, so whichever notes is stricken would be more pleasant
+			const musicScale = [ 0, 3, 5, 7, 10 ];
 
-							const musicInterval = musicScale[ child.userData.index % musicScale.length ] + 12 * Math.floor( child.userData.index / musicScale.length );
-							oscillators[ g ].frequency.value = 110 * Math.pow( 2, musicInterval / 12 );
-							controller.colliding = true;
-							group.children[ i ].collided = true;
+			function handleController( controller ) {
 
-						}
+				controller.userData.colliding = false;
 
-					}
+				const audio = controller.userData.audio;
+				const gamepad = controller.userData.gamepad;
 
+				if ( audio === undefined || gamepad === undefined ) return;
 
+				const oscillator = audio.source;
+				const supportHaptic = 'hapticActuators' in gamepad && gamepad.hapticActuators != null && gamepad.hapticActuators.length > 0;
 
-					if ( controller.colliding ) {
+				const sphere = {
+					radius: 0.03,
+					center: controller.position
+				};
 
-						if ( ! controller.playing ) {
+				for ( let i = 0; i < group.children.length; i ++ ) {
 
-							controller.playing = true;
-							oscillators[ g ].connect( audioCtx.destination );
+					const child = group.children[ i ];
+					box.setFromObject( child );
 
-						}
+					if ( box.intersectsSphere( sphere ) ) {
 
-					} else {
+						child.material.emissive.b = 1;
+						const intensity = child.userData.index / group.children.length;
+						child.scale.setScalar( 1 + Math.random() * 0.1 * intensity );
 
-						if ( controller.playing ) {
+						if ( supportHaptic ) {
 
-							controller.playing = false;
-							oscillators[ g ].disconnect( audioCtx.destination );
+							gamepad.hapticActuators[ 0 ].pulse( intensity, 100 );
 
 						}
 
+						const musicInterval = musicScale[ child.userData.index % musicScale.length ] + 12 * Math.floor( child.userData.index / musicScale.length );
+						oscillator.frequency.value = 110 * Math.pow( 2, musicInterval / 12 );
+						controller.userData.colliding = true;
+						group.children[ i ].collided = true;
+
 					}
 
 				}
 
-				for ( let i = 0; i < group.children.length; i ++ ) {
+				if ( controller.userData.colliding ) {
 
-					const child = group.children[ i ];
-					if ( ! child.collided ) {
+					audio.setVolume( 0.5 );
 
-						// reset uncollided boxes
-						child.material.emissive.b = 0;
-						child.scale.setScalar( 1 );
+				} else {
 
-					}
+					audio.setVolume( 0 );
 
 				}
 

粤ICP备19079148号