Table of Contents

如何在 xr-frame 執行階段載入 AR 場景下的 3D 內容

本文詳細闡述了 xr-frame 資源載入與節點掛載的分離機制,透過腳本動態實現 3D 內容在 Block 節點下的靈活掛載,實現 AR。

官方資料

官方資料中已經有充分的內容說明如何在執行階段載入 3D 內容,本文中僅簡要說明一些 AR 場景下常用的內容和載入方式。

資源載入 vs 節點掛載

在 xr-frame 中,顯示一個 3D 模型分為兩個階段:

  1. 資源載入:指將模型檔案(如 .glb )從網路或本地下載並解析到記憶體中。此時模型已就緒,但在場景中不可見。

  2. 節點掛載:指在場景樹中建立一個節點,並將已載入的資源關聯到該節點上。此時模型才會正式出現在渲染畫布中。

如何使用程式碼動態載入 3D 內容

  1. 資源載入

    透過 xr-frame 場景的資源管理系統呼叫 loadAsset手動載入資源。

    參數中的 type 指資源類型,assetId 指載入後的資源 id,src 指資源的 url,一般是資源託管伺服器的位址。

    需要記錄 assetId 用於後續的掛載和釋放資源。

    try {
        await scene.assets.loadAsset({type: 'gltf', assetId: 'panda', src: 'url/EasyARPanda.glb'});
    } catch (err) {
        console.error(`Failed to load assets: ${err.message}`);
    }
    
  2. 節點掛載

    使用 element.addChild() 將載入好的模型放在 ShadowRoot 下。

    const root = scene.getElementById("shadow-root");
    let panda = scene.createElement(xrFrameSystem.XRGLTF,
        {
            "model": "panda",
            "anim-autoplay": ""
        }
    );
    root.addChild(panda);
    

    ShadowRoot 元素是 xr-frame 專門用來防止動態建立和移除節點的根節點,詳見 Shadow節點

    使用插件物件提供的 createXRNodeFromNodeAnnotation 方法能夠根據 EMA 資料建立 Block 的子節點,確保 3D 內容顯示在正確的空間位置。

    const nodeAnnotation = annotation as easyar.ema.v0_5.Node;
    const xrNode: xrfs.XRNode = easyarPlugin.createXRNodeFromNodeAnnotation(nodeAnnotation, blockHolder);
    let panda = scene.createElement(xrFrameSystem.XRGLTF,
        {
            "model": "panda",
            "anim-autoplay": ""
        }
    );
    xrNode.addChild(panda);
    

如何在 Block 下不使用標註直接掛載內容

警告

使用此方法的前提是,您已驗證該 LocalTransform 的數值在 xr-frame 座標系下能夠實現預期的渲染效果。

除此以外的情況請使用 Unity 編輯器的標註功能實現。

透過 getBlockById(id) 取得場景樹上的 block 節點物件,如果不存在相應的 block 節點說明對這個 Block 的定位還未成功過(在第一次定位到該 Block 時節點會被自動建立)。可以用 holdBlock(blockInfo, blockTransformInput) 建立一個該 Block 的節點,也可以在定位回呼中判斷對該 Block 的定位成功再掛載內容。

提示

在 Unity 編輯器的場景樹中選擇 Block 節點 記錄它 Inspector 面板上顯示的 ID

Unity編輯器中的BlockID

也可以在雲定位庫頁面中查到 Block ID

定位庫中的BlockID

const blockID = "aaaa1234-bbbb-cccc-dddd-eeeeee123456"
if (!blockHolder.getBlockById(blockParent.id)) {
    // 沒有存在的 Block 節點,建立一個
    blockHolder.holdBlock({
        id: blockID
    })
}
let blockElement = blockHolder.getBlockById(blockParent.id).el;

將模型節點以掛載到指定的 Block 下,分別用 position.setArray()quaternion.set()scale.setArray() 把修改模型節點的 LocalTransform

export interface LocalTransform {
    /** @description 位置 */
    position: xrfs.Vector3;
    /** @description 旋轉 */
    rotation: xrfs.Quaternion;
    /** @description Scale */
    scale: xrfs.Vector3;
}

// 假設有一個已知的在 Block 下的 LocalTransform
const targetTransform: LocalTransform;

blockElement.addChild(modelNode);
let modelTransform = modelNode.getComponent(xrFrameSystem.Transform);
    modelTransform.position.setArray([
        targetTransform.position.x,
        targetTransform.position.y,
        targetTransform.position.z
    ]);
    let annoRotation = new xrFrameSystem.Quaternion().setValue(
        targetTransform.rotation.x,
        targetTransform.rotation.y,
        targetTransform.rotation.z,
        targetTransform.rotation.w
    );
    modelTransform.quaternion.set(annoRotation);
    modelTransform.scale.setArray([
        targetTransform.scale.x,
        targetTransform.scale.y,
        targetTransform.scale.z
    ]);

xr-frame 支援的資源類型

  • Texture 紋理和影像
  • CubeTexture 立方體紋理
  • VideoTexture 影片紋理
  • EnvData 環境
  • GLTF 模型
  • Keyframe 幀動畫
  • Atlas 圖集

每種資源的載入方法詳細見微信官方文件xr-frame 官方範例

附註

支援的 GLTF 格式及拓展參考 xr-frame 官方 GLTF 使用說明