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 使用說明