提交 74157593 编写于 作者: A alteredq

Added 3d sound support plus example.

Thanks to @mikaelemtinger ;)
上级 47d69fe4
因为 它太大了无法显示 source diff 。你可以改为 查看blob
/**
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
* @author paulirish / http://paulirish.com/
*/
function bind( scope, fn ) {
return function () {
fn.apply( scope, arguments );
};
}
CameraControlWASD = function ( camera, movement_speed, look_speed, nofly, look_vertical ) {
this.movement_speed = movement_speed !== undefined ? movement_speed : 1.0;
this.look_speed = look_speed !== undefined ? look_speed : 0.005;
this.nofly = nofly;
this.look_vertical = look_vertical;
this.camera = camera;
this.mouseX = 0;
this.mouseY = 0;
this.lat = 0;
this.lon = 0;
this.phy = 0;
this.theta = 0;
this.moveForward = false;
this.moveBackward = false;
this.moveLeft = false;
this.moveRight = false;
this.windowHalfX = window.innerWidth / 2;
this.windowHalfY = window.innerHeight / 2;
this.onDocumentMouseDown = function ( event ) {
event.preventDefault();
event.stopPropagation();
switch ( event.button ) {
case 0: this.moveForward = true; break;
case 2: this.moveBackward = true; break;
}
};
this.onDocumentMouseUp = function ( event ) {
event.preventDefault();
event.stopPropagation();
switch ( event.button ) {
case 0: this.moveForward = false; break;
case 2: this.moveBackward = false; break;
}
};
this.onDocumentMouseMove = function (event) {
this.mouseX = event.clientX - this.windowHalfX;
this.mouseY = event.clientY - this.windowHalfY;
};
this.onDocumentKeyDown = function ( event ) {
switch( event.keyCode ) {
case 38: /*up*/
case 87: /*W*/ this.moveForward = true; break;
case 37: /*left*/
case 65: /*A*/ this.moveLeft = true; break;
case 40: /*down*/
case 83: /*S*/ this.moveBackward = true; break;
case 39: /*right*/
case 68: /*D*/ this.moveRight = true; break;
}
};
this.onDocumentKeyUp = function ( event ) {
switch( event.keyCode ) {
case 38: /*up*/
case 87: /*W*/ this.moveForward = false; break;
case 37: /*left*/
case 65: /*A*/ this.moveLeft = false; break;
case 40: /*down*/
case 83: /*S*/ this.moveBackward = false; break;
case 39: /*right*/
case 68: /*D*/ this.moveRight = false; break;
}
};
this.update = function() {
if ( this.moveForward ) this.camera.translateZ( - this.movement_speed, this.nofly );
if ( this.moveBackward ) this.camera.translateZ( this.movement_speed, this.nofly );
if ( this.moveLeft ) this.camera.translateX( - this.movement_speed, this.nofly );
if ( this.moveRight ) this.camera.translateX( this.movement_speed, this.nofly );
this.lon += this.mouseX * this.look_speed;
if( this.look_vertical ) this.lat -= this.mouseY * this.look_speed;
this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
this.phi = ( 90 - this.lat ) * Math.PI / 180;
this.theta = this.lon * Math.PI / 180;
this.camera.target.position.x = 100 * Math.sin( this.phi ) * Math.cos( this.theta ) + this.camera.position.x;
this.camera.target.position.y = 100 * Math.cos( this.phi ) + this.camera.position.y;
this.camera.target.position.z = 100 * Math.sin( this.phi ) * Math.sin( this.theta ) + this.camera.position.z;
};
document.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
document.addEventListener( 'mousemove', bind( this, this.onDocumentMouseMove ), false );
document.addEventListener( 'mousedown', bind( this, this.onDocumentMouseDown ), false );
document.addEventListener( 'mouseup', bind( this, this.onDocumentMouseUp ), false );
document.addEventListener( 'keydown', bind( this, this.onDocumentKeyDown ), false );
document.addEventListener( 'keyup', bind( this, this.onDocumentKeyUp ), false );
};
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>three.js - misc - sound</title>
<meta charset="utf-8">
<style type="text/css">
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
font-family:Monospace;
font-size:13px;
text-align:center;
font-weight: bold;
text-align:center;
}
a {
color:#0078ff;
}
#info {
color:#fff;
position: absolute;
top: 0px; width: 100%;
padding: 5px;
z-index:100;
}
</style>
</head>
<body>
<div id="info">
<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - webgl 3d sounds example -
music by <a href="http://www.newgrounds.com/audio/listen/358232" target="_blank">larrylarrybb</a> and
<a href="http://www.newgrounds.com/audio/listen/376737" target="_blank">skullbeatz</a> <br/><br/>
navigate with WASD / arrows / mouse
</div>
<div id="container"></div>
<script type="text/javascript" src="js/ThreeSound.js"></script>
<script type="text/javascript" src="js/CameraControl.js"></script>
<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
<script type="text/javascript" src="js/Detector.js"></script>
<script type="text/javascript" src="js/Stats.js"></script>
<script type="text/javascript">
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, scene, renderer, soundRenderer;
var light, pointLight;
var cameraControl;
var mesh;
var material_sphere1, material_sphere2;
var postprocessing = { enabled: true };
init();
animate();
function init() {
container = document.getElementById( 'container' );
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0x000000, 0.0035 );
camera = new THREE.Camera( 50, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 0, 25, 0 );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 0.5, 1 );
light.position.normalize();
scene.addLight( light );
var sphere = new Sphere( 20, 32, 16 );
material_sphere1 = new THREE.MeshLambertMaterial( { color: 0xffaa00, shading: THREE.FlatShading } );
material_sphere2 = new THREE.MeshLambertMaterial( { color: 0xff2200, shading: THREE.FlatShading } );
var cube = new Cube( 5, 40, 5 );
var material_cube = new THREE.MeshLambertMaterial( { color: 0xffff00, shading: THREE.FlatShading } );
material_cube.color.setHSV( 0.1, 0.7, 1 );
// sound spheres
var s = 1;
var mesh1 = new THREE.Mesh( sphere, material_sphere1 );
mesh1.position.set( -250, 30, 0 );
mesh1.scale.set( s, s, s );
var sound1 = new THREE.Sound3D( [ "sounds/358232_j_s_song.mp3", "sounds/358232_j_s_song.ogg" ] , 275, 20, true );
//var sound1 = new THREE.Sound3D( "sounds/358232_j_s_song.ogg", 275, 20, true );
sound1.play();
var dbg = new THREE.Mesh( cube, material_cube );
dbg.position.set( 0, -10 ,0 );
mesh1.addChild( dbg );
mesh1.addChild( sound1 );
scene.addObject( mesh1 );
var mesh2 = new THREE.Mesh( sphere, material_sphere2 );
mesh2.position.set( 250, 30, 0 );
mesh2.scale.set( s, s, s );
var sound2 = new THREE.Sound3D( [ "sounds/376737_Skullbeatz___Bad_Cat_Maste.mp3", "sounds/376737_Skullbeatz___Bad_Cat_Maste.ogg" ], 275, 20, true );
//var sound2 = new THREE.Sound3D( "sounds/376737_Skullbeatz___Bad_Cat_Maste.ogg", 275, 20, true );
sound2.play();
var dbg = new THREE.Mesh( cube, material_cube );
dbg.position.set( 0, -10, 0 );
mesh2.addChild( dbg );
mesh2.addChild( sound2 );
scene.addObject( mesh2 );
// ground
var material_wireframe = new THREE.MeshLambertMaterial( { color: 0xffaa00, wireframe: true, wireframe_linewidth: 1 } );
material_wireframe.color.setHSV( 0.1, 0.2, 0.25 );
var plane = new Plane( 1000, 1000, 100, 100 );
mesh = new THREE.Mesh( plane, material_wireframe );
mesh.position.y = 0.1;
mesh.rotation.x = -1.57;
scene.addObject( mesh );
renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1 } );
renderer.setSize( window.innerWidth, window.innerHeight );
soundRenderer = new THREE.SoundRenderer();
container.innerHTML = "";
container.appendChild( renderer.domElement );
container.appendChild( soundRenderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
//container.appendChild( stats.domElement );
cameraControl = new CameraControlWASD( camera, 1, 0.002, true, false );
initPostprocessing();
renderer.autoClear = false;
}
function initPostprocessing() {
postprocessing.scene = new THREE.Scene();
postprocessing.camera = new THREE.Camera();
postprocessing.camera.projectionMatrix = THREE.Matrix4.makeOrtho( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, -10000, 10000 );
postprocessing.camera.position.z = 100;
var pars = { min_filter: THREE.LinearFilter, mag_filter: THREE.LinearFilter };
postprocessing.rtTexture1 = new THREE.RenderTarget( window.innerWidth, window.innerHeight, pars );
postprocessing.rtTexture2 = new THREE.RenderTarget( 512, 512, pars );
postprocessing.rtTexture3 = new THREE.RenderTarget( 512, 512, pars );
var screen_shader = ShaderUtils.lib["screen"];
var screen_uniforms = Uniforms.clone( screen_shader.uniforms );
screen_uniforms["tDiffuse"].texture = postprocessing.rtTexture1;
screen_uniforms["opacity"].value = 1.0;
postprocessing.materialScreen = new THREE.MeshShaderMaterial( {
uniforms: screen_uniforms,
vertex_shader: screen_shader.vertex_shader,
fragment_shader: screen_shader.fragment_shader,
blending: THREE.AdditiveBlending
} );
var convolution_shader = ShaderUtils.lib["convolution"];
var convolution_uniforms = Uniforms.clone( convolution_shader.uniforms );
postprocessing.blurx = new THREE.Vector2( 0.001953125, 0.0 ),
postprocessing.blury = new THREE.Vector2( 0.0, 0.001953125 );
convolution_uniforms["tDiffuse"].texture = postprocessing.rtTexture1;
convolution_uniforms["uImageIncrement"].value = postprocessing.blurx;
convolution_uniforms["cKernel"].value = ShaderUtils.buildKernel( 4.0 );
postprocessing.materialConvolution = new THREE.MeshShaderMaterial( {
uniforms: convolution_uniforms,
vertex_shader: "#define KERNEL_SIZE 25.0\n" + convolution_shader.vertex_shader,
fragment_shader: "#define KERNEL_SIZE 25\n" + convolution_shader.fragment_shader
} );
postprocessing.quad = new THREE.Mesh( new Plane( window.innerWidth, window.innerHeight ), postprocessing.materialConvolution );
postprocessing.quad.position.z = -500;
postprocessing.scene.addObject( postprocessing.quad );
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
var time = new Date().getTime() * 0.005;
material_sphere1.color.setHSV( 0.0, 0.3 + 0.7 * ( 1 + Math.cos(time) ) / 2, 1 );
material_sphere2.color.setHSV( 0.1, 0.3 + 0.7 * ( 1 + Math.sin(time) ) / 2, 1 );
cameraControl.update();
if ( postprocessing.enabled ) {
renderer.clear();
// Render scene into texture
renderer.render( scene, camera, postprocessing.rtTexture1 );
// Render quad with blured scene into texture (convolution pass 1)
postprocessing.quad.materials = [ postprocessing.materialConvolution ];
postprocessing.materialConvolution.uniforms.tDiffuse.texture = postprocessing.rtTexture1;
postprocessing.materialConvolution.uniforms.uImageIncrement.value = postprocessing.blurx;
renderer.render( postprocessing.scene, postprocessing.camera, postprocessing.rtTexture2 );
// Render quad with blured scene into texture (convolution pass 2)
postprocessing.materialConvolution.uniforms.tDiffuse.texture = postprocessing.rtTexture2;
postprocessing.materialConvolution.uniforms.uImageIncrement.value = postprocessing.blury;
renderer.render( postprocessing.scene, postprocessing.camera, postprocessing.rtTexture3 );
// Render original scene with superimposed blur to texture
postprocessing.quad.materials = [ postprocessing.materialScreen ];
postprocessing.materialScreen.uniforms.tDiffuse.texture = postprocessing.rtTexture3;
postprocessing.materialScreen.uniforms.opacity.value = 1.3;
renderer.render( postprocessing.scene, postprocessing.camera, postprocessing.rtTexture1, false );
// Render to screen
postprocessing.materialScreen.uniforms.tDiffuse.texture = postprocessing.rtTexture1;
renderer.render( postprocessing.scene, postprocessing.camera );
} else {
renderer.clear();
renderer.render( scene, camera );
}
soundRenderer.render( scene, camera );
}
</script>
</body>
</html>
Music from Newgrounds Audio portal, licensed under
Creative Commons Attribution Noncommercial Share Alike
Bad Cat [Master Version] by Skullbeatz
http://www.newgrounds.com/audio/listen/376737
The Sound of Epicness by larrylarrybb
http://www.newgrounds.com/audio/listen/358232
\ No newline at end of file
......@@ -24,11 +24,13 @@ THREE.Camera = function( FOV, aspect, zNear, zFar, renderer, target ) {
this.tmpVec = new THREE.Vector3();
this.translateX = function ( amount ) {
this.translateX = function ( amount, nofly ) {
this.tmpVec.sub( this.target.position, this.position ).normalize().multiplyScalar( amount );
this.tmpVec.crossSelf( this.up );
if ( nofly ) this.tmpVec.y = 0;
this.position.addSelf( this.tmpVec );
this.target.position.addSelf( this.tmpVec );
......@@ -40,10 +42,12 @@ THREE.Camera = function( FOV, aspect, zNear, zFar, renderer, target ) {
};
*/
this.translateZ = function ( amount ) {
this.translateZ = function ( amount, nofly ) {
this.tmpVec.sub( this.target.position, this.position ).normalize().multiplyScalar( amount );
if ( nofly ) this.tmpVec.y = 0;
this.position.subSelf( this.tmpVec );
this.target.position.subSelf( this.tmpVec );
......
......@@ -591,6 +591,14 @@ THREE.Matrix4.prototype = {
},
extractPositionVector: function( v ) {
v.x = this.n14;
v.y = this.n24;
v.z = this.n34;
},
toString: function() {
return "| " + this.n11 + " " + this.n12 + " " + this.n13 + " " + this.n14 + " |\n" +
......
/**
* @author mikael emtinger / http://gomo.se/
*/
THREE.Sound3D = function( sources, radius, volume, loop ) {
THREE.Object3D.call( this );
// flags
this.isLoaded = false;
this.isAddedToDOM = false;
this.isPlaying = false;
this.duration = -1;
this.radius = radius !== undefined ? Math.abs( radius ) : 100;
this.volume = Math.min( 1, Math.max( 0, volume !== undefined ? volume : 1 ) );
// dom
this.domElement = document.createElement( "audio" );
this.domElement.volume = 0;
this.domElement.pan = 0;
this.domElement.loop = loop !== undefined ? loop : true;
// init sources
this.sources = sources instanceof Array ? sources : [ sources ];
var element, source, type,
s, sl = this.sources.length;
for( s = 0; s < sl; s++ ) {
source = this.sources[ s ];
source.toLowerCase();
if( source.indexOf( ".mp3" ) !== -1 ) type = "audio/mpeg";
else if( source.indexOf( ".ogg" ) !== -1 ) type = "audio/ogg";
else if( source.indexOf( ".wav" ) !== -1 ) type = "audio/wav";
if( this.domElement.canPlayType( type ) ) {
element = document.createElement( "source" );
element.src = this.sources[ s ];
this.domElement.THREESound3D = this;
this.domElement.appendChild( element );
this.domElement.addEventListener( "canplay", this.onLoad, true );
this.domElement.load();
break;
}
}
};
THREE.Sound3D.prototype = new THREE.Object3D();
THREE.Sound3D.prototype.constructor = THREE.Sound3D;
THREE.Sound3D.prototype.supr = THREE.Object3D.prototype;
/*
* OnLoad
*/
THREE.Sound3D.prototype.onLoad = function( ) {
var sound3D = this.THREESound3D;
if( sound3D.isLoaded )
return;
this.removeEventListener( "canplay", this.onLoad, true );
sound3D.isLoaded = true;
sound3D.duration = this.duration;
if( sound3D.isPlaying )
sound3D.play();
};
/*
* Add To DOM
*/
THREE.Sound3D.prototype.addToDOM = function( parent ) {
this.isAddedToDOM = true;
parent.appendChild( this.domElement );
};
/*
* Play
*/
THREE.Sound3D.prototype.play = function( startTime ) {
this.isPlaying = true;
if( this.isLoaded ) {
this.domElement.play();
if( startTime )
this.domElement.currentTime = startTime % this.duration;
}
};
/*
* Pause
*/
THREE.Sound3D.prototype.pause = function() {
this.isPlaying = false;
this.domElement.pause();
};
/*
* Stop
*/
THREE.Sound3D.prototype.stop = function(){
this.isPlaying = false;
this.domElement.pause();
this.domElement.currentTime = 0;
};
/*
* Calculate Volume and Pan
*/
THREE.Sound3D.prototype.calculateVolumeAndPan = function( cameraRelativePosition ) {
var distance = cameraRelativePosition.length();
if( distance <= this.radius )
this.domElement.volume = this.volume * ( 1 - distance / this.radius );
else
this.domElement.volume = 0;
};
/*
* Update
*/
THREE.Sound3D.prototype.update = function( parentGlobalMatrix, forceUpdate, camera ) {
// update local (rotation/scale is not used)
if( this.matrixAutoUpdate ) {
this.localMatrix.setPosition( this.position );
forceUpdate = true;
}
// update global
if( forceUpdate || this.matrixNeedsUpdate ) {
if( parentGlobalMatrix )
this.globalMatrix.multiply( parentGlobalMatrix, this.localMatrix );
else
this.globalMatrix.copy( this.localMatrix );
this.matrixNeedsUpdate = false;
forceUpdate = true;
}
// update children
var i, l = this.children.length;
for( i = 0; i < l; i++ )
this.children[ i ].update( this.globalMatrix, forceUpdate, camera );
};
/**
* @author mikael emtinger / http://gomo.se/
*/
THREE.SoundRenderer = function() {
this.volume = 1;
this.domElement = document.createElement( "div" );
this.domElement.id = "THREESound";
this.cameraPosition = new THREE.Vector3();
this.soundPosition = new THREE.Vector3();
/*
* Render
*/
this.render = function( scene, camera, callSceneUpdate ) {
if( callSceneUpdate )
scene.update( undefined, false, camera );
// loop through all sounds
var sound;
var sounds = scene.sounds;
var s, l = sounds.length;
//camera.globalMatrix.extractPositionVector( this.cameraPosition );
for( s = 0; s < l; s++ ) {
sound = sounds[ s ];
sound.globalMatrix.extractPositionVector( this.soundPosition );
this.soundPosition.subSelf( camera.position );
if( sound.isPlaying && sound.isLoaded ) {
if( !sound.isAddedToDOM )
sound.addToDOM( this.domElement );
sound.calculateVolumeAndPan( this.soundPosition );
}
}
}
}
......@@ -13,6 +13,7 @@ THREE.Scene = function() {
this.objects = [];
this.lights = [];
this.sounds = [];
this.fog = null;
};
......@@ -34,12 +35,16 @@ THREE.Scene.prototype.addChild = function( child ) {
THREE.Scene.prototype.addChildRecurse = function( child ) {
if( child instanceof THREE.Light ) {
if( this.lights.indexOf( child ) === -1 )
this.lights.push( child );
} else if( child instanceof THREE.Sound3D ) {
if( this.sounds.indexOf( child ) === -1 )
this.sounds.push( child );
} else if( !( child instanceof THREE.Camera || child instanceof THREE.Bone ) ) {
if( this.objects.indexOf( child ) === -1 )
......@@ -73,6 +78,13 @@ THREE.Scene.prototype.removeChildRecurse = function( child ) {
if( i !== -1 )
this.lights.splice( i, 1 );
} else if( child instanceof THREE.Sound3D ) {
var i = this.sounds.indexOf( child );
if( i !== -1 )
this.sounds.splice( i, 1 );
} else if( !( child instanceof THREE.Camera ) ) {
var i = this.objects.indexOf( child );
......
......@@ -64,6 +64,7 @@ COMMON_FILES = [
'objects/Bone.js',
'objects/SkinnedMesh.js',
'objects/Ribbon.js',
'objects/Sound3D.js',
'scenes/Scene.js',
'scenes/Fog.js',
'scenes/FogExp2.js',
......@@ -72,6 +73,7 @@ COMMON_FILES = [
'renderers/CanvasRenderer.js',
'renderers/SVGRenderer.js',
'renderers/WebGLRenderer.js',
'renderers/SoundRenderer.js',
'renderers/renderables/RenderableObject.js',
'renderers/renderables/RenderableFace3.js',
'renderers/renderables/RenderableParticle.js',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册