成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

WebVR教程——Web Audio開發(fā)3D音效

youkede / 3335人閱讀

摘要:輸入結(jié)點(diǎn)主要負(fù)責(zé)加載解碼音頻源,比如獲取二進(jìn)制音頻源的獲取音頻源的等處理結(jié)點(diǎn)主要對(duì)音頻數(shù)據(jù)進(jìn)行計(jì)算處理,比如處理音頻振幅的等輸出結(jié)點(diǎn)則將音頻輸出至揚(yáng)聲器或耳機(jī),便是默認(rèn)的輸出節(jié)點(diǎn)。

在VR開發(fā)中,除了圖形視覺渲染,音頻處理是重要的一環(huán),好的音頻處理可以欺騙用戶的聽覺,達(dá)到身臨其境的效果,本文主要介紹WebVR音頻是如何開發(fā)的。

VR Audio

VR音頻的輸出硬件主要是耳機(jī),根據(jù)音頻源與場景之間的關(guān)系,可將VR音頻分為兩類:靜態(tài)音頻和空間化音頻(audio spatialization)。

靜態(tài)音頻

這類音頻作用于整個(gè)VR場景,可簡單的理解成背景音樂,音頻輸出是靜態(tài)的,比如微風(fēng)雨滴聲、鬧市聲等充斥整個(gè)場景的背景音效。
對(duì)于環(huán)境音效的開發(fā),我們可以簡單的使用

空間化音頻

音頻作用在空間的實(shí)體上,具有發(fā)聲體和聽者的位置關(guān)系,音頻輸出會(huì)根據(jù)發(fā)聲體與用戶的距離、方向動(dòng)態(tài)變化,它模擬了現(xiàn)實(shí)中聲音的傳播方式,具有空間感。

實(shí)現(xiàn)原理:在虛擬場景中,通過調(diào)節(jié)音頻的振幅來描述發(fā)聲體與聽者之間的距離,再通過調(diào)節(jié)左右通道(audio channel)之間的差異,控制左右耳機(jī)喇叭輸出,來描述發(fā)聲體相對(duì)聽者的方位。

從發(fā)聲體與用戶兩點(diǎn)間的距離來看,如距離越遠(yuǎn),音頻音量(振幅)應(yīng)越??;

從發(fā)聲體與用戶的方向來看,如發(fā)聲體位于聽者左側(cè),則音頻輸出的左聲道應(yīng)比右聲道音量大。

形如音頻空間化此類稍復(fù)雜的音頻的處理,可通過Web Audio API來實(shí)現(xiàn)。

Web Audio API 簡介

Web Audio API提供了一個(gè)功能強(qiáng)大的音頻處理系統(tǒng),允許我們在瀏覽器中通過js來實(shí)時(shí)控制處理音頻,比如音頻可視化、音頻混合等。

Web Audio處理流程可以比喻成一個(gè)加工廠對(duì)聲源的加工,這個(gè)加工廠由多個(gè)加工模塊AudioNode連接而成,音頻源經(jīng)過一系列的處理加工后,被輸送至揚(yáng)聲器。

AudioContext

類似于canvascontext上下文環(huán)境,它代表了一個(gè)audio加工廠控制中心,負(fù)責(zé)各個(gè)audioNode的創(chuàng)建和組合,通過new AudioContext()的方式創(chuàng)建。

AudioNode

AudioNode音頻節(jié)點(diǎn),則是加工廠的加工模塊, 按照功能可分為三類:輸入結(jié)點(diǎn)、處理結(jié)點(diǎn)、輸出結(jié)點(diǎn)。每個(gè)結(jié)點(diǎn)都擁有connect方法連接下一個(gè)節(jié)點(diǎn),將音頻輸出到下一個(gè)模塊。

輸入結(jié)點(diǎn)主要負(fù)責(zé)加載解碼音頻源,比如獲取二進(jìn)制音頻源的BufferSourceNode、獲取

處理結(jié)點(diǎn)主要對(duì)音頻數(shù)據(jù)進(jìn)行計(jì)算處理,比如處理音頻振幅的GainNode等;

輸出結(jié)點(diǎn)則將音頻輸出至揚(yáng)聲器或耳機(jī),AudioContext.destination便是默認(rèn)的輸出節(jié)點(diǎn)。

一個(gè)簡單的音頻處理流程只需要分為四步:

創(chuàng)建音頻上下文

創(chuàng)建并初始化輸入結(jié)點(diǎn)、處理結(jié)點(diǎn)

將輸入結(jié)點(diǎn)、處理結(jié)點(diǎn)、輸出結(jié)點(diǎn)進(jìn)行有連接

動(dòng)態(tài)修改結(jié)點(diǎn)屬性以輸出不同音效

參考以下代碼:

