走進網頁虛擬現實 WebVR

謝小飛發表於2017-04-14

  最近幾年,虛擬現實VR的概念火了一把,各種VR概念的遊戲、裝置、視訊受到人們的廣泛關注。筆者在逛商場的時候也經常會看到有VR裝置體驗的地方讓遊人體驗一把,各種酷炫的頭盔和酷炫的裝置著實抓人眼球。但是作為一個前端工作者,我們肯定也希望在我們的網頁裡也能看到這麼酷炫的效果,不經意間在網上發現了一個網頁虛擬現實框架A-Frame,分享一下筆者的使用心得。

介紹

  A-Frame是Mozilla釋出的一個全新的開源框架,旨在幫助開發者開發在瀏覽器中執行的高效能響應式的VR體驗。只需要在頁面中引入aFrame.min.js就能夠整合支援VR頁面所需要的元件了。

走進網頁虛擬現實 WebVR
A-Frame

優點

基於DOM

  我們可以使用傳統的JavaScript DOM API來操縱A-Frame場景來新增邏輯,行為和功能。同時,A-Frame是基於DOM的,現在一些流行的框架能夠基於A-Frame工作,比如React、Vue、jQuery和Angular。

實體元件系統

  A-Frame是一個基於three.js的實體元件系統。在A-Frame裡一切都是實體,我們插入元件,可以隨意撰寫外觀,行為和功能整合。

豐富的生態系統

  A-Frame配備了多個元件,但由於A-Frame在其核心部分是完全可擴充套件的,社群已經為生態系統填充了許多元件,如物理,粒子系統,音訊視覺化和Leap Motion控制元件。這個生態系統是A-Frame的命脈。開發人員可以構建一個元件併發布它,然後其他人可以使用該元件並直接從HTML使用,甚至不必知道任何JavaScript。

走進網頁虛擬現實 WebVR
e-system

強大的視覺化檢查器

  視覺化編輯器用於檢查和編輯A框架場景的視覺化工具。與瀏覽器的DOM檢查器類似,您可以進入任何A-Frame場景,本地或Web上,然後點選ctrl+alt+i鍵盤。
  這將開啟視覺檢查器,我們可以在其中進行更改。可以在視覺上移動和放置物體,用元件的屬性隨意的挪動物體,或者圍繞相機平移以檢視場景的不同檢視。

元件

  介紹了這麼多,讓我們來看一下A-Frame是如何來構造元件的。

a-scene

  一個場景是由a-scene建立的,是全景渲染的根物件,所有的元素都需要放在a-scene這個元件裡。它會處理3D所需的所有設定:設定WebGL、畫布、相機、燈光、渲染器、渲染迴圈以及開啟及時的WebVR支援。

a-sky

  每一個場景都需要一個背景,a-sky標籤用來設定場景的背景,可以直接放置src為全景圖片,或者直接渲染color值。

<a-scene>
  <a-sky color="#ccc" src="images/panorama.jpg"></a-sky>
</a-scene>複製程式碼

  如果直接渲染了color值,那麼整個背景就會變成該顏色;如果設定全景圖片,可以左右移動來檢視。效果連結戳這裡

走進網頁虛擬現實 WebVR
effect

a-box

  我們通過a-box標籤來生成一個長方體,有一下幾個重要的屬性:

  • width:寬度
  • height:高度
  • depth:深度
  • color:顏色
  • position:位置
  • rotation:旋轉
  • scale:縮放
<a-scene>
  <a-sky color="#f0f0f0"></a-sky>
  <a-box 
    color="red" 
    depth="1" 
    height="1" 
    width="1" 
    position="0 2 -5" 
    rotation="0 45 45" 
    scale="1 1 1">
  </a-box>
</a-scene>複製程式碼

  最後生成一個長1高1深1顏色為紅色的長方體:

走進網頁虛擬現實 WebVR
cub

