先來個預告效果圖開場
前言:瀏覽蘋果官網時,你會看到發現每個裝置在介紹頁底部有這麼一行文字:“用增強現實看看***”。使用蘋果裝置點選之後就能將該裝置投放於使用者所在場景視界,在手機攝像頭轉動的時候,也能看到物體物件不同的角度,感覺就像真的有一臺手機放在你的面前。(效果如下圖。注意:由於該技術採用蘋果自有的 arkit 技術,安卓手機無法檢視)
聰明的你可能已經想到了,為什麼只能用蘋果手機才能檢視,那有沒有一種純前端實現的通用的 web AR 技術呢?
純前端解決方案
純前端技術的實現可以用下圖總結:
以 JSARToolKit 為例:
- 使用 WebRTC 獲取攝像頭資訊,然後在 canvas 畫布上繪製原圖;
- JSARToolKit 計算姿態矩陣,進而渲染虛擬資訊
實現核心步驟
- (識別)WebRTC 獲取攝像頭影片流;
- (跟蹤)Tracking.js 、JSFeat 、ConvNetJS 、deeplearn.js 、keras.js ;
- (渲染)A-Frame、 Three.js、 Pixi.js 、Babylon.js
比較成熟的框架:AR.js
好比每個領域都有對應的主流開發框架,Web AR 領域比較成熟框架的就是 AR.js,它在增強現實方面主要提供瞭如下三大功能:
- 影象追蹤。當相機發現一幅 2D 影象時,可以在其上方或附近顯示某些內容。內容可以是 2D 影象、gif、3D 模型(也可以是動畫)和 2D 影片。案例:藝術品、學習資料(書籍)、傳單、廣告等等。
- 基於位置的 AR。這種“增強現實”技術利用了真實世界的位置,在使用者的裝置上顯示增強現實的內容。開發者可以利用該庫使使用者獲得基於現實世界位置的體驗。使用者可以隨意走動(最好是在戶外)並透過智慧手機看到現實世界中任何地點的 AR 內容。若使用者移動和旋轉手機,AR 內容也會同步做出反應(這樣一些 AR 內容就被“固定”到真實位置了,且會根據它們與使用者的距離做出適當的變化)。這樣的解決方案讓我們做出互動式旅遊嚮導成為可能,比如遊客來到一個新的城市,遊覽名勝古蹟、博物館、餐館、酒店等等都會更方便。我們也可以改善學習體驗,如尋寶遊戲、生物或歷史學習遊戲等,還可以將該技術用於情景藝術(視覺藝術體驗與特定的現實世界座標相結合)。
- 標記跟蹤。當相機發現一個標記時,可以顯示一些內容(這與影象跟蹤相同)。標記的穩定性不成問題,受限的是形狀、顏色和尺寸。可以應用於需要大量不同標記和不同內容的體驗,如:(增強書籍)、傳單、廣告等。
開始上手體驗 AR.js
開發除錯開啟 https
由於使用到攝像頭敏感許可權,除錯時必須基於 https 環境開啟才能正常執行。如果是以往,自己手動搭建個 https 環境除錯對於很多新手來說還是比較麻煩耗費時間,好在最新的基於 vite+vue3 的腳手架搭建的專案,可以輕鬆用一行命令開啟 https 訪問。用腳手架初始化好程式碼之後,先修改 package.json 檔案,在 dev 命令中加上--host 暴露網路請求地址(預設不開啟),如下圖:
接著用下面命令執行即可開啟 https:
npm run dev -- --https
先跑跑官方 demo,看看效果
學習一門新框架或語言,最好的方式就是先將官方 demo 跑起來體驗看看。
下面是官方程式碼展示的案例效果(注:該錄製動圖體積較大,請耐心等待載入)
wow ~ 是不是感覺還蠻有意思的?接下來正式進入文章的主題,開始擼貓吧
開始
前面有提到,AR.js 基於三種方式展示內容,下面將使用基於影象追蹤(Image Tracking) 方式實現。顧名思義,影象追蹤就是基於一張圖片,根據圖片的特性點識別圖片並跟蹤展示 AR 內容,例如當攝像頭捕捉到該圖片時,就可以將要展示的內容懸浮於該圖片上方展示。
引入依賴庫
Ar.js 從版本 3 開始採用了新的架構,使用jsartoolkit5[1]進行跟蹤定位,而渲染庫有兩種方式可選:A-Frame 或 Three.js。A-Frame 方式就是透過 html 標籤的方式簡化建立場景素材,比如說展示一張圖片,可以直接使用 <a-image></a-image>方式展示。
修改 index.html 檔案:
先將 vue 程式碼注入註釋掉
然後引入依賴:
<script src='./src/sdk/ar-frame/aframe-master.min.js'></script>
<script src='./src/sdk/ar-frame/aframe-ar-nft.js'></script>
擼貓姿勢一:展示貓圖片
<body>
<a-scene embedded arjs>
<a-assets>
<img id="my-image" class="lazyload" data-src="./src/assets/cat.jpg" src="/assets/loading.gif">
</a-assets>
<a-marker preset="hiro">
<a-image rotation="90 0 0" class="lazyload" data-src="#my-image" src="/assets/loading.gif"></a-image>
<!-- <a-box position="0 0.5 0" material="color: green;"></a-box> -->
</a-marker>
<a-entity camera></a-entity>
</a-scene>
</body>
簡單解釋下上面的程式碼:
- <a-scene>宣告一個場景,你可以理解相當於一個 body 元素,裡面嵌入其他標籤元素;
- <a-marker>標籤宣告的是標識圖片,也就是相機識別到標識圖片時,做相應的處理;這裡採用外掛預設的 hiro 圖片,下面效果動圖可以看到
- 使用<a-assets>包裹使用到的素材,相當於宣告引入素材,接著在<a-marker>中使用
看下效果:
擼貓姿勢二:播放影片
除了展示圖片,還可以展示影片,先看效果:
程式碼如下:
<a-scene vr-mode-ui="enabled: false;" renderer='antialias: true; alpha: true; precision: mediump;' embedded
arjs='trackingMethod: best; sourceType: webcam; debugUIEnabled: false;'>
<a-assets>
<video
class="lazyload" data-src="https://ugcydzd.qq.com/uwMROfz2r57CIaQXGdGnC2ddPkb5Wzumid6GMsG9ELr7HeBy/szg_52471341_50001_d4615c1021084c03ad0df73ce2e898c8.f622.mp4?sdtfrom=v1010&guid=951847595ac28f04306b08161bb6d1f7&vkey=3A19FB37CFE7450C64A889F86411FC6CE939A42CCDAA6B177573BBCB3791A64C441EFF5B3298E3ED4E99FFA22231772796F5E8A1FCC33FE4CAC487680A326980FFCC5C56EB926E9B4D20E8740C913D1F7EBF59387012BEC78D2816B17079152BC19FCEF09976A248C4B24D3A5975B243614000CAA333F06D850034DA861B01DCA1D53B546120B74F%22" src="/assets/loading.gif"
preload="auto" id="vid" response-type="arraybuffer" loop crossorigin webkit-playsinline muted playsinline>
</video>
</a-assets>
<a-nft videohandler type='nft' url='./src/assets/dataNFT/pinball' smooth="true" smoothCount="10"
smoothTolerance="0.01" smoothThreshold="5">
<a-video class="lazyload" data-src="#vid" src="/assets/loading.gif" position='50 150 -100' rotation='90 0 180' width='300' height='175'>
</a-video>
</a-nft>
<a-entity camera></a-entity>
</a-scene>
<script>
window.onload = function () {
AFRAME.registerComponent('videohandler', {
init: function () {
var marker = this.el;
this.vid = document.querySelector("#vid");
marker.addEventListener('markerFound', function () {
// 識別到標識圖,開始播放影片
this.vid.play();
}.bind(this));
marker.addEventListener('markerLost', function () {
// 丟失標識圖,停止播放影片
this.vid.pause();
this.vid.currentTime = 0;
}.bind(this));
}
});
};
</script>
:喵~是不是感覺更酷更好玩了?
擼貓姿勢三:配合聲網技術,與你家的貓隔空喊話
如果你是一位前端開發者,相信你一定知道阮一峰這個大佬。曾經在他的每週科技週刊看到這麼一個有趣的事情:在亞馬遜某片雨林裡,安裝了錄音裝置,實時將拾取到的鳥叫聲傳到一個網站,你可以開啟該網站聽到該片雨林裡的實時鳥叫聲,簡單的說就是該網站可以聽到該片雨林的”鳥叫直播 "。(可惜現在一時找不到該網站網址)
而作為工作黨,愛貓人士的我們,可能有著上述同樣的情感需求:要出差幾天,家裡的貓一時沒法好好照顧,想要實時看到家裡的愛貓咋辦?
買臺監控攝像頭唄
當然是開啟聲網找到解決方案:
視訊通話[2] (這裡為聲網文件點個贊,整個產品的文件分類規劃的特別清晰,不像某些雲服務產品文件像是垃圾桶裡翻東西)
使用 vue3 寫法改造文件 demo
先安裝依賴包:
"agora-rtc-sdk-ng": "latest"
app.vue 中程式碼:
<script setup>
import AgoraRTC from "agora-rtc-sdk-ng";
import { ref } from "vue";
const joinBtn = ref(null);
const leaveBtn = ref(null);
let rtc = {
localAudioTrack: null,
client: null,
};
let options = {
appId: "2e76ff53e8c349528b5d05783d53f53c",
channel: "test",
token:
"0062e76ff53e8c349528b5d05783d53f53cIADkwbufdA1BIXWsCZ1oFKLEfyPRrCbL3ECbUg71dsv8HQx+f9gAAAAAEAACwxdSy/6RYQEAAQDK/pFh",
uid: 123456,
};
rtc.client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
rtc.client.on("user-published", async (user, mediaType) => {
await rtc.client.subscribe(user, mediaType);
console.log("subscribe success");
if (mediaType === "video") {
const remoteVideoTrack = user.videoTrack;
const remotePlayerContainer = document.createElement("div");
remotePlayerContainer.id = user.uid.toString();
remotePlayerContainer.textContent = "Remote user " + user.uid.toString();
remotePlayerContainer.style.width = "640px";
remotePlayerContainer.style.height = "480px";
document.body.append(remotePlayerContainer);
remoteVideoTrack.play(remotePlayerContainer);
}
if (mediaType === "audio") {
const remoteAudioTrack = user.audioTrack;
remoteAudioTrack.play();
}
rtc.client.on("user-unpublished", (user) => {
const remotePlayerContainer = document.getElementById(user.uid);
remotePlayerContainer.remove();
});
});
// 加入通話
const handleJoin = async () => {
await rtc.client.join(
options.appId,
options.channel,
options.token,
options.uid
);
rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
await rtc.client.publish([rtc.localAudioTrack, rtc.localVideoTrack]);
const localPlayerContainer = document.createElement("div");
localPlayerContainer.id = options.uid;
localPlayerContainer.textContent = "Local user " + options.uid;
localPlayerContainer.style.width = "640px";
localPlayerContainer.style.height = "480px";
document.body.append(localPlayerContainer);
rtc.localVideoTrack.play(localPlayerContainer);
console.log("publish success!");
};
// 離開通話
const handleLeave = async () => {
rtc.localAudioTrack.close();
rtc.localVideoTrack.close();
rtc.client.remoteUsers.forEach((user) => {
const playerContainer = document.getElementById(user.uid);
playerContainer && playerContainer.remove();
});
await rtc.client.leave();
};
</script>
<template>
<div>
<button ref="joinBtn" @click="handleJoin" type="button" id="join">
加入
</button>
<button ref="leaveBtn" @click="handleLeave" type="button" id="leave">
離開
</button>
</div>
</template>
<style></style>
跑起來效果:
這時就相當於在家安裝了一個攝像頭,如果我們需要遠端檢視,就可以透過聲網官方提供的一個測試地址[3]
加入通話手機開啟上述網址,輸入你的專案 appId 跟 token,可以看到成功加入通話:
下方圖片是手機攝像頭捕捉到的畫面,原諒我用貓照片代替
讓影片畫面跑在 AR.js 畫面中
這個由於個人時間關係,暫時就不研究實現。這裡提供一個想法就是:單純的影片畫面看起來有點單調,畢竟有可能貓並不在影片畫面中出現,結合擼貓姿勢一提到的展示圖片,其實我們可以在 ar 場景中影片區域周圍,佈置照片牆或其他酷炫一點的 subject,這樣的話我們開啟影片即使看不到貓星人,也可以看看它的照片之類的互動。
結束語
本文借徵文活動,簡單入手瞭解了下 web AR 相關知識,在這幾天學習的過程中覺得還是蠻好玩的,此文也當拋磚引玉,希望更多開發者瞭解 AR 相關的知識。
AR 在體驗上真的很酷,未來值得期待。
最近幾年蘋果一直致力於推進 AR 技術體驗並帶來相關落地產品,例如為了配合提升 AR 體驗,帶來雷達掃描,空間音訊功能。值得一提的是,今年的蘋果秋季釋出會,蘋果的邀請函也是利用到了 AR + 空間音訊技術,即使你不是果粉,當你實際上手體驗的時候,你依然會真正發自內心的感覺:wow ~ cool。可以點此影片[4]觀看了解。
而目前的 Web AR 技術相比於蘋果自有的 ARkit 技術,在體驗上還存在一些差距(如效能問題,識別不穩定),同時缺乏生態圈,希望 Web AR 技術在未來得到快速發展,畢竟 web 端跨平臺通用特性,讓人人的終端都可以跑起來才是實現 AR 場景大規模應用的前提。
Facebook 押注的元宇宙概念中,其實也包含了 AR 技術,所以在元宇宙世界到來之前,AR 技術值得我們每一個前端開發者關注學習。
彩蛋
如果你問我最喜歡什麼貓,我會說--“房東的貓”,~哈哈哈 ~
參考資料
[1]
https://github.com/artoolkitx/jsartoolkit5
[2]
https://docs.agora.io/cn/Video/start_call_web_ng?platform=Web
[3]
https://webdemo.agora.io/basicVideoCall/index.html
[4]
https://www.bilibili.com/video/BV1R3411i7LL?from=search&seid=17803327188398196779&spm_id_from=333.337.0.0
作者:碼克吐溫
https://juejin.cn/post/7030342557825499166
作者:碼克吐溫 https://juejin.cn/post/7030342557825499166