WWDC Quick Look 💓 By SwiftGGTeam
HTML Model Elementを始める

HTML Model Elementを始める

元の動画を見る

ハイライト

Appleはネイティブの<model>要素をvisionOSからiOS、iPadOS、macOSへ広げます。開発者はJavaScriptライブラリを追加せず、1行のHTMLだけでWebページにインタラクティブな3Dモデルを埋め込めます。AR Quick Lookと立体レンダリングにも対応します。

主要内容

Webで3Dモデルを表示するには、これまで実質的に2つの道しかありませんでした。Googleのmodel-viewerを導入するか、Three.jsで自前のレンダリングパイプラインを組むかです。どちらも大量のJavaScriptを読み込む必要があり、visionOSでは立体レンダリング(stereoscopic rendering)のパフォーマンス負荷にも別途対応しなければなりません。

AppleはまずvisionOSでネイティブの<model>要素を導入しました。今、この要素がiOS、iPadOS、macOSのSafariにも来ます。同じ1行のマークアップが、すべてのAppleプラットフォームで動作します。

(00:37)

<model>はネイティブHTML要素で、ブラウザが直接レンダリングします。visionOSでは立体レンダリングが標準で備わり、iPhoneやiPadでも滑らかに操作できます。W3Cで標準化が進んでいるWeb標準でもあり、コードは将来に向けて互換性を持ちます。この要素に対応していないブラウザ向けには、Appleが公式のpolyfillをフォールバックとして提供しています。

(00:48)

このセッションではアウトドア用品のECサイトを例に、3Dアセットの取得から公開前の最適化までの完全な流れを示します。アセットを取得する方法は3つあります。iPhoneで実物をスキャンする、Blenderなどのツールでゼロから作る、AIで生成する、の3つです。セッションでは、キャンプ用マレットの数枚の写真からTripo3Dで数分以内にUSDZモデルを生成する流れが紹介されました。

(02:22)

USDZはAppleが推奨する形式です。Universal Scene Descriptionをzipパッケージ化した形式で、ジオメトリ、マテリアル、テクスチャ、アニメーションを1つのファイルに収めます。Safariは他の形式にも対応しますが、互換性の観点ではUSDZが第一候補です。

(03:17)

詳細内容

モデルの読み込みとフォールバック

<model>の使い方は<img><video>と同じくらい直感的です。src属性でUSDZファイルを指すだけです。

<!-- src 属性を使う -->
<model src="mallet.usdz"></model>

<!-- <source> 子要素で MIME タイプを指定する -->
<model>
    <source src="mallet.usdz" type="model/vnd.usdz+zip">
</model>

(04:19)

フォールバックも簡単です。<model>の内側に<img>を置くと、この要素に対応していないブラウザでは画像が表示されます。

<model id="mallet" src="mallet.usdz">
    <img src="mallet.png"
         alt="Rubber mallet with wooden handle">
</model>

(04:39)

ポイント:

  • <model>の内側に<img>をネストして、自然なフォールバックを実現します
  • 古いSafariや<model>非対応ブラウザでは画像が自動的にレンダリングされます
  • ユーザーは少なくとも商品の静的ビューを見られます

3Dモデルファイルは数十MBになることが多く、読み込みに時間がかかります。readyプロパティは、モデルの読み込み完了時にresolveされるPromiseを返します。

<model id="mallet" src="mallet.usdz"></model>

<script>
    const model = document.getElementById("mallet");
    model.ready.then(result => {
        // Hide the loading indicator
    }).catch(error => {
        // Loading failed, show fallback
    });
</script>

(05:09)

ポイント:

  • model.readyはPromiseで、モデルの解析が完了するとresolveされます
  • thenコールバック内でloadingアニメーションを非表示にします
  • catchコールバックで読み込み失敗を処理し、フォールバック内容を表示します

<model>にまったく対応していないブラウザにはpolyfillを使えます。

<script type="module">
    if (!window.HTMLModelElement) {
        import("model-element-polyfill.js").then(() => {
            // Polyfill ready to use
        });
    }