const myAudio = document.querySelector("audio");
const audioCtx = new AudioContext(); // 創(chuàng)建音頻上下文
 // 創(chuàng)建輸入結(jié)點(diǎn),解碼audio標(biāo)簽的音頻源;創(chuàng)建處理結(jié)點(diǎn),處理音頻
const source = audioCtx.createMediaElementSource(myAudio);
const gainNode = audioCtx.createGain(); // 創(chuàng)建GainNode結(jié)點(diǎn)控制音頻振幅
// 將輸入結(jié)點(diǎn)、處理結(jié)點(diǎn)、輸出結(jié)點(diǎn)兩兩相連
source.connect(gainNode); // 將輸入結(jié)點(diǎn)連接到gainNode處理結(jié)點(diǎn)
gainNode.connect(audioCtx.destination); // 將gainNode連接到destination輸出節(jié)點(diǎn)
// 通過動(dòng)態(tài)改變結(jié)點(diǎn)屬性產(chǎn)生不同音效
source.start(0); // 播放音頻
gainNode.gain.value = val; // 設(shè)置音量

理解了Web Audio的開發(fā)流程,接下來看看如何在WebVR中實(shí)現(xiàn)Audio Spatialization,這里VR場景使用three.js進(jìn)行開發(fā)。

實(shí)現(xiàn)空間化音頻

Audio Spatialization的實(shí)現(xiàn)主要通過AudioListenerPannerNode結(jié)點(diǎn)配合,這兩個(gè)對(duì)象可以根據(jù)空間方位信息動(dòng)態(tài)處理音頻源,并輸出左右聲道。

AudioListener對(duì)象代表三維空間中的聽者(用戶),通過AudioContext.listener屬性獲??;

PannerNode對(duì)象指的是三維空間中的發(fā)聲體,通過?AudioContext.createPanner()創(chuàng)建。

我們需要初始化這兩個(gè)對(duì)象,并將空間方位信息作為入?yún)?dòng)態(tài)傳給它們。

設(shè)置PannerNode
const myAudio = document.querySelector("audio");
const audioCtx = new AudioContext(); // 創(chuàng)建音頻上下文
const source = audioCtx.createMediaElementSource(myAudio);

const panner = audioCtx.createPannerNode();
panner.setPosition(speaker.position.x, speaker.position.y, speaker.position.z); // 將發(fā)聲體坐標(biāo)傳給PannerNode

source.connect(panner); // 將輸入結(jié)點(diǎn)連接到PannerNode處理結(jié)點(diǎn)
panner.connect(audioCtx.destination); 
source.start(0); // 播放音頻
設(shè)置AudioListener

VR用戶頭顯最多有6-Dof:position位置3-Dof系統(tǒng)和orientation方向3-Dof系統(tǒng),我們需要將這6-Dof的信息傳入AudioListener,由它為我們處理音頻數(shù)據(jù)。
對(duì)于用戶位置數(shù)據(jù),AudioListener提供了三個(gè)位置屬性:positionX,positionY,positionZ,它分別代表聽者當(dāng)前位置的xyz坐標(biāo),我們可將用戶在場景中的位置(一般用camera的position)賦值給這三個(gè)屬性。

// 為listener設(shè)置position
const listener = audioCtx.listener;
listener.positionX = camera.position.x;
listener.positionY = camera.position.y;
listener.positionZ = camera.position.z;

除了傳入用戶的位置,我們還需要將用戶的視角方向信息傳給AudioListener,具體是給AudioListener的Forward向量三個(gè)分量forwardX,forwardY,forwardZ和Up向量三個(gè)分量upX,upY,upZ賦值。

Forward向量沿著鼻子方向指向前,默認(rèn)是(0,0,-1);

Up向量沿著頭頂方向指向上,默認(rèn)是(0,1,0)。

在VR場景中,當(dāng)用戶轉(zhuǎn)動(dòng)頭部改變視角時(shí),up向量或forward向量會(huì)隨之改變,但兩者始終垂直。

Up向量 = Camera.旋轉(zhuǎn)矩陣 × [0,1,0]
Forward向量 = Camera.旋轉(zhuǎn)矩陣 × [0,0,-1]

參照上方公式,這里的camera是three.js的camera,指代用戶的頭部,通過camera.quaternion獲取相機(jī)的旋轉(zhuǎn)(四元數(shù))矩陣,與初始向量相乘,得到當(dāng)前Up向量和Forward向量,代碼如下:

    // 計(jì)算當(dāng)前l(fā)istener的forward向量
    let forward = new THREE.Vector3(0,0,-1);
    forward.applyQuaternion(camera.quaternion); // forward初始向量與camera四元數(shù)矩陣相乘,得到當(dāng)前的forward向量
    forward.normalize(); // 向量歸一
    // 賦值給AudioListener的forward分量
    listener.forwardX.value = forward.x;
    listener.forwardY.value = forward.y;
    listener.forwardZ.value = forward.z;
    // 計(jì)算當(dāng)前l(fā)istener的up向量
    let up = new THREE.Vector3(0,1,0);
    up.applyQuaternion(camera.quaternion); // up初始向量與camera四元數(shù)矩陣相乘,得到當(dāng)前的up向量
    up.normalize(); // 向量歸一
    // 賦值給AudioListener的up分量
    listener.upX.value = up.x;
    listener.upY.value = up.y;
    listener.upZ.value = up.z;
