Browse Source

Merge pull request #14243 from Mugen87/dev12

PositionalAudio: Added orientation
Mr.doob 7 years ago
parent
commit
f13c5d7916
3 changed files with 262 additions and 2 deletions
  1. 1 0
      examples/files.js
  2. 250 0
      examples/webaudio_orientation.html
  3. 11 2
      src/audio/PositionalAudio.js

+ 1 - 0
examples/files.js

@@ -313,6 +313,7 @@ var files = {
 	],
 	],
 	*/
 	*/
 	"webaudio": [
 	"webaudio": [
+		"webaudio_orientation",
 		"webaudio_sandbox",
 		"webaudio_sandbox",
 		"webaudio_timing",
 		"webaudio_timing",
 		"webaudio_visualizer"
 		"webaudio_visualizer"

+ 250 - 0
examples/webaudio_orientation.html

@@ -0,0 +1,250 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webaudio - orientation</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				background:#777;
+				padding:0;
+				margin:0;
+				overflow:hidden;
+				font-family: Monospace;
+			}
+
+			#info {
+				position: absolute;
+				z-index: 2;
+				top: 0px;
+				width: 100%;
+				color: #ffffff;
+				padding: 5px;
+
+				font-size:13px;
+				text-align:center;
+				font-weight: bold;
+			}
+
+			a {
+				color: #ffffff;
+			}
+
+			#overlay {
+				position: absolute;
+				z-index: 1;
+				top: 0;
+				left: 0;
+				width: 100%;
+				height:100%;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				opacity: 1;
+				background-color: #000000;
+				color: #ffffff;
+			}
+
+			#overlay > div {
+				text-align: center;
+			}
+
+			#overlay > div > button {
+				height: 20px;
+				width: 100px;
+				background: transparent;
+				color: #ffffff;
+				outline: 1px solid #ffffff;
+				border: 0px;
+				cursor: pointer;
+			}
+
+			#overlay > div > p {
+				color: #777777;
+				font-size: 12px;
+			}
+
+		</style>
+
+		<script src="../build/three.js"></script>
+		<script src="js/Detector.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/loaders/GLTFLoader.js"></script>
+
+	</head>
+<body>
+
+	<audio loop id="music" preload="auto" style="display: none">
+		<source src="sounds/376737_Skullbeatz___Bad_Cat_Maste.ogg" type="audio/ogg">
+		<source src="sounds/376737_Skullbeatz___Bad_Cat_Maste.mp3" type="audio/mpeg">
+	</audio>
+
+	<div id="overlay">
+		<div>
+			<button id="startButton">Click to Play</button>
+			<p>Automatic audio playback requires a user interaction.</p>
+		</div>
+	</div>
+	<div id="container"></div>
+	<div id="info">
+		<a href="https://threejs.org" target="_blank" rel="noopener noreferrer">three.js</a> webaudio orientation |
+		music by <a href="http://www.newgrounds.com/audio/listen/376737" target="_blank" rel="noopener noreferrer">skullbeatz</a>
+	</div>
+
+	<script>
+
+	if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+	var scene, camera, renderer;
+
+	var startButton = document.getElementById( 'startButton' );
+	startButton.addEventListener( 'click', init );
+
+	function init() {
+
+		var overlay = document.getElementById( 'overlay' );
+		overlay.remove();
+
+		var container = document.getElementById( 'container' );
+
+		//
+
+		camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 100 );
+		camera.position.set( 0, 1, 2 );
+
+		var reflectionCube = new THREE.CubeTextureLoader()
+			.setPath( 'textures/cube/SwedishRoyalCastle/' )
+			.load( [ 'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ] );
+		reflectionCube.format = THREE.RGBFormat;
+
+		scene = new THREE.Scene();
+		scene.background = new THREE.Color( 0xa0a0a0 );
+		scene.fog = new THREE.Fog( 0xa0a0a0, 2, 20 );
+
+		//
+
+		light = new THREE.HemisphereLight( 0xffffff, 0x444444 );
+		light.position.set( 0, 200, 0 );
+		scene.add( light );
+
+		light = new THREE.DirectionalLight( 0xffffff );
+		light.position.set( 0, 200, 100 );
+		light.castShadow = true;
+		light.shadow.camera.top = 180;
+		light.shadow.camera.bottom = -100;
+		light.shadow.camera.left = -120;
+		light.shadow.camera.right = 120;
+		scene.add( light );
+
+		//
+
+		var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20, 20 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) );
+		mesh.rotation.x = - Math.PI / 2;
+		mesh.receiveShadow = true;
+		scene.add( mesh );
+
+		var grid = new THREE.GridHelper( 20, 20, 0x000000, 0x000000 );
+		grid.material.opacity = 0.2;
+		grid.material.transparent = true;
+		scene.add( grid );
+
+		//
+
+		var audioLoader = new THREE.AudioLoader();
+
+		var listener = new THREE.AudioListener();
+		camera.add( listener );
+
+		var audioElement = document.getElementById( 'music' );
+
+		var positionalAudio = new THREE.PositionalAudio( listener );
+		positionalAudio.setMediaElementSource( audioElement );
+		positionalAudio.setRefDistance( 1 );
+
+		// configure directionality cone, see https://developer.mozilla.org/en-US/docs/Web/API/PannerNode
+
+		positionalAudio.panner.coneInnerAngle = 210;
+		positionalAudio.panner.coneOuterAngle = 230;
+		positionalAudio.panner.coneOuterGain = 0.1;
+
+		//
+
+		var gltfLoader = new THREE.GLTFLoader();
+		gltfLoader.load( 'models/gltf/BoomBox/glTF-Binary/BoomBox.glb', function( gltf ) {
+
+			boomBox =  gltf.scene;
+			boomBox.position.set( 0, 0.2, 0 );
+			boomBox.scale.set( 20, 20, 20 );
+
+			boomBox.traverse( function( object ) {
+
+				if ( object.isMesh ) {
+
+					object.material.envMap = reflectionCube;
+					object.geometry.rotateY( - Math.PI );
+
+				}
+
+			} );
+
+			audioElement.play();
+			boomBox.add( positionalAudio );
+			scene.add( boomBox );
+			animate();
+
+		} );
+
+		// sound is damped behind this wall
+
+		var wallGeometry = new THREE.BoxBufferGeometry( 2, 1, 0.1 );
+		var wallMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
+
+		var wall = new THREE.Mesh( wallGeometry, wallMaterial );
+		wall.position.set( 0, 0.5, - 0.5 );
+		scene.add( wall );
+
+
+		//
+
+		renderer = new THREE.WebGLRenderer( { antialias: true } );
+		renderer.setSize( window.innerWidth, window.innerHeight );
+		renderer.setPixelRatio( window.devicePixelRatio );
+		container.appendChild( renderer.domElement );
+
+		renderer.gammaOutput = true;
+
+		//
+
+		var controls = new THREE.OrbitControls( camera, renderer.domElement );
+		controls.target.set( 0, 0.1, 0 );
+		controls.update();
+		controls.minDistance = 0.5;
+		controls.maxDistance = 10;
+		controls.maxPolarAngle = 0.5 * Math.PI;
+
+		//
+
+		window.addEventListener( 'resize', onWindowResize, false );
+
+	}
+
+	function onWindowResize( event ) {
+
+		camera.aspect = window.innerWidth / window.innerHeight;
+		camera.updateProjectionMatrix();
+
+		renderer.setSize( window.innerWidth, window.innerHeight );
+
+	}
+
+	function animate() {
+
+		requestAnimationFrame( animate );
+		renderer.render( scene, camera );
+
+	}
+
+	</script>
+
+</body>
+</html>

