Babylon.js声音引擎基于Web Audio规范。官方不决定提供音频标签和其他回退的备用机制。因此,要使用声音引擎,必须使用与Web Audio兼容的浏览器(一般支持WebGL的浏览器都支持)。尽管如此,如果你在不兼容的浏览器上使用,也不会出现异样,只是没有声音播放而已。声音引擎提供背景音频(ambient sound),空间音频(spatialized sound)和定向音频(directional sound)。它可以通过代码或者加载.babylon文件来创建。它将遵循您将要看到的引擎其它部分一样的简单而强大的理念。支持的音频格式是浏览器支持的音频格式。它通常是.mp3和.wav。
一下是创建声音或音乐为背景声音(非空间化)的代码:
// 加载一个声音并自动循化播放
var music = new BABYLON.Sound("Music", "music.wav", scene, null, { loop: true, autoplay: true });
您可以在官网查看第一个最普通的示例:点击这里
使用BABYLON.Sound()构造函数加载音频会产出两个阶段:
这是一个普通的代码:
var music = new BABYLON.Sound("Music", "music.wav", scene,
function () {
// 音频在被下载和解析之后
music.play();
}
);
如果你点击鼠标左键或者键盘空格键,这个示例代码会发出枪声:
var gunshot = new BABYLON.Sound("gunshot", "sounds/gunshot.wav", scene);
window.addEventListener("mousedown", function (evt) {
//鼠标左键单击
if (evt.button === 0) {
gunshot.play();
}
});
window.addEventListener("keydown", function (evt) {
// 敲击空格键
if (evt.keyCode === 32) {
gunshot.play();
}
});
你可以通过配置选项或者通过setVolume()
函数设置声音的音量。你可以通过相同的方式设置声音的播放速率。
你可以设置onended
回调在声音已经播放完毕时,自动触发。
这是一个设置两项的一个基本示例代码:
var volume = 0.1;
var playbackRate = 0.5;
var gunshot = new BABYLON.Sound("Gunshot", "./gunshot-1.wav", scene, null, { playbackRate: playbackRate, volume: volume });
gunshot.onended = function () {
if (volume < 1) {
volume += 0.1;
gunshot.setVolume(volume);
}
playbackRate += 0.1;
gunshot.playbackRate = playbackRate;
};
首先将速率设置为0.5和音量设置为0.1 。每次声音播放完成,将触发onended
函数,音量和播放速率都会增加。
你可以使用音频引擎的setGlobalVolume()
函数设置Babylon.js播放的所有声音的全局音量,而不是根据特定声音设置音量。
BABYLON.Engine.audioEngine.setGlobalVolume(0.5);
首先需要确定所有的音频文件已经加载成功,然后在所有的音频对象上调用play()
即可。
var music1 = new BABYLON.Sound("Violons11", "sounds/violons11.wav", scene,
soundReady, { loop: true });
var music2 = new BABYLON.Sound("Violons18", "sounds/violons18.wav", scene,
soundReady, { loop: true });
var music3 = new BABYLON.Sound("Cellolong", "sounds/cellolong.wav", scene,
soundReady, { loop: true });
var soundsReady = 0;
function soundReady() {
soundsReady++;
if (soundsReady === 3) {
music1.play();
music2.play();
music3.play();
}
}
如果你使用自己提供ArrayBuffer调用构造函数,则可以绕过第一个阶段(使用ajax请求文件)。
一下是示例代码:
var gunshotFromAB;
loadArrayBufferFromURL("sounds/gunshot.wav");
function loadArrayBufferFromURL(urlToSound) {
var request = new XMLHttpRequest();
request.open('GET', urlToSound, true);
request.responseType = "arraybuffer";
request.onreadystatechange = function () {
if (request.readyState == 4) {
if (request.status == 200) {
gunshotFromAB = new BABYLON.Sound("FromArrayBuffer", request.response, scene, soundReadyToBePlayed);
}
}
};
request.send(null);
}
function soundReadyToBePlayed() {
gunshotFromAB.play();
}
AssetsManager非常有用,因为它可以处理一些很棒的功能,比如屏幕加载
var music1, music2, music3;
// Assets manager
var assetsManager = new BABYLON.AssetsManager(scene);
var binaryTask = assetsManager.addBinaryFileTask("Violons18 task", "sounds/violons18.wav");
binaryTask.onSuccess = function (task) {
music1 = new BABYLON.Sound("Violons18", task.data, scene, soundReady, { loop: true });
}
var binaryTask2 = assetsManager.addBinaryFileTask("Violons11 task", "sounds/violons11.wav");
binaryTask2.onSuccess = function (task) {
music2 = new BABYLON.Sound("Violons11", task.data, scene, soundReady, { loop: true });
}
var binaryTask3 = assetsManager.addBinaryFileTask("Cello task", "sounds/cellolong.wav");
binaryTask3.onSuccess = function (task) {
music3 = new BABYLON.Sound("Cello", task.data, scene, soundReady, { loop: true });
}
var soundsReady = 0;
function soundReady() {
soundsReady++;
if (soundsReady === 3) {
music1.play();
music2.play();
music3.play();
}
}
assetsManager.load();
要将声音转换为空间声音,你需要通过选项指定:
var music = new BABYLON.Sound("music", "music.wav", scene, null, { loop: true, autoplay: true, spatialSound: true });
空间声音的默认属性是:
maxDistance仅在使用“ 线性 ”衰减时使用。否则,您可以使用rolloffFactor和refDistance选项调整其他模型的衰减。两者都默认设置为1,但您当然可以更改它。
例如:
var music = new BABYLON.Sound("music", "music.wav",
scene, null, {
loop: true, autoplay: true, spatialSound: true,
distanceModel: "exponential", rolloffFactor: 2
});
在场景中,声音的默认位置是原点(0,0,0)。要修改它,请使用setPosition()
函数:
music.setPosition(new BABYLON.Vector3(100, 0, 0));
为了更好的理解,请查看官方示例,
我们可以使用键盘和鼠标移动相机位置。每个声音都由一个紫色的球体表示。当接近一个球体时,你会听到一个音乐。距离球心距离越近,声音越大,反之,距离越远,声音越小。
这可能是处理场景中3D声音的最简单的方法。只需要创建一个BABYLON.Sound
,将其添加到现有的模型上面即可完成!如果网格正在移动,声音将随之移动。你根本不用整什么:
var music = new BABYLON.Sound("Violons", "sounds/violons11.wav", scene, null, { loop: true, autoplay: true });
// 声音将跟随着模型位置移动
music.attachToMesh(box);
在音频对象上调用attachToMesh()
函数会将其自动转换为空间3D声音。使用上面的代码,你将使用默认的配置:maxDistance
为100的声音线性衰减和“HRTF”类型的音频算法。
默认情况下,声音是向所有的方向传递的。如果你有需要,可以自定义方向传播的方向。
注意:定向声音只适合绑定到模型的声音。
示例代码:
var music = new BABYLON.Sound("Violons", "violons11.wav", scene, null, { loop: true, autoplay: true });
music.setDirectionalCone(90, 180, 0);
music.setLocalDirectionToMesh(new BABYLON.Vector3(1, 0, 0));
music.attachToMesh(box);
setDirectionalCone
有3个参数:
声音椎体的外锥度数必须必内锥大,否则会出现错误并且定向声音不起作用。
setLocalDirectionToMesh
是设置声音椎体在模型的哪个方向。默认情况下,是(1,0,0)
。
示例中,你如果进入椎体的朝向范围,将会听到音乐,如果不在,将不会有音乐,因为我们将coneOuterGain
设置为0 。
如果要使用特定算法管理衰减(或Web Audio中的距离模型),可以使用Babylon.js自定义衰减功能绕过本机Web Audio衰减。
注意: Web Audio是“ 硬件加速 ”。这意味着它主要由设备上的专用音频芯片通过本机代码(浏览器)处理。然后,这在3D实时渲染的性能方面几乎没有任何成本。切换到自定义衰减将使用基于JavaScript的Babylon.js距离计算,并且速度会变慢。
此外,自定义衰减仅适用于空间声音(显然),但也适用于连接到Babylon.js网格的声音。也就是说,让我们现在查看代码来做到这一点。首先,您必须在选项中指定它:
// Create and load the sound async
var music = new BABYLON.Sound("Music", "music.wav", scene, null, { loop: true, autoplay: true, useCustomAttenuation: true });
您将切换到内部Babylon.js数学计算。默认的自定义衰减功能是线性的。
要创建自己的逻辑,需要这样的代码:
// 创建一个自定义衰减函数,距离模型越近,声音越小
// 距离越远,声音越大
music.setAttenuationFunction(function (currentVolume, currentDistance, maxDistance, refDistance, rolloffFactor) {
return currentVolume * currentDistance / maxDistance;
});
你可以通过这5个参数,实现你的自定义的衰减函数。只需要返回一个应用于声音的数字即可。
这个例子逻辑有点奇怪,因为距离模型越远,声音越大。这里查看示例
此外,Firefox目前在处理正确线性衰减的Web Audio实现中存在一个错误。这可以通过使用Babylon.js默认线性自定义衰减来修复。
这是以前的示例代码,现在可以在Firefox中正常运行:
https://www.babylonjs-playground.com/#2AH4YH#2
目前只有3DS Max导出器可以直接将声音导出到.babylon。
要从.babylon文件中加载声音,您需要在场景对象上使用getSoundByName()
函数。
这是一个示例代码:
var canvas = document.getElementById("renderCanvas");
var engine = new BABYLON.Engine(canvas, true);
BABYLON.SceneLoader.Load("TestScene/", "testsound.babylon", engine, function (newScene) {
newScene.executeWhenReady(function () {
newScene.activeCamera.attachControl(canvas);
//从场景对象上面获取到声音对象
var gunshotSound = newScene.getSoundByName("gunshot-1.wav");
window.addEventListener("keydown", function (evt) {
if (evt.keyCode === 32 && gunshotSound) {
gunshotSound.play();
}
});
engine.runRenderLoop(function () {
newScene.render();
});
});
}, function (progress) {
// 待办事项:向用户提供进度反馈
});
按空格键将播放枪声。
在几个声轨上分离音乐和声音更好的管理声音的音量可能很有用。它还将在未来版本中特定声轨效果。
默认情况下,Babylon.js创建一个BABYLON.SoundTrack
对象为一个声轨。我们可以将实例化的音频对象添加到这个音轨上。
var soundTrack = new BABYLON.SoundTrack(scene);
soundTrack.AddSound(cellolong);
soundTrack.AddSound(violons11);
使用此代码,“ cellolong ”和“ violons11 ”声音将从主Babylon.js音轨移动到此特定音轨。现在,这意味着您可以独立于主轨道更改此轨道的音量,从而更改这两个声音的音量。
使用AddSound()
函数会将音频对象从原来的容器中移动到指定的新的声轨中:
var soundTrack1 = new BABYLON.SoundTrack(scene);
soundTrack1.AddSound(cellolong);
soundTrack1.AddSound(violons11);
var soundTrack2 = new BABYLON.SoundTrack(scene);
soundTrack2.AddSound(violons11);
“ violons11 ”声音最终只会出现在“ soundTrack2 ”中。
您可以轻松实时分析音频。
了解其工作原理的最简单代码是:
var myAnalyser = new BABYLON.Analyser(scene);
BABYLON.Engine.audioEngine.connectToAnalyser(myAnalyser);
myAnalyser.drawDebugCanvas();
这将连接到音频引擎的全局音量,并将所有一起播放的声音的频率绘制到屏幕顶部的2D画布显示中。
您可以更改调试画布的位置和大小,并在声道而不是全局音频引擎上使用分析器:
var myAnalyser = new BABYLON.Analyser(scene);
soundTrack1.connectToAnalyser(myAnalyser);
myAnalyser.DEBUGCANVASSIZE.width = 160;
myAnalyser.DEBUGCANVASSIZE.height = 100;
myAnalyser.DEBUGCANVASPOS.x = 40;
myAnalyser.DEBUGCANVASPOS.y = 30;
myAnalyser.drawDebugCanvas();
您也可以称自己为分析器功能,以创建自己的使用方法。
这是一个完整的示例