sample-easyar-mega-annotation-js

演示如何使用Mega的基本功能,在xr-frame基础上使用xr-easyar-session标签启动Mega功能,通过接口加载ema并加载模型资源。

配置和运行

请参考 开发入门 进行配置和运行

如果想创建标准的xr-frame工程,请参考微信官方文档 开始

详解

sample的运行流程基于小程序基本框架,目录pages中存放所有的页面逻辑,components中存放所有被页面使用的组件功能,xr-frame和AR功能的在component中加载和使用。

小程序的目录结构说明:https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html

ema是如何加载的?

<xr-easyar-session
    id="easyar-session"
    api-key="{{apiKey}}"
    api-secret="{{apiSecret}}"
    server-address="{{serverAddress}}"
    app-id="{{appId}}"
    license-key="{{licenseKey}}"
    ...
    bind:ready="onMegaReady"
></xr-easyar-session>

添加xr-easyar-session标签并配置相关数据,绑定ready事件。由于通过接口加载ema,所以不需要设置ara-id参数。

const EasyAR = requirePlugin("EasyARMega");
Component({
    ...
    methods: {
        ...
        onMegaReady(event) {
            ...
        }
    }
})

在js代码中调用微信接口requirePlugin()引入EasyARMega插件,同时实现绑定在ready事件上的onMegaReady方法。

当程序运行时mega组件内部初始化完成之后广播ready事件,并将 EasyARSession 组件通过参数传入,EasyARSession为标签xr-easyar-session上的默认组件。

通过EasyARSession接口请求ema数据

session.queryEma(araID)
.then(ema => {
    ...
});

请求到ema数据之后需要通过BlockHolder持有之后才可以使用

session.holdEma(ema, {clearPrevious: false});

设置clearPrevious参数可决定是否卸载掉旧的ema数据,默认为false。clearPrevious设置为false时会将新数据叠加到场景中,如果新的ema中存在id相同的block和annotation,则会分别使用新的数据替换掉旧的。clearPrevious设置为true时会卸载掉所有已生成在场景中的block和annotation。

通过接口加载ema数据时不会触发emaLoaded事件。

如何根据标注点位加载模型?

ema加载完成后 首先需要创建模型与标注点位(annotation)的对应关系。

/**模型资源信息,这里以键值对的格式排列以方便调用,
    * 信息中的数据格式与xr-frame的资源加载所需的数据格式一致,调用资源加载接口时可以直接设置进去*/
const assetConfigs = {
    "panda": {
        assetId: "panda",//资源id
        type: "gltf",//资源类型,gltf和glb格式的模型都填"gltf"
        src: "https://staticfile-cdn.sightp.com/easyar/webar/mini/xiongmao.gltf",//资源下载链接
        option: null//其他设置参照小程序文档相关说明
    },
    "just_a_girl": {
        assetId: "just_a_girl",
        type: "gltf",
        src: "https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/just_a_girl/index.glb",
        option: null
    },
}
/**annotation与模型资源的对应表,这里以键值对的格式排列,方便调用。
    * 运行之前需要将annotation的id填入key和id位置*/
const metaData = {
    "***请填入标注点位1的ID***": {
        id: "***请填入标注点位1的ID***",//annotation的id
        assetId: "panda",//对应点位的模型的id,模型的加载信息在assetConfigs中
    },
    "***请填入标注点位2的ID***": {
        id: "***请填入标注点位2的ID***",
        assetId: "just_a_girl",
    },
};

assetConfigs中记录的是模型的加载信息,这里添加了一个熊猫模型和一个少女手办的模型的信息,sample使用它们各自的assetId来作为key值进行索引。

metaData中记录的是标注点位与模型的对应关系,使用annotation的id索引获取对应资源的assetId。

annotation 的id可以在Unity编辑器中标注点位时获得

../../_images/HowGetAnnotationId.png

由于需要在运行中加载标注数据,请在使用前确保已使用标注工具完成标注并上传数据。

如何使用Mega Studio进行标注并上传数据,参考 标注工具

为了方便查找,sample均以键值对的形式记录模型和标注对应关系,开发者也可以使用其他任意方式记录模型与标注点位的对应关系。

通过blockHolder获取并遍历所有的annotation

//遍历生成的所有Annotation组件,Annotation继承于xr-frame的compoennt
session.getBlockHolder().annotations.forEach(anno => {
    ...
});

xr-frame的资源加载机制中同一个资源链接加载多次会报出错误,而实际开发过程中同一份资源可能会需要在多个位置放置,所以需要在加载之前先判断资源是否已经在加载队列或者是否已经被加载.

let annotationId = anno.info.id;
let meta = metaData[annotationId];
let model = null;
if (meta) {
    let asset = assetConfigs[meta.assetId];
    if (asset) {
        let status = scene.assets.getAssetWithState(asset.type, asset.assetId);
        if (status.state == 0) {
            scene.assets.loadAsset(asset);
        }
        model = scene.createElement(xrFrameSystem.XRGLTF, { "model": asset.assetId, "anim-autoplay": "" });
    }
}

通过scene.assets.getAssetWithState()得到资源的加载状态信息,通过state判断资源的存在状态,状态为0代表了资源不存在,这里就可以直接开始加载资源。

可以通过微信小程序官方文档来了解资源系统

https://developers.weixin.qq.com/miniprogram/dev/component/xr-frame/assets/

XRGLTF节点可以在资源加载过程中提前创建,通过在createElement时设置model参数可以指定要创建的模型资源assetId,等到资源加载完成之后会自动设置到XRGLTF节点上。设置"anim-autoplay"可自动播放模型动画。

关于GLTF模型的介绍参考微信官方文档

https://developers.weixin.qq.com/miniprogram/dev/component/xr-frame/gltf/

除了使用GLTF模型以外,也可以创建3d引擎内置的基础几何体,通过创建XRMesh来使用自定义mesh或者引擎内置的几何体资源,sample中使用cube来代替没有对应资源的标注点位。

if (!model) {
    //创建xr-frame内置几何体
    model = scene.createElement(xrFrameSystem.XRMesh, { geometry: "cube" });
}

内置几何体的类型通过geometry来设置,具体关于XRMesh的说明参考微信小程序官方文档

https://developers.weixin.qq.com/miniprogram/dev/api/xr-frame/classes/XRMesh.html

模型生成出来之后,需要放置到对应的标注位置上,只需要将模型节点设置为annotation的子节点即可。

anno.el.addChild(model);
let transform = model.getComponent(xrFrameSystem.Transform);
transform.position.setValue(0, 0, 0);
transform.rotation.setValue(0, 0, 0);
transform.scale.setValue(1, 1, 1);

为了确保位置方向大小与标注点位一致,需要通过模型的transform组件将position和rotation的值归零、将scale的值归一。position、rotation和scale为自身相对于父节点的本地状态,设置这三个参数可以快速将模型与父节点annotation的状态进行匹配。

transform的相关说明参考微信小程序API文档

https://developers.weixin.qq.com/miniprogram/dev/api/xr-frame/classes/Transform.html