a-assets

  但是如果僅僅是紅色的外觀那麼就太單調了。A-Frame允許我們給元件設定紋理圖片,雖然可以直接給元件設定src屬性,不過不推薦這種做法,推薦通過資源管理系統a-assets
  一般在遊戲等視覺體驗豐富的場景中,由於有著大量的圖片、模型、聲音等資源,都會對這些資源進行一個預載入處理,確保在渲染的時候不會出現缺失的現象。
  我們把這些資源放到a-assets也是為了進行預載入。我們可以存放以下資源:

  • <a-asset-item>:其他資產,如3D模型和材料
  • <audio>:聲音檔案
  • <img>:影像紋理
  • <video>:視訊紋理

  我們通過給資源標誌一個唯一的id,然後在元件的src中引用這個id來進行呼叫。

<a-box 
  src="#boxTexture" 
  depth="1" 
  height="1" 
  width="1" 
  position="0 2 -5" 
  rotation="0 45 45" 
  scale="1 1 1">
</a-box>複製程式碼

  這樣我們的長方體就變成了一個帶有圖案紋理的長方體。

走進網頁虛擬現實 WebVR
cub1

a-light

  我們可以通過使用a-light來改變場景的亮度。預設情況下,如果我們沒有指定任何指示燈,A-Frame將新增環境光和定向光。如果A-Frame沒有為我們新增燈,場景將是黑色的。一旦我們新增了我們自己的燈,預設的照明設定將被刪除,並替換為我們的設定。
  我們還會新增一個點光源,點光源就像燈泡; 我們可以將它們放在場景周圍,點光源對實體的影響取決於它與實體的距離。

< - 紅色定向燈從左上方閃爍。 - >
<a-light color="red" position="-1 1 0"></a-light>

< - 藍點光,5米空中。 - >
<a-light tpye="point" color="blue" position="0 5 0"></a-light>

< - 昏暗環境照明。 - >
<a-light type="ambient" color="yellow"></a-light>複製程式碼

  我們給環境一個黃色照明的光源,最後的效果是這樣的。

走進網頁虛擬現實 WebVR
cub2

a-animation

  我們可以使用A-Frame的內建動畫系統<a-animation>向盒子新增動畫。我們可以將<a-animation>元素作為實體的子代。讓我們把盒子上下襬動來給場景新增一些動作。

<a-box src="#boxTexture" depth="1" height="1" width="1" position="0 2 -5" rotation="0 45 45" scale="1 1 1">
  <!-- 在box裡面新增animation元素 -->
  <a-animation 
    attribute="position" 
    to="0 1 -5" 
    direction="alternate" 
    dur="2000" 
    repeat="indefinite">
  </a-animation>
</a-box>複製程式碼

走進網頁虛擬現實 WebVR
animation

  一些屬性說明:

  • attribute:需要把哪個屬性作為動畫
  • to:屬性到某個值
  • direction:方向,alternate表示來回
  • dur:時間間隔
  • repeat:重複次數

a-text

  在A-Frame中還可以新增文字元件<a-text>

<a-text value="Hello, A-Frame!"
        color="#0abef0"
        position="-0.9 0.2 -3" 
        scale="1.5 1.5 1.5">
</a-text>複製程式碼

  最後新增文字的效果,效果連結戳這裡

走進網頁虛擬現實 WebVR
cub3

a-cylinder

  圓筒原型是多功能的,可用於建立不同種類的形狀:

<!-- 基本圓筒。 -- >
<a-cylinder  color="crimson"  height="3"  radius="1.5"></a-cylinder>
<!-- 六角形。 -- >
<a-cylinder  color="cyan"  segments-radial="8"></a-cylinder>
<!-- 吃豆人。 -- >
<a-cylinder color="yellow"  theta-start="50"  theta-length="280"  side="double"></a-cylinder >
<!-- 綠色管道。 -->
<a-cylinder  color="green"  open-ended="true"></a-cylinder>複製程式碼

a-cone

  用於創造一個椎體。

<a-cone position="0 0 -20" rotation="35 45 30" height="10" radius-top="2" radius-bottom="10" color="#F3BA8D"></a-cone>複製程式碼

