本記事は『WebXR』をテーマにしたアドベントカレンダー『 WebXR Advent Calendar 2024』の 24 日目です。
2024年ももう終わりですが、今年はApple Vision Proの発売やGoogleによるAndroid XRでWebXRのサポートが発表されるなど、WebAR業界においても追い風となるニュースがいくつかありました。
今回は「これが実装されたらWebARがアツい!2025年絶対来てほしいSafari Feature Flags!」と題して、いまSafariで実験的に利用できる(Feature Flagsで有効にできる)注目の機能を詳しくご紹介したいと思います。
2024年12月時点ではフラグが立っていない(デフォルトでは対応していない)ものの、2025年には機能実装されてほしい!という願望も込めて、コードも込でご紹介していきます。
今回取り上げる主な機能は以下の6つです。
- HTML
<model>
element - Image Capture API
- ScreenCapture
- Shape Detection API
- Notifications
- WebXR Device API
それでは、ここから各機能の詳細について、実際のコード例や具体的な活用シーンを含めて解説していきます。なお、ここに紹介するコードはあくまでも試験的なサンプルであり、Safariでの挙動を保証するものではありません。あらかじめご了承ください。
HTML <model>
element
まずはHTML model 要素です。これは、ブラウザ上で3Dモデルを直接表示するための要素として期待されています。
こちらの記事でも2021年にご紹介しています。
ただ、これは実はApple Vision ProでのSafariで真価を発揮します。
このようなイメージです。
複数のモデルを一気に展開するボタンを設置できたりします。
では、実際にどのように <model>
要素が書けるのか、試験的なサンプルコードを示してみます。(これはあくまで仮であり、現在のブラウザでそのまま動くわけではない点にご注意ください。)
<!-- Hypothetical usage example of <model> element -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Model Element Test</title>
<style>
/* 簡易的なレイアウト調整 */
body {
text-align: center;
margin-top: 50px;
font-family: sans-serif;
}
model {
width: 400px;
height: 300px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<h1>Testing the <model> Element</h1>
<model src="path/to/3D/model.gltf" alt="3Dモデル"
environment="neutral"
controls="auto"
poster="path/to/loading-image.png">
<p>このブラウザは <model> 要素をサポートしていません。</p>
</model>
</body>
</html>
このように、画像を表示するときの<img>
要素のような感覚で、ソースファイル(src
属性)やローディング中のスタイル、環境光の指定などを行い、3Dモデルを埋め込むイメージです。
こちらのW3Cのドキュメントを詳しくはご覧ください。
Image Capture API
次はImage Capture APIです。これは、デバイスのカメラと直接やり取りをして、写真や映像のキャプチャ、ピント調整、露出制御、ホワイトバランス設定などの高度なカメラ制御をブラウザ上で行えるAPIとなります。
現在、Android版Chromeなどでは比較的早くから実験的に搭載されてきたのですが、SafariでもFeature Flagsを有効にすることで試験的に利用できます。
ここで大事なことは、純正のカメラを利用できる、ということです。
じゃ今までよく見かけるWebARでカメラ撮影してたのはどうしてたの?というと、CanvasのdrawImageを利用していたのです。つまりビデオストリームをCanvasに焼き込むようなイメージで、一回Canvasを経由している為、純正カメラでの撮影ではないわけです。
実際に差を見てみましょう。SafariのImage Capture APIをオンにした状態で、撮影してみます。
左側のImage Captureを使用して撮影した画像にはカメラの情報が出ています。右側はCanvasを経由している故、カメラ情報は取得できていません。
当然カメラ側の機能もフルに使えないという点も大きいです。
Image Captureの場合、4032 x 3024 px(約1200万画素)まで解像度を上げることができました。
下記に簡易サンプルコードを示します。これはあくまで試験的な例ですので、実際にはブラウザのサポート状況をチェックするためのif
文やエラーハンドリングが必要になります。
// Image Capture API のサンプル(実験的)
// 1. ユーザーのカメラにアクセスし、VideoStreamを取得
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
// 2. video要素にStreamを設定
const video = document.querySelector('video');
video.srcObject = stream;
video.play();
// 3. trackからImageCaptureオブジェクトを生成
const track = stream.getVideoTracks()[0];
const imageCapture = new ImageCapture(track);
// 4. ピントや露出などの設定(対応ブラウザでは)
imageCapture.getPhotoCapabilities()
.then(capabilities => {
console.log('Photo capabilities: ', capabilities);
// 例えば露出補正に対応していれば、値を変更してみるなど
});
// 5. 実際に写真を撮影し、Canvasなどに描画
document.getElementById('captureButton').addEventListener('click', () => {
imageCapture.takePhoto()
.then(blob => {
const img = document.getElementById('capturedImage');
img.src = URL.createObjectURL(blob);
})
.catch(error => {
console.error('Image capture failed: ', error);
});
});
})
.catch(error => {
console.error('Could not get user media: ', error);
});
ですが、1つ問題があります。
WebARにおいて撮影をしていくシーンは、当然現実とデジタルを組み合わせています。それが3Dであれ2Dであれ、デジタルとしてのレイヤーのオブジェクトを重ねている為、Canvasを組み合わせる必要があります。
つまり、結局ARにおける撮影だと「Canvas経由する必要があるので画質が劣化する問題」ですね。
ですが、Image Capture APIを使うことで元のカメラ画像のレイヤー(解像度高)+3DレイヤーとCanvas合成することで、アウトプットとなるキャプチャ画像自体は高解像度に出来るはずです(時間不足で検証できておらずです)
ScreenCapture
ScreenCaptureはブラウザがページの内容を動画や静止画でキャプチャすることを可能にするAPIです。画面共有や画面録画で活用できます。
例えばGoogle Chromeの画面の共有をイメージしていただけるとわかりやすいです。
こちらでお試しください。
https://palanar.app/landing_pages/screen-capture-api
例えばモバイルブラウザでも画面共有ができたり、動画撮影ができるようになります。
厳密には今でもvideoをcanvasに流しそれをMedia Recorder APIで撮影する方法もありますが、より解像度の高い動画撮影なども可能になりそうです。
下記に簡単なサンプルコードを示します。
ですが、現時点ではフラグを設定しても上手く動かないようです。
上記のように、フラグをオンにするとサポートされる旨は出るもののこの後は動かずです…
// ScreenCapture API の概念的なサンプル
// デスクトップやタブ、ウィンドウなどの映像を取得する場合
const captureButton = document.getElementById('startCapture');
const stopButton = document.getElementById('stopCapture');
let mediaRecorder;
let recordedChunks = [];
captureButton.addEventListener('click', async () => {
try {
// 1. ユーザーに画面の共有を促す
const displayStream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: true });
// 2. MediaRecorderを使って録画を開始
mediaRecorder = new MediaRecorder(displayStream);
// 3. dataavailableイベントで録画データを蓄積
mediaRecorder.ondataavailable = (event) => {
if (event.data && event.data.size > 0) {
recordedChunks.push(event.data);
}
};
// 4. 録画停止時にBlobをまとめてURL化
mediaRecorder.onstop = () => {
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const videoURL = URL.createObjectURL(blob);
const recordedVideo = document.getElementById('recordedVideo');
recordedVideo.src = videoURL;
recordedVideo.controls = true;
};
mediaRecorder.start();
} catch (err) {
console.error('Error: ', err);
}
});
stopButton.addEventListener('click', () => {
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
}
});
このコードの流れとしては、navigator.mediaDevices.getDisplayMedia()
で画面共有を開始し、得られたMediaStream
をMediaRecorder
で録画していく形になります。こうして録画されたデータをBlob
形式で扱えるようになるため、ユーザーは録画完了後に動画ファイルをダウンロードしたり、さらにARコンテンツに加工を加えたりできるわけです。
これがモバイルSafariでも容易に実行できるようになれば、WebARのユーザーエクスペリエンスは飛躍的に向上するでしょう。
Shape Detection API
Shape Detection APIは、顔認識・テキスト認識(OCR)・バーコード認識などをブラウザのネイティブ機能を利用して高速に行うためのAPIです。
これまでJavaScriptによるコンピュータビジョンライブラリ(例えばOpenCV.jsなど)を使って同様の処理を実装することは可能でしたが、パフォーマンスやデバイス依存の問題もあり、なかなかスムーズにいかないケースが多々ありました。
また、QRコードの浸透もあり、ブラウザでQRコード認識するjsQRなどのライブラリを使用するケースも多いのではないでしょうか。
もしSafariがShape Detection APIを本格的にサポートするようになれば、WebARコンテンツで顔の向きや表情をトラッキングして、キャラクターのアクセサリーを重ねるといった機能がさらに高速かつ高精度に実現できるようになるかもしれません。また、バーコードやQRコードを読み取るシーンなども、WebARアプリの中でネイティブアプリと遜色ないスピードで実装できる期待があります。
例えばApple Vision ProのSafariを開き、そのカメラで次々にバーコードを見るだけで商品登録できる、高速OCRとか(今ならAIでも近いものができますが)、QRコードを見ていくだけで何かデータベース連携したコンテンツが登録されていくとか。
Apple Vision Proでバーコードを見るだけでレジ打ちなどもできるかもしれませんね!
現状、PCのChromeだと上手くいくのですが、iOS Safariだとフラグをオンにしても上手く認識しませんでした…
バーコードリーダーサンプルはこちらです。
https://palanar.app/landing_pages/detect-api
以下、サンプルです。現時点ではSafariで使用するには実験的フラグを立ち上げたり、さらに制限があったりするため、そのままでは動かない可能性が高い点にご注意ください。
// Shape Detection API の概念的サンプル
// 顔検出の例
const video = document.getElementById('videoElement');
const canvas = document.getElementById('canvasElement');
const context = canvas.getContext('2d');
let faceDetector;
if ('FaceDetector' in window) {
faceDetector = new FaceDetector({ fastMode: true, maxDetectedFaces: 5 });
} else {
console.warn('FaceDetector is not supported in this browser.');
}
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
video.srcObject = stream;
video.play();
// 定期的に顔検出を実行
requestAnimationFrame(detectFaces);
})
.catch(err => {
console.error(err);
});
function detectFaces() {
context.drawImage(video, 0, 0, canvas.width, canvas.height);
if (faceDetector) {
faceDetector.detect(canvas)
.then(faces => {
faces.forEach(face => {
const box = face.boundingBox;
context.beginPath();
context.strokeStyle = '#00FF00';
context.lineWidth = 2;
context.rect(box.x, box.y, box.width, box.height);
context.stroke();
});
})
.catch(err => console.error(err));
}
requestAnimationFrame(detectFaces);
}
このコードでは、FaceDetector
のdetect
メソッドを用いて映像から顔を検出し、その位置をcanvas
上に描画しています。WebARの文脈では、ここで得られた顔の位置や大きさ、角度などの情報をもとにARエフェクトを重畳表示するといった使い方が想定されます。ネイティブに近いレベルで処理が行われるため、JavaScriptライブラリを使うよりも高速かつ省メモリで実装できる可能性があります。
Notifications
Safariでは、iOS16.4からWeb Push通知が利用可能になったことで大きな話題を集めましたが、今後は通知権限の扱いの細分化やよりリッチな通知UIなどが追加されていくことが期待されます。通知が充実すると、WebARにおいてもユーザーとの継続的なコミュニケーションが取りやすくなるメリットがあります。
例えば、ARコンテンツを定期的に更新している場合、ユーザーがホーム画面に追加しているWebアプリ(PWA)を通じて自動的に通知を受け取れるようになります。これによってユーザーの再訪を促し、新しいコンテンツを確実に届けることができます。従来、ネイティブアプリであればプッシュ通知を送るのが当たり前でしたが、WebAR側でも同様の仕組みを取り入れられるようになることで、アプリダウンロードのハードルを下げ、より気軽にAR体験を提供できます。
以下に簡単な通知APIのサンプルコードを示します。すでにiOS16.4以降のSafariでもホーム画面に追加したPWAという条件付きではありますが、基本的には以下のような実装が可能です。
// Notifications API のシンプルなサンプル
// 1. 通知の許可をリクエスト
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
// 2. 通知を作成
const notification = new Notification('WebARお知らせ', {
body: '新しいARコンテンツが追加されました!チェックしてみましょう。',
icon: '/images/notification-icon.png'
});
// 3. 通知クリック時の動作
notification.onclick = function(event) {
event.preventDefault();
window.open('https://example.com/webar/new-content', '_blank');
};
} else {
console.log('Notification permission denied or ignored');
}
});
上記のように、ユーザーが通知をタップした際に特定のURLを開くなどの挙動を設定できます。これをWebARコンテンツの更新通知に応用すれば、ユーザーにタイムリーに新しいシーンやキャラクター、エフェクトの追加情報を知らせることが可能になります。特に、イベントやキャンペーンなど期間限定のAR企画を行う際に、通知は非常に効果的な手段となるでしょう。
WebXR Device API
最後はWebXR Device APIです。
ラスボス的な存在ですね。2024年12月時点ではFeature Flagsに入らない(実は入ったり外れたりを繰り返している)のですが、特別枠でご紹介させてください。
ARやVRなどの拡張現実・仮想現実をブラウザで実現するための標準仕様として、数年前から各ブラウザで実装が進められてきました。Android版Chromeや一部のデスクトップブラウザではかなり実用的になっていますが、iOS版Safariではまだまだフルサポートされていない部分があり、代替手段として独自のJavaScriptライブラリや手法が使われるケースが多いのが現状です。
WebXR Device APIがSafariで本格的にサポートされることになれば、SLAM(Simultaneous Localization and Mapping)を用いた空間認識や、カメラの動きに追従してオブジェクトを正確に配置するといった、本格的なARエクスペリエンスをネイティブアプリと同等のレベルで実現することが可能になるはずです。
下記のサンプルはWebXR Device APIを使用してARセッションを開始し、空間上に3Dオブジェクト(例としてキューブ)を配置するイメージコードです。これはChromeなどであれば一部動作が確認できますが、iOS Safariでは現時点では動作しない可能性が高いのでご注意ください。
// WebXR Device API の概念的なARサンプル
// 1. ARセッションをリクエスト
const enterARButton = document.getElementById('enterAR');
let xrSession = null;
let xrRefSpace = null;
let gl = null;
enterARButton.addEventListener('click', () => {
if (!navigator.xr) {
console.error('WebXR not supported');
return;
}
navigator.xr.requestSession('immersive-ar', { requiredFeatures: ['hit-test'] })
.then(session => {
xrSession = session;
// 2. GLコンテキストなどの初期化
const canvas = document.createElement('canvas');
gl = canvas.getContext('webgl', { xrCompatible: true });
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
// 3. リファレンススペースの取得
session.requestReferenceSpace('local').then(refSpace => {
xrRefSpace = refSpace;
// 4. レンダリングループ開始
session.requestAnimationFrame(onXRFrame);
});
})
.catch(err => {
console.error('Failed to start AR session', err);
});
});
function onXRFrame(t, frame) {
xrSession.requestAnimationFrame(onXRFrame);
const pose = frame.getViewerPose(xrRefSpace);
if (!pose) return;
// WebGLでの描画設定
const glLayer = xrSession.renderState.baseLayer;
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
for (const view of pose.views) {
const viewport = glLayer.getViewport(view);
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
// ここでキューブなどの3Dオブジェクトを描画
// 例: drawCube(view.projectionMatrix, pose.transform.matrix);
}
}
このように、navigator.xr.requestSession('immersive-ar')
を呼び出してARセッションを開始し、WebGLを用いてキューブやその他の3Dモデルを描画していく流れがWebXRの基本的な形となります。さらにhit-test
やplane-detection
などの機能を活用すれば、実際の物理空間の平面を推定してその上にオブジェクトを設置する、といったリアルなAR体験が実現できるというわけです。
更にApple Vision Proでは現状、Safariのカメラ映像がペルソナのみとなっています。
これを外カメラアクセス及びImmersive AR Sessionも可能になると、まさに見た空間をそのままAR演出可能な、最高のWebARの実現が可能となります!(Meta Questは可能です)
まとめ
今回は「これが実装されたらWebARがアツい!2025年絶対来てほしいSafari Feature Flags!」と題して、Safariで現時点では実験的な段階にとどまっている機能を中心に取り上げました。
WebARはここ数年で大きく成長してきました。以前はアプリでしか実現できなかった高度なカメラ制御やSLAM技術がWeb上でも可能になり、ユーザーはアプリストアからのダウンロードを必要とせずに気軽にARを体験できるようになっています。その一方で、Safari(特にiOS版)では他のブラウザに比べてAR関連の機能が遅れている面があり、WebAR開発者のあいだでも課題として指摘されてきました。
しかし、iOS16.4でWeb Pushが対応したように、Appleは少しずつWebの拡張機能にも前向きに取り組んでいる様子がうかがえます。2025年に向けてこれらの機能が順次搭載されていくことがあれば、WebARはさらに手軽でリッチなものになるでしょう。特に、<model>
要素やWebXR Device APIが本格的にサポートされれば、ネイティブアプリ並みの高品質なAR体験がブラウザだけで完結する未来も見えてきます。
追い風として、Android XRは公式でWebXRのサポート及び開発手段の1つとして大きく取り上げています。
私の2025年予想としては、2025年WebXR Device API(特にimmersive-ar)がSafariでサポートされる と考えています。
期待を込めてですが、2017年頃からWebARを追っている身として、その時期が近いと感じています。
以上、まだまだ実験的な段階ではありますが、もしこれらが正式実装されればWebARに大きなインパクトを与えることは間違いありません。今後のSafariやiOSのアップデートを追いかけながら、新機能の登場を楽しみに待ちつつ、引き続きWebARの技術情報を深掘りしていきたいと思います。
明日の Day 25、最終日は @ikkouさん の『WebXR ( WebVR/WebAR ) の現状確認 2024 Winter』です!毎年まとめて頂いているので大変私達も参考にさせて頂いております🙏