+ 11 - 2
src/audio/PositionalAudio.js

@@ -3,6 +3,7 @@
  */
  */
 
 
 import { Vector3 } from '../math/Vector3.js';
 import { Vector3 } from '../math/Vector3.js';
+import { Quaternion } from '../math/Quaternion.js';
 import { Audio } from './Audio.js';
 import { Audio } from './Audio.js';
 import { Object3D } from '../core/Object3D.js';
 import { Object3D } from '../core/Object3D.js';
 
 
@@ -76,14 +77,22 @@ PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {
 	updateMatrixWorld: ( function () {
 	updateMatrixWorld: ( function () {
 
 
 		var position = new Vector3();
 		var position = new Vector3();
+		var quaternion = new Quaternion();
+		var scale = new Vector3();
+
+		var orientation = new Vector3();
 
 
 		return function updateMatrixWorld( force ) {
 		return function updateMatrixWorld( force ) {
 
 
 			Object3D.prototype.updateMatrixWorld.call( this, force );
 			Object3D.prototype.updateMatrixWorld.call( this, force );
 
 
-			position.setFromMatrixPosition( this.matrixWorld );
+			var panner = this.panner;
+			this.matrixWorld.decompose( position, quaternion, scale );
+
+			orientation.set( 0, 0, 1 ).applyQuaternion( quaternion );
 
 
-			this.panner.setPosition( position.x, position.y, position.z );
+			panner.setPosition( position.x, position.y, position.z );
+			panner.setOrientation( orientation.x, orientation.y, orientation.z );
 
 
 		};
 		};