WebVR實(shí)現(xiàn)音頻角色

在VR場景中,根據(jù)音頻的發(fā)起方和接收方可以分為兩個(gè)角色:Speaker發(fā)聲體與Listener聽者,即用戶。

一個(gè)VR場景音頻角色由一個(gè)Listener和多個(gè)Speaker組成,于是筆者將PannerNodeAudioListener進(jìn)行獨(dú)立封裝,整合為Speaker類和Listener對(duì)象。
PS:這里沿用前幾期three.js開發(fā)WebVR的方式,可參考《WebVR開發(fā)——標(biāo)準(zhǔn)教程》

Speaker實(shí)現(xiàn)

Speaker類代表發(fā)聲體,主要做了以下事情:

初始化階段加載解析音頻源,創(chuàng)建并連接輸入結(jié)點(diǎn)、處理結(jié)點(diǎn)、輸出結(jié)點(diǎn)

提供update公用方法,在每一幀中更新PannerNode位置。

class Speaker {
    constructor(ctx,path) {
        this.path = path;
        this.ctx = ctx;
        this.source = ctx.createBufferSource();
        this.panner = ctx.createPanner();
        this.source.loop = true; // 設(shè)置音頻循環(huán)播放
        this.source.connect(this.panner); // 將輸入結(jié)點(diǎn)連至PannerNode
        this.panner.connect(ctx.destination); // 將PannerNode連至輸出結(jié)點(diǎn)
        this._processAudio(); // 異步函數(shù),請(qǐng)求與加載音頻數(shù)據(jù)
    }
    update(position) {
        const { panner } = this;
        panner.setPosition(position.x, position.y, position.z); // 將發(fā)聲體坐標(biāo)傳給PannerNode
    }
    _loadAudio(path) { 
        // 使用fetch請(qǐng)求音頻文件
        return fetch(path).then(res => res.arrayBuffer());
    }
    async _processAudio() {
        const { path, ctx, source } = this;
        try {
            const data = await this._loadAudio(path); // 異步請(qǐng)求音頻
            const buffer = await ctx.decodeAudioData(data); // 解碼音頻數(shù)據(jù)
            source.buffer = buffer; // 將解碼數(shù)據(jù)賦值給BufferSourceNode輸入結(jié)點(diǎn)
            source.start(0); // 播放音頻
        } catch(err) {
            console.err(err);
        }
    }
}

這里初始化的流程跟前面略有不同,這里使用的是fetch請(qǐng)求音頻文件,通過BufferSourceNode輸入結(jié)點(diǎn)解析音頻數(shù)據(jù)。
update方法傳入發(fā)聲體position,設(shè)置PannerNode位置。

Listener實(shí)現(xiàn)

Listener對(duì)象代表聽者,提供update公用方法,在每幀中傳入AudioListener的位置和方向。

// 創(chuàng)建Listener對(duì)象
const Listener = {
  init(ctx) {
    this.ctx = ctx;
    this.listener = this.ctx.listener;
  },
  update(position,quaternion) {
    const { listener } = this;
    listener.positionX = position.x;
    listener.positionY = position.y;
    listener.positionZ = position.z;
    // 計(jì)算當(dāng)前l(fā)istener的forward向量
    let forward = new THREE.Vector3(0,0,-1);
    forward.applyQuaternion(quaternion);
    forward.normalize();
    listener.forwardX.value = forward.x;
    listener.forwardY.value = forward.y;
    listener.forwardZ.value = forward.z;
    // 計(jì)算當(dāng)前l(fā)istener的up向量
    let up = new THREE.Vector3(0,1,0);
    up.applyQuaternion(quaternion);
    up.normalize();
    listener.upX.value = up.x;
    listener.upY.value = up.y;
    listener.upZ.value = up.z;
  }
}

這里只是簡單的將AudioListener作一層封裝,update方法傳入camera的position和四元數(shù)矩陣,設(shè)置AudioListener位置、方向。

接下來,將Listener和Speaker引入到WebVR應(yīng)用中,下面例子描述了這樣一個(gè)簡陋場景:一輛狂響喇叭的汽車從你身旁經(jīng)過,并駛向遠(yuǎn)方。

