音频组件
引擎通过封装 Web Audio API,提供用户加载播放音频的基础能力:
AudioListener
- 虚拟音频接收组件,需要与下列音源配合使用StaticAudio
- 与空间位置无关的音源,播放效果与 Listener 无关PositionAudio
- 基于空间位置的音源,播放效果会随着 Listener 的相对位置改变
静态音频
播放与空间位置无关的音频,如全局背景音乐,音效等
ts
import {AudioListener, StaticAudio} from '@orillusion/media-extention'
// 音频接收组件,静态音频可以添加给任意对象,这里用 scene 为例
let listener = scene.addComponent(AudioListener)
// 创建静态音源
let audioObj = new Object3D()
let staticAudio = audioObj.addComponent(StaticAudio)
// 设置收听对象
staticAudio.setLisenter(listener)
// 加载音频
await staticAudio.load('https://cdn.orillusion.com/audio.ogg')
// 播放音频,声音效果与空间位置无关
staticAudio.play()
import {AudioListener, StaticAudio} from '@orillusion/media-extention'
// 音频接收组件,静态音频可以添加给任意对象,这里用 scene 为例
let listener = scene.addComponent(AudioListener)
// 创建静态音源
let audioObj = new Object3D()
let staticAudio = audioObj.addComponent(StaticAudio)
// 设置收听对象
staticAudio.setLisenter(listener)
// 加载音频
await staticAudio.load('https://cdn.orillusion.com/audio.ogg')
// 播放音频,声音效果与空间位置无关
staticAudio.play()
ts
import { BoxGeometry, Camera3D, DirectLight, Engine3D, LitMaterial, KelvinUtil, MeshRenderer, Object3D, Scene3D, Vector3, Color, OrbitController, View3D, AtmosphericComponent } from '@orillusion/core';
import { StaticAudio, AudioListener } from '@orillusion/media-extention'
import * as dat from 'dat.gui';
class Static_Audio {
lightObj: Object3D;
scene: Scene3D;
camera: Object3D
mats: any[];
audio: StaticAudio
constructor() {}
async run() {
Engine3D.setting.shadow.autoUpdate = true;
Engine3D.setting.shadow.updateFrameRate = 1;
Engine3D.setting.shadow.type = 'HARD';
Engine3D.setting.shadow.shadowBound = 100;
await Engine3D.init();
this.scene = new Scene3D();
this.scene.addComponent(AtmosphericComponent);
this.camera = new Object3D()
this.camera.localPosition = new Vector3(0, 20, 50)
let mainCamera = this.camera.addComponent(Camera3D)
this.scene.addChild(this.camera)
mainCamera.perspective(60, Engine3D.aspect, 0.1, 20000.0);
let orbit = this.camera.addComponent(OrbitController)
orbit.target = new Vector3(0, 4, 0)
orbit.minDistance = 10
orbit.maxDistance = 200
let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
Engine3D.startRenderView(view);
await this.initScene();
}
async initScene() {
{
let wall = new Object3D()
let mr = wall.addComponent(MeshRenderer)
mr.geometry = new BoxGeometry(40, 30, 1)
let mat = new LitMaterial()
mat.baseColor = new Color(1,0,0)
mr.material = mat
this.scene.addChild(wall)
wall.z = -5
}
{
let floor = new Object3D();
let mr = floor.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(3000, 1, 3000);
let mat = new LitMaterial();
mr.material = mat;
this.scene.addChild(floor);
}
/******** light *******/
{
this.lightObj = new Object3D();
this.lightObj.rotationX = 35;
this.lightObj.rotationY = 110;
this.lightObj.rotationZ = 0;
let directLight = this.lightObj.addComponent(DirectLight);
directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
directLight.castShadow = true;
directLight.intensity = 30;
this.scene.addChild(this.lightObj);
}
{
let group = new Object3D()
let speaker = await Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/speaker/scene.gltf')
speaker.localScale.set(4,4,4)
speaker.rotationX = -120
//speaker.y = 1.5
group.addChild(speaker)
group.y = 2
this.scene.addChild(group)
let listener = this.camera.addComponent(AudioListener)
let audio = group.addComponent(StaticAudio)
audio.setLisenter(listener)
await audio.load('https://cdn.orillusion.com/audio.ogg')
let buttons = {
play:()=>{audio.play()},
pause:()=>{audio.pause()},
stop:()=>{audio.stop()},
volume: 1
}
let gui = new dat.GUI()
gui.addFolder('Orillusion')
gui.add(buttons, 'play')
gui.add(buttons, 'pause')
gui.add(buttons, 'stop')
gui.add(buttons, 'volume', 0, 1, 0.01).onChange(v=>{
audio.setVolume(v)
})
}
}
}
new Static_Audio().run()
import { BoxGeometry, Camera3D, DirectLight, Engine3D, LitMaterial, KelvinUtil, MeshRenderer, Object3D, Scene3D, Vector3, Color, OrbitController, View3D, AtmosphericComponent } from '@orillusion/core';
import { StaticAudio, AudioListener } from '@orillusion/media-extention'
import * as dat from 'dat.gui';
class Static_Audio {
lightObj: Object3D;
scene: Scene3D;
camera: Object3D
mats: any[];
audio: StaticAudio
constructor() {}
async run() {
Engine3D.setting.shadow.autoUpdate = true;
Engine3D.setting.shadow.updateFrameRate = 1;
Engine3D.setting.shadow.type = 'HARD';
Engine3D.setting.shadow.shadowBound = 100;
await Engine3D.init();
this.scene = new Scene3D();
this.scene.addComponent(AtmosphericComponent);
this.camera = new Object3D()
this.camera.localPosition = new Vector3(0, 20, 50)
let mainCamera = this.camera.addComponent(Camera3D)
this.scene.addChild(this.camera)
mainCamera.perspective(60, Engine3D.aspect, 0.1, 20000.0);
let orbit = this.camera.addComponent(OrbitController)
orbit.target = new Vector3(0, 4, 0)
orbit.minDistance = 10
orbit.maxDistance = 200
let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
Engine3D.startRenderView(view);
await this.initScene();
}
async initScene() {
{
let wall = new Object3D()
let mr = wall.addComponent(MeshRenderer)
mr.geometry = new BoxGeometry(40, 30, 1)
let mat = new LitMaterial()
mat.baseColor = new Color(1,0,0)
mr.material = mat
this.scene.addChild(wall)
wall.z = -5
}
{
let floor = new Object3D();
let mr = floor.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(3000, 1, 3000);
let mat = new LitMaterial();
mr.material = mat;
this.scene.addChild(floor);
}
/******** light *******/
{
this.lightObj = new Object3D();
this.lightObj.rotationX = 35;
this.lightObj.rotationY = 110;
this.lightObj.rotationZ = 0;
let directLight = this.lightObj.addComponent(DirectLight);
directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
directLight.castShadow = true;
directLight.intensity = 30;
this.scene.addChild(this.lightObj);
}
{
let group = new Object3D()
let speaker = await Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/speaker/scene.gltf')
speaker.localScale.set(4,4,4)
speaker.rotationX = -120
//speaker.y = 1.5
group.addChild(speaker)
group.y = 2
this.scene.addChild(group)
let listener = this.camera.addComponent(AudioListener)
let audio = group.addComponent(StaticAudio)
audio.setLisenter(listener)
await audio.load('https://cdn.orillusion.com/audio.ogg')
let buttons = {
play:()=>{audio.play()},
pause:()=>{audio.pause()},
stop:()=>{audio.stop()},
volume: 1
}
let gui = new dat.GUI()
gui.addFolder('Orillusion')
gui.add(buttons, 'play')
gui.add(buttons, 'pause')
gui.add(buttons, 'stop')
gui.add(buttons, 'volume', 0, 1, 0.01).onChange(v=>{
audio.setVolume(v)
})
}
}
}
new Static_Audio().run()
3D空间音频
基于 PannerNode 的3D空间位置的音频播放,声音的方位和大小与接收者和音源的相对位置有关。
ts
import {AudioListener, PositionAudio} from '@orillusion/media-extention'
let movingObj = new Object3D()
// 添加音频接收组件,一般是动态移动的物体,比如添加给 camera 来模拟用户空间位置
let listener = movingObj.addComponent(AudioListener)
// 创建空间音源
let audioObj = new Object3D()
let positionAudio = audioObj.addComponent(PositionAudio)
// 设置音源空间参数, 详见 PannerNode API
positionAudio.refDistance = 10;
positionAudio.maxDistance = 100;
positionAudio.setDirectionalCone( 180, 230, 0.1 ); // coneInnerAngle, coneOuterAngle, coneOuterGain
...
// 显示音频的空间范围
positionAudio.showHelper()
// 设置收听对象
positionAudio.setLisenter(listener)
// 加载音频
await positionAudio.load('https://cdn.orillusion.com/audio.ogg')
// 播放音频,声音方位和大小会随着 movingObj 和 audioObj 的相对位置而变化
positionAudio.play()
import {AudioListener, PositionAudio} from '@orillusion/media-extention'
let movingObj = new Object3D()
// 添加音频接收组件,一般是动态移动的物体,比如添加给 camera 来模拟用户空间位置
let listener = movingObj.addComponent(AudioListener)
// 创建空间音源
let audioObj = new Object3D()
let positionAudio = audioObj.addComponent(PositionAudio)
// 设置音源空间参数, 详见 PannerNode API
positionAudio.refDistance = 10;
positionAudio.maxDistance = 100;
positionAudio.setDirectionalCone( 180, 230, 0.1 ); // coneInnerAngle, coneOuterAngle, coneOuterGain
...
// 显示音频的空间范围
positionAudio.showHelper()
// 设置收听对象
positionAudio.setLisenter(listener)
// 加载音频
await positionAudio.load('https://cdn.orillusion.com/audio.ogg')
// 播放音频,声音方位和大小会随着 movingObj 和 audioObj 的相对位置而变化
positionAudio.play()
ts
import { BoxGeometry, Camera3D, DirectLight, Engine3D, LitMaterial, KelvinUtil, MeshRenderer, Object3D, Scene3D, Vector3, Color, OrbitController, View3D, AtmosphericComponent } from '@orillusion/core';
import { PositionAudio, AudioListener } from '@orillusion/media-extention'
import * as dat from 'dat.gui'
class Position_Audio {
lightObj: Object3D;
scene: Scene3D;
camera: Object3D
mats: any[];
audio: PositionAudio
private a = 40
private b = 80
private angle = 0
constructor() {}
async run() {
Engine3D.setting.shadow.autoUpdate = true;
Engine3D.setting.shadow.updateFrameRate = 1;
Engine3D.setting.shadow.type = 'HARD';
Engine3D.setting.shadow.shadowBound = 100;
await Engine3D.init({
renderLoop: this.loop.bind(this)
});
console.log(1)
this.scene = new Scene3D();
this.scene.addComponent(AtmosphericComponent);
this.camera = new Object3D()
this.camera.localPosition = new Vector3(0, 20, 50)
let mainCamera = this.camera.addComponent(Camera3D)
this.scene.addChild(this.camera)
mainCamera.perspective(60, Engine3D.aspect, 0.1, 20000.0);
let orbit = this.camera.addComponent(OrbitController)
orbit.target = new Vector3(0, 4, 0)
orbit.minDistance = 10
orbit.maxDistance = 200
let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
Engine3D.startRenderView(view);
await this.initScene();
}
async initScene() {
{
let wall = new Object3D()
let mr = wall.addComponent(MeshRenderer)
mr.geometry = new BoxGeometry(40, 30, 1)
let mat = new LitMaterial()
mat.baseColor = new Color(1,0,0)
mr.material = mat
this.scene.addChild(wall)
wall.z = -5
}
{
let floor = new Object3D();
let mr = floor.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(3000, 1, 3000);
let mat = new LitMaterial();
mr.material = mat;
this.scene.addChild(floor);
}
/******** light *******/
{
this.lightObj = new Object3D();
this.lightObj.rotationX = 35;
this.lightObj.rotationY = 110;
this.lightObj.rotationZ = 0;
let directLight = this.lightObj.addComponent(DirectLight);
directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
directLight.castShadow = true;
directLight.intensity = 30;
this.scene.addChild(this.lightObj);
}
{
let [speaker, man, music] = await Promise.all([
Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/speaker/scene.gltf'),
Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/glb/CesiumMan.glb'),
fetch('https://cdn.orillusion.com/audio.ogg').then(res=>res.arrayBuffer())
])
speaker.localScale.set(4,4,4)
speaker.rotationX = -120
speaker.y = 0.5
let group = new Object3D()
group.addChild(speaker)
group.y = 2
this.scene.addChild(group)
man.name = 'man'
man.scaleX = 10;
man.scaleY = 10;
man.scaleZ = 10;
man.rotationX = -90;
man.rotationY = -90
man.localPosition.set(0, 0.5, 30)
this.scene.addChild(man)
let listener = man.addComponent(AudioListener)
let audio = group.addComponent(PositionAudio)
audio.setLisenter(listener)
await audio.loadBuffer(music)
audio.refDistance = 10;
audio.maxDistance = 100;
audio.setDirectionalCone( 180, 230, 0.1 );
audio.showHelper()
let buttons = {
play:()=>{audio.play()},
pause:()=>{audio.pause()},
stop:()=>{audio.stop()},
volume: 1,
'Toggle Helper': ()=>{
audio.toggleHelper()
}
}
let gui = new dat.GUI()
gui.addFolder('Orillusion')
gui.add(buttons, 'play')
gui.add(buttons, 'pause')
gui.add(buttons, 'stop')
gui.add(buttons, 'volume', 0, 1, 0.01).onChange(v=>{
audio.setVolume(v)
})
gui.add(buttons, 'Toggle Helper')
}
}
loop(){
let man = this.scene.getChildByName('man') as Object3D
if(man){
this.angle += 0.005
man.x = this.a * Math.cos(this.angle)
man.z = this.b * Math.sin(this.angle) + 30
man.rotationY -= 0.005 * 180 / Math.PI
}
}
}
new Position_Audio().run()
import { BoxGeometry, Camera3D, DirectLight, Engine3D, LitMaterial, KelvinUtil, MeshRenderer, Object3D, Scene3D, Vector3, Color, OrbitController, View3D, AtmosphericComponent } from '@orillusion/core';
import { PositionAudio, AudioListener } from '@orillusion/media-extention'
import * as dat from 'dat.gui'
class Position_Audio {
lightObj: Object3D;
scene: Scene3D;
camera: Object3D
mats: any[];
audio: PositionAudio
private a = 40
private b = 80
private angle = 0
constructor() {}
async run() {
Engine3D.setting.shadow.autoUpdate = true;
Engine3D.setting.shadow.updateFrameRate = 1;
Engine3D.setting.shadow.type = 'HARD';
Engine3D.setting.shadow.shadowBound = 100;
await Engine3D.init({
renderLoop: this.loop.bind(this)
});
console.log(1)
this.scene = new Scene3D();
this.scene.addComponent(AtmosphericComponent);
this.camera = new Object3D()
this.camera.localPosition = new Vector3(0, 20, 50)
let mainCamera = this.camera.addComponent(Camera3D)
this.scene.addChild(this.camera)
mainCamera.perspective(60, Engine3D.aspect, 0.1, 20000.0);
let orbit = this.camera.addComponent(OrbitController)
orbit.target = new Vector3(0, 4, 0)
orbit.minDistance = 10
orbit.maxDistance = 200
let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
Engine3D.startRenderView(view);
await this.initScene();
}
async initScene() {
{
let wall = new Object3D()
let mr = wall.addComponent(MeshRenderer)
mr.geometry = new BoxGeometry(40, 30, 1)
let mat = new LitMaterial()
mat.baseColor = new Color(1,0,0)
mr.material = mat
this.scene.addChild(wall)
wall.z = -5
}
{
let floor = new Object3D();
let mr = floor.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(3000, 1, 3000);
let mat = new LitMaterial();
mr.material = mat;
this.scene.addChild(floor);
}
/******** light *******/
{
this.lightObj = new Object3D();
this.lightObj.rotationX = 35;
this.lightObj.rotationY = 110;
this.lightObj.rotationZ = 0;
let directLight = this.lightObj.addComponent(DirectLight);
directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
directLight.castShadow = true;
directLight.intensity = 30;
this.scene.addChild(this.lightObj);
}
{
let [speaker, man, music] = await Promise.all([
Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/speaker/scene.gltf'),
Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/glb/CesiumMan.glb'),
fetch('https://cdn.orillusion.com/audio.ogg').then(res=>res.arrayBuffer())
])
speaker.localScale.set(4,4,4)
speaker.rotationX = -120
speaker.y = 0.5
let group = new Object3D()
group.addChild(speaker)
group.y = 2
this.scene.addChild(group)
man.name = 'man'
man.scaleX = 10;
man.scaleY = 10;
man.scaleZ = 10;
man.rotationX = -90;
man.rotationY = -90
man.localPosition.set(0, 0.5, 30)
this.scene.addChild(man)
let listener = man.addComponent(AudioListener)
let audio = group.addComponent(PositionAudio)
audio.setLisenter(listener)
await audio.loadBuffer(music)
audio.refDistance = 10;
audio.maxDistance = 100;
audio.setDirectionalCone( 180, 230, 0.1 );
audio.showHelper()
let buttons = {
play:()=>{audio.play()},
pause:()=>{audio.pause()},
stop:()=>{audio.stop()},
volume: 1,
'Toggle Helper': ()=>{
audio.toggleHelper()
}
}
let gui = new dat.GUI()
gui.addFolder('Orillusion')
gui.add(buttons, 'play')
gui.add(buttons, 'pause')
gui.add(buttons, 'stop')
gui.add(buttons, 'volume', 0, 1, 0.01).onChange(v=>{
audio.setVolume(v)
})
gui.add(buttons, 'Toggle Helper')
}
}
loop(){
let man = this.scene.getChildByName('man') as Object3D
if(man){
this.angle += 0.005
man.x = this.a * Math.cos(this.angle)
man.z = this.b * Math.sin(this.angle) + 30
man.rotationY -= 0.005 * 180 / Math.PI
}
}
}
new Position_Audio().run()