</script>

(05:39)

ポイント:

  • window.HTMLModelElementでネイティブ対応を検出します
  • 非対応ならpolyfillスクリプトを動的に読み込みます
  • polyfillはvisionOSの立体レンダリングのようなハードウェア依存機能までは再現できません

スタイルとインタラクション

<model>は独自の仮想空間にレンダリングされ、ページの背景を継承しません。要素に直接background-colorを設定する必要があります。

<model id="mallet" src="mallet.usdz"></model>
<style>
    model {
        background-color: #f4f1ec;
    }
</style>

(06:13)

ポイント:

  • 背景色は常に不透明で、透明度を含む色は不透明色に変換されます
  • <model>要素へ直接CSSを書くことで見た目を制御できます

最も単純なインタラクションは、ユーザーがモデルを自由に回転できるようにすることです。stagemode="orbit"属性を追加します。

<model id="mallet"
       src="mallet.usdz"
       stagemode="orbit">
</model>

(06:47)

ポイント:

  • stagemode="orbit"により、ユーザーはモデルを左右に自由回転できます
  • 上下方向に傾けて指を離すと、モデルはばねのように元の角度へ戻ります
  • 回転中に一部が切れないよう、モデルは自動的に少し縮小されます

視点をカスタマイズしたい場合は、JavaScriptでentityTransformを操作します。先にstagemodeを無効にする点に注意します。

<model id="boot" src="boot.usdz"></model>
<button id="button-side">Side</button>
<button id="button-reset">Reset</button>

<script>
    const model = document.getElementById("boot");
    const initialTransform = model.entityTransform;

    document.getElementById("button-side")
            .addEventListener("click", () => {
        const transform = new DOMMatrix();
        transform.rotateSelf(0, 135, 0);
        model.entityTransform = transform;
    });

    document.getElementById("button-reset")
            .addEventListener("click", () => {
        model.entityTransform = initialTransform;
    });
</script>

(07:31)

ポイント:

  • entityTransformを使う前にstagemode属性を削除するか、"none"に設定します
  • DOMMatrixは3D空間におけるモデルの向きを表します
  • rotateSelf(0, 135, 0)はY軸を中心に135度回転します
  • リセット用にinitialTransformを事前に保存します
  • カスタム回転ではモデルが切れる可能性があるため、位置を手動調整する必要があります

視点を直接切り替えると唐突に見えます。requestAnimationFrameで滑らかな遷移を実装します。

const model = document.getElementById("boot");
const duration = 500;
let currentAngle = 0;
let animationId = null;

function animateTo(targetAngle) {
    if (animationId) cancelAnimationFrame(animationId);
    const startAngle = currentAngle;
    const startTime = performance.now();

    function step(now) {
        const progress = Math.min((now - startTime) / duration, 1);
        const ease = 1 - Math.pow(1 - progress, 3);
        currentAngle = startAngle + (targetAngle - startAngle) * ease;
        model.entityTransform = new DOMMatrix().rotateSelf(0, currentAngle, 0);
        if (progress < 1) animationId = requestAnimationFrame(step);
    }

    requestAnimationFrame(step);
}

document.getElementById("button-side").addEventListener("click", () => animateTo(135));
document.getElementById("button-reset").addEventListener("click", () => animateTo(0));

(08:35)

ポイント:

  • まずcancelAnimationFrameで実行中のアニメーションをキャンセルし、衝突を防ぎます
  • ease = 1 - Math.pow(1 - progress, 3)でease-outのイージングを実現します
  • 各フレームで新しいDOMMatrixを使ってentityTransformを更新します
  • 500ミリ秒の長さは、応答性と視覚的な滑らかさのバランスを取ります

アニメーション再生

USDZファイルにはBlenderやMayaで作ったアニメーションを埋め込めます。<model>は既定で最初のアニメーショントラックを再生し、JavaScriptで再生速度を制御できます。