class WebVRApp {
...
  start() {
      const { scene, camera } = this;
      ... // 創(chuàng)建燈光、地面
      // 創(chuàng)建一輛簡陋小車
      const geometry = new THREE.CubeGeometry(4, 3, 5);
      const material = new THREE.MeshLambertMaterial({ color: 0xef6500 });
      this.car = new THREE.Mesh(geometry, material);
      this.car.position.set(-12, 2, -100);
      scene.add(this.car);

      const ctx = new AudioContext(); // 創(chuàng)建AudioContext上下文
      Listener.init(ctx); // 初始化listener
      this.car_speaker = new Speaker(ctx,"audio/horn.wav"); // 創(chuàng)建speaker,傳入上下文和音頻路徑

  }
}

首先在start方法創(chuàng)建小汽車,接著初始化Listener并創(chuàng)建一個(gè)Speaker。

class WebVRApp {
...
  update() {
      const { scene, camera, renderer} = this;
      // 啟動(dòng)渲染
      this.car.position.z += 0.4;
      this.car_speaker.update(this.car.position); // 更新speaker位置
      Listener.update(camera.position, camera.quaternion); // 更新Listener位置以及頭部朝向
      renderer.render(scene, camera);
  }
}
new WebVRApp();

在動(dòng)畫渲染update方法中,更新小汽車的位置,并調(diào)用Speaker和Listener的update方法,傳入小汽車的位置、用戶的位置和旋轉(zhuǎn)矩陣,更新音頻空間信息。
示例地址:https://yonechen.github.io/We...(需要支持es7的瀏覽器如新版chrome,太懶沒做打包編譯?)
源碼地址:https://github.com/YoneChen/W...

小結(jié)

本文主要講解了WebVR應(yīng)用音頻空間化的實(shí)現(xiàn)步驟,核心是運(yùn)用了Web Audio API的PannerNodeAudioListener兩個(gè)對(duì)象處理音頻源,文末展示了VR Audio的一個(gè)簡單代碼例子,three.js本身也提供了完善的音頻空間化支持,可以參考PositinalAudio。
最近筆者正在實(shí)現(xiàn)WebVR多人聊天室,下期文章圍繞此展開,敬請(qǐng)期待~
更多文章可關(guān)注WebVR技術(shù)莊園
WebVR開發(fā)教程——交互事件(二)使用Gamepad
WebVR開發(fā)教程——深度剖析 關(guān)于WebVR的開發(fā)調(diào)試方案以及原理機(jī)制
WebVR開發(fā)教程——標(biāo)準(zhǔn)入門 使用Three.js開發(fā)WebVR場景的入門教程

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90745.html

相關(guān)文章

  • SegmentFault 技術(shù)周刊 Vol.35 - WebGL:打開網(wǎng)頁看大片

    摘要:在文末,我會(huì)附上一個(gè)可加載的模型方便學(xué)習(xí)中文藝術(shù)字渲染用原生可以很容易地繪制文字,但是原生提供的文字效果美化功能十分有限。 showImg(https://segmentfault.com/img/bVWYnb?w=900&h=385); WebGL 可以說是 HTML5 技術(shù)生態(tài)鏈中最為令人振奮的標(biāo)準(zhǔn)之一,它把 Web 帶入了 3D 的時(shí)代。 初識(shí) WebGL 先通過幾個(gè)使用 Web...

    objc94 評(píng)論0 收藏0
  • WebVR開發(fā)教程——深度剖析

    摘要:片元著色器主要處理片元顏色,在這里只是將紋理坐標(biāo)和紋理對(duì)象傳給片元著色器。根據(jù)公式分別計(jì)算出左右視口的模型視圖投影矩陣,傳給頂點(diǎn)著色器程序,與頂點(diǎn)緩沖區(qū)的頂點(diǎn)坐標(biāo)相乘繪制出最終頂點(diǎn)。 最近WebVR API 1.1已經(jīng)發(fā)布,2.0草案也在擬定中,在我看來,WebVR走向大眾瀏覽器是早晚的事情了,今天本人將對(duì)WebVR開發(fā)環(huán)境和開發(fā)流程進(jìn)行深入介紹。 WebVR與WebVR API 首先...

    Cciradih 評(píng)論0 收藏0
  • VR大潮來襲 ---前端開發(fā)能做些什么

    摘要:通過佩戴的分離式頭顯瀏覽連接在主機(jī)端的網(wǎng)頁,現(xiàn)支持的瀏覽器主要是火狐的和設(shè)置的谷歌。的概念大概就如此,這次我們將采用的方式來測試我們的場景,現(xiàn)在踏上我們的開發(fā)之旅。 showImg(https://segmentfault.com/img/remote/1460000008904026); WebVR即web + VR的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的API標(biāo)準(zhǔn)讓我們可...

    mikyou 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

youkede

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<