好歌分享:Love is the answer
近年 VR/AR 一直不斷出現在大家的視線內,雖然一直沒有什麼殺手級的應用出現,但這阻止不了開發者們的雄心壯志,尤其是 JavaScript 社群,畢竟 Jeff Atwood 說過:
"Any application that can be written in JavaScript, will eventually be written in JavaScript." — Jeff Atwood, Author, Entrepreneur, Cofounder of StackOverflow
隨著 a-frame 的出現,WebVR 成為現實,並且很容易開發;Web AR 部分進展則相對緩慢ㄧ些,瀏覽器原生支援的 API 還一直處於不穩定的開發階段,但即便如此,我們還是可以在特定版本的瀏覽器上使用,此外,也有像是 AR.js 這樣融合 artoolkit、three.js、WebGL 和 WebRTC 等技術的工具可以使用。
今天就來稍稍研究一下,看看目前的技術能如何開發 Web AR!
照慣例,開始前先看點 demo,把 Pokemon 帶到你家客應:
CreateWebVR 這網站上列出了一些目前有的 library,以及目前支援 WebAR 的瀏覽器:
其中 AR.js 使用了 A-Frame (基於 Three.js) 以及 JSARTookit5(JavaScript 移植版的 ARToolKit),而這兩個技術主要皆是利用 WebGL 為主,因此大多現行的瀏覽器都能直接支援,不需要特殊的 API。
這大概也是為何 AR.js 能在 GitHub 上擁有一萬多顆星星,遠勝過上列其他套件的原因。再加上作者的實驗證明 AR.js 即便在兩年的老舊手機上也能運行順暢,擁有良好的 Performance。
但 AR.js 也並非沒有缺點,由於是基於 ARToolKit,因此只能夠支援 Marker-based 的 AR 效果,也就是像最前面的 Demo 圖片一樣,是需要在鏡頭內放置一個設定好的 Marker,讓其辨識,取得環境的一些 Sensor 資訊,包含鏡頭的深淺遠近等等,才能讓 AR 物件渲染在視窗中。
即便如此,AR.js 其簡潔、便利的使用方式(有 a-frame 與 threejs 的 extension),能讓你用短短 10 行程式碼就產生出一個 WebAR 效果的網頁,還是非常好用的。
如果你是使用 AR.js 的話,基本上現行有支援 WebGL 的手機瀏覽器就都能夠運行,不需要額外的 Polyfill 等等。
但如果你想要使用非 Marker-based 效果的 AR 應用,你就得研究 WebXR Device API
,其前身為 WebAR API。
WebXR Device API 現在還在不斷更新中,不是個穩定的 API。
運用到 WebXR Device API 的有 Google 使用的 three.ar.js 與整合 A-Frame 的 aframe-ar.js,以及 Mozilla 主導的 three.xr.js 和 aframe-xr.js。
Google 提供了 WebARonARCore 和 WebARonARKit 兩種分別在 Android 與 iOS 平台上運行的特殊 browsers,讓你能在上面跑 WebXR Device 相關的 API:而 Mozilla 在 iOS 上也推出 Mozilla WebXR Viewer 來對應,三者皆是用到手機平台原生的 ARKit。
如同剛剛所說,WebXR Device API 還很不穩定,而且 Google 與 Mozilla 各自在 Android 與 iOS 上有不同的實作,Google code lab 上的範例只能運行在 version 為 70 - 72 的 Chrome canary 上,而 Mozilla 雖然有推出 Mozilla WebXR Viewer,但上面的範例實作也只能運行在 Mozilla WebXR Viewer 上頭...
不過去看一下雙方的範例程式碼後,會發現其實用法蠻雷同的,大多都有下面這些流程(以 Google 的程式碼來當範例):
判斷是否支援 WebXR Device API,並初始設定:
/**
* Fetches the XRDevice, if available.
*/
async init() {
// `navigator.xr` 是 WebXR Device API 的入口,有必要確認其存在
// 而 `XRSession` 中的 `requestHitTest` 則是要 enable #webxr-hit-test flag
// 確認這兩個 API 存在,確保能夠製造出點擊畫面
if (navigator.xr && XRSession.prototype.requestHitTest) {
try {
this.device = await navigator.xr.requestDevice();
} catch (e) {
// Error handling,通知使用者的瀏覽器並不支援
this.onNoXRDevice();
return;
}
} else {
// Error handling,通知使用者的瀏覽器並不支援
this.onNoXRDevice();
return;
}
// 成功取得 XRDevice 物件後,需要 bind 一個 user gesture 的 event,然後呼叫
// `device.requestSession()`,這是規範在 spec 中的
document.querySelector('#enter-ar').addEventListener('click', this.onEnterAR);
}
取得 XRDevice
後,利用 device.requestSession()
製造出運行 XR 的環境:
async onEnterAR() {
const outputCanvas = document.createElement('canvas');
const ctx = outputCanvas.getContext('xrpresent');
try {
// `device.requestSession()` 一定要是由 user 觸發,像是 click handler 內
const session = await this.device.requestSession({
outputContext: ctx,
environmentIntegration: true,
});
document.body.appendChild(outputCanvas);
// 成功創建 Session 後就能開始運算 AR 了
this.onSessionStarted(session)
} catch (e) {
// Error handling,通知使用者的瀏覽器並不支援
this.onNoXRDevice();
}
}
當 XRSession 成功創建後,接著就是 set up three.js,撰寫 renderer,設定 scene、camera,並 attach 上 XRWebGLLayer,然後啟動 render loop:
async onSessionStarted(session) {
this.session = session;
// ...省略
// 利用 Three.js 繪製 3D 物件,因此要借用 THREE.WebGLRenderer 來當作 XRSession 的 render layer
this.renderer = new THREE.WebGLRenderer({
alpha: true,
preserveDrawingBuffer: true,
});
// ...省略
// 設定 render layer
this.session.baseLayer = new XRWebGLLayer(this.session, this.gl);
const framebuffer = this.session.baseLayer.framebuffer;
this.renderer.setFramebuffer(framebuffer);
// ...省略, 設定 scene
this.scene = DemoUtils.createLitScene();
// ...省略, 設定 camera
this.camera = new THREE.PerspectiveCamera();
// ...省略, 更多的設定
// 在 `requestAnimationFrame` 中啟動 render loop
this.session.requestAnimationFrame(this.onXRFrame);
// ...省略
}
省略了很多細節,但大致的步驟就是這樣,詳細程式碼在此下載
對 WebXR Device API 比較有興趣的讀者除了 Google code lab 上的範例程式與 Mozilla 的 webxr-ios-js 範例 外,也可以到 immersive-web/webxr 看看該 WebXR Device API 的 Specs detail 與解釋,他們也有提供 Sample Page 可作參考。
由於手邊沒有適合的 Android 手機,不能嘗試利用 WebXR Device API,所以今天就先來看看 AR.js 有多簡單。
你需要的就只有:
AR.js 有提供一個 Marker generator - AR.js Marker Training
你可以上傳想要的圖片放到 Marker 中,例如一個記載你的 WebVR webapp 網址的 QR code 就很適合。像這篇文章作者利用 AR.js 結合實體卡片送給他女友一個小驚喜。
我建議把你做好的 Marker 下載下來,否則當你手機對著電腦中的 marker 時,3D Model 方位視角會跟你是垂直的,不是很好看。
接著可以到 Poly 或是 sketchfab 下載 gltf
的 3D 模型。(搜尋想要的 Model 時記得勾選 downloadable
,比較不會選到需要付費才能下載的,當然你要付費也很棒!)
以我最前面的例子來說,我在 sketchfab 中載了一個傑尼龜的模型
接著用 AR.js 對應 AFrame 的 extension 撰寫簡單的 WebVR app:
<script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script>
<script src="https://cdn.rawgit.com/jeromeetienne/AR.js/1.7.5/aframe/build/aframe-ar.js"></script>
<body style='margin : 0px; overflow: hidden;'>
<a-scene embedded arjs='sourceType: webcam; debugUIEnabled: false;'>
<a-marker type='pattern' url='assets/pattern-marker.patt'>
<a-entity position='0 -6 -12' rotation="-20 0 0" gltf-model="url(assets/scene.gltf)"></a-entity>
</a-marker>
</a-scene>
</body>
在 <a-scene />
中,我們指定一個 attribute arjs
,並且設定 sourceType
為 webcam
,相關 attribute 設定其實來自 artoolkit system
,有需要可以到 GitHub 的列表查看。
接著我們透過 <a-marker />
放入我們製作的 marker,副檔名為 .patt
,這邊的 type attribute,如果你是單純用 barcode 的話,可以設為 type=barcode
,但若是客製化的 marker,就要設為 type=pattern
。
最後在 <a-entity />
上頭設定我們想要呈現的 AR 3D Model,gltf-model
attribute 設定模型的路徑,再透過 position
與 rotation
來調整你的模型出現在鏡頭的位置。
這邊特別要注意一下,因為你載下來的 3D Model,都有自己的位置屬性,所以你可能會需要自己多加調整出適合的 position
與 rotation
值,否則你的 3D Model 很可能一直成像在你手機的鏡頭外而看不到,然後你還以為是程式出問題...
當手機鏡頭偵測到 <a-marker />
內對應的 marker 時,就會在鏡頭內渲染出 <a-entiy />
。
如果只是像我一樣想要嘗試一下的話,可以簡單利用 Chrome 的 webapp - Web Server for Chrome 來 host 你的 htlm file,然後利用 ngork 或是 serveo 來當作你 localhost 的 proxy,讓你的手機可以方便相連。
一切順利的話,你就會看到一隻傑尼龜出現在你家裡啦~
如果你沒有手機可以玩,想用電腦 Browser 跑的話,會需要到 chrome://flags
中把 WebVR
的選項開啟,然後用 inpsecter 將 Browser 調整成手機模式。
並且需要加上 polyfill,因為普通的 chrome 是沒有支援 navigator.xr
api 的:
<script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script>
<script>
var polyfill = new WebXRPolyfill();
</script>
雖然 WebXR Device API 還不穩定,但就是在這時候開始試用才更能給出回饋,高手們來試試吧!決定下次拿公司測試機來跟著 Code lab 上的範例改改看! 另外,AR.js 雖然目前是 Marker-based,但從 GitHub 上的一些討論 來看,之後應該是有機會支援 Markerless 的。
AR 這樣牽扯到電腦視覺、硬體、演算法、Sensor 等複雜運算的技術,要實作到 Web 上更是困難,進度慢是可以理解的,但還是衷心期盼著那一天,能夠開啟網頁就能丈量傢俱尺寸或是試穿衣物!
關於作者: @arvinh 前端攻城獅,熱愛數據分析和資訊視覺化