使用JS和DOM

  在A-Frame中也有DOM元素,通過querySelector()和querySelectorAll()方法來提供元素的遍歷,查詢,查詢和選擇。這個很像jQuery中的選擇器。

querySelector

  如果我們想抓住一個元素,我們使用querySelector()返回那一個元素。比如我們來抓住場景元素:

var scene = document.querySelector(`a-scene`);
console.log(scene);複製程式碼

  如果元素具有ID,則可以使用ID選擇器(即,#)。我們來抓住一個有一個ID的紅色框。之前我們在整個文件上做了一個查詢選擇器。在這裡,我們將在場景範圍內做一個查詢選擇器。使用查詢選擇器,我們可以將查詢的範圍限制在任何元素內:

var scene = document.querySelector(`a-scene`);
console.log(scene.querySelector(`#mybox`));複製程式碼

querySelectorAll

  如果我們要抓取一組元素,我們使用querySelector()哪個返回一個元素陣列。我們可以查詢元素名稱、類名、屬性名:

// 查詢元素名稱
console.log(document.querySelectorAll(`a-box`));
// 查詢類名
console.log(document.querySelectorAll(`.mybox`));
// [
// <a-entity light="type:ambient"></a-entity>
// <a-entity light="type:directional"></a-entity>
//]
// 查詢屬性名
console.log(document.querySelectorAll(`[light]`));複製程式碼

  如果我們抓住了一組使用的實體querySelectorAll(),我們可以迴圈使用它們for。我們圍繞場景中的每個元素迴圈遍歷。

var els = document.querySelectorAll(`a-box`);
for(var i = 0; i < els.length; i++){
  console.log(els[i]);
}複製程式碼

createElement

  要建立一個實體,我們可以使用document.createElement。這將給我們一個空白的實體:

var el = document .createElement(`a-entity`);複製程式碼

  但是,在將實體附加到我們的場景之前,該實體將不會被初始化或者成為場景的一部分。

appendChild

  要向DOM新增實體,我們可以使用.appendChild(element)。具體來說,我們想把它新增到我們的場景中。我們抓住現場,建立實體,並將實體附加到我們的場景。

var sceneEl = document .querySelector(`a-scene`);
var entityEl = document .createElement(`a-entity`);
sceneEl.appendChild(entityEl);複製程式碼

  請注意,這appendChild()方法是瀏覽器中的非同步操作。在實體完成附加到DOM之前,我們不能對實體執行許多操作(如呼叫.getAttribute())。如果我們需要查詢剛被追加的實體上的一個屬性,我們可以監聽loaded該實體上的事件,或者將邏輯放在A-Frame元件中,以便一旦它被準備好就執行:

removeChild

  要從DOM中移除實體,因此從場景中刪除一個實體,我們removeChild(element)從父元素呼叫。如果我們有一個實體,我們必須要用它的parent(parentNode)去除實體。

entityEl.parentNode.removeChild(entityEl);複製程式碼

setAttribute

  要更新元件,我們可以使用setAttribute()方法。更新元件需要幾種形式。如果元件是單屬性元件,則setAttribute其行為與通常情況相同:

entity.setAttribute(`visible`,false);複製程式碼

  但是如果是單屬性,它可以處理該值的特殊解析。例如,position元件是單屬性元件,但其屬性型別解析器允許它佔用一個物件:

entity.setAttribute(`position`,{x:1,y:2,z:3});複製程式碼

  要設定或替換多屬性元件的元件資料,我們可以傳遞註冊元件的屬性名稱,並將屬性物件傳遞為value:

entity.setAttribute(`light`, {
  type: `spot`,
  distance: 30,
  intensity: 2.0
});複製程式碼

removeAttribute

  從DOM中刪除屬性或者分離元件,呼叫元件的remove生命週期方法。

entity.removeAttribute(`goemetry`);  //分離幾何元件。
entity.removeAttribute(`sound`);  //分離聲音元件。複製程式碼

相關文章