<model id="bottle" src="bottle.usdz"></model>
<button id="button-play" onclick="play(5)">
    Play
</button>
<button id="button-reverse" onclick="play(-5)">
    Reverse
</button>

<script>
    const model = document.getElementById("bottle");

    function play(rate) {
        model.playbackRate = rate;
        model.play();
    }
</script>

(10:07)

ポイント:

  • model.play()でアニメーション再生を開始します
  • playbackRateで再生速度を制御し、正の値は正方向、負の値は逆再生です
  • 例では5と-5を使って、5倍速の正再生と逆再生を実現しています

AR Quick Look

<model><a rel="ar">タグで包むと、iOSとiPadOSのユーザーはタップして直接AR Quick Lookに入れます。

<a rel="ar" href="bottle.usdz">
    <model id="boot" src="bottle.usdz"></model>
</a>

(11:06)

ポイント:

  • <a rel="ar"><model>と同じUSDZファイルを指します
  • iOS/iPadOSではネイティブAR体験を起動します
  • visionOSではモデルが立体レンダリングで表示され、ユーザーはページから商品を「引き出して」確認できます

コマンドライン最適化ツール

usdcrushはUSDZファイルサイズを大幅に圧縮できます。セッションの例では、7.9 MBのブーツモデルを1.9 MBまで圧縮し、肉眼で分かる画質劣化はありませんでした。

(12:39)

usdrecordはUSDZファイルからサムネイルやフォールバック画像を一括レンダリングできます。商品カタログ全体を走査してfallback画像を自動生成するスクリプトを書けば、手動のスクリーンショットは不要です。

(13:10)

この2つのツールはmacOSにプリインストールされており、USDツールスイートの一部です。

重要ポイント

1. EC商品ページを1行で3D化する

既存の商品画像を<model>タグに置き換え、同じUSDZファイルを読み込みます。ユーザーはページ上で商品を回転して細部を確認し、タップしてARモードに入り、自宅に置いた見た目を確認できます。入口は1行のHTMLです。

  • 実装の考え方: usdrecordでfallback画像を一括生成し、<model>内に<img>をネストしてフォールバックを作り、外側を<a rel="ar">で包んでAR入口を用意します

2. ポートフォリオサイトでインタラクティブな3D展示を行う

デザイナーや建築家は、自分のWebサイトで3D作品を直接展示できます。訪問者はファイルをダウンロードせず、ブラウザ内でモデルを回転・確認できます。stagemode="orbit"の1行でインタラクションを実現できます。

  • 実装の考え方: USDZ形式で書き出し、<model stagemode="orbit">で直接埋め込み、CSSで背景色を設定してページの雰囲気になじませます

3. 教育アプリで3Dモデルを解説する

生物の授業では細胞構造を、歴史の授業では復元された文物モデルを表示できます。entityTransformrequestAnimationFrameでプリセット視点の切り替えを実装し、「断面図」ボタンを押すと特定角度へ滑らかに回転させます。

  • 実装の考え方: いくつかの視点角度を定義し、animateTo()関数でイージング付きの視点切り替えを実装し、playbackRateでモデル内蔵アニメーションを制御します

4. AI生成3Dアセットのワークフロー

Tripo3DやMeshy.aiを使い、数枚の商品写真からUSDZモデルを生成し、usdcrushで圧縮してデプロイします。プロの3Dモデリングスキルは不要です。

  • 実装の考え方: 写真 -> AIでUSDZを生成 -> usdcrushで圧縮 -> usdrecordでfallback画像を生成 -> 公開

5. 3Dコンテンツのクロスプラットフォーム配信

同じHTMLコードでiPhone、iPad、Mac、Vision Proに3Dコンテンツを表示できます。visionOSでは立体的な奥行き効果も加わります。polyfillを組み合わせれば、ネイティブ<model>非対応ブラウザもカバーできます。

  • 実装の考え方: window.HTMLModelElementを検出し、存在しない場合はpolyfillを読み込んで互換性を最大化します

関連セッション

コメント

GitHub Issues · utterances