前言
xr-frame是一套小程序官方提供的XR/3D应用解决方案,基于混合方案实现,性能逼近原生、效果好、易用、强扩展、渐进式、遵循小程序开发标准。xr-frame在基础库v2.32.0开始基本稳定,发布为正式版,但仍有一些功能还在开发,目前(2024.08.24)有一些限制如下:
1最低要求客户端iOS8.0.29、安卓8.0.30及以上,推荐稳定版在iOS8.0.36、安卓8.0.35及以上。
2基础库最低2.27.1及以上,推荐2.32.0及以上。
3开发工具需要最新版本,建议Nightly版本。
4小程序全局同一时刻只能存在一个xr-frame组件,否则可能会发生异常。
5同一个xr-frame组件只能存在一个xr-scene,并且必须为顶层。
6目前不支持和小程序传统标签比如混写。
7目前不支持wxml自动补全,真机调试需要特别注意,见真机调试文档。
后续的展望:
1 XR-FRAME内置特色的UI组件,让开发者可以在XR-FRAME组件中写UI,来实现一套酷炫的UI系统。
2 AR/VR能力持续增强,支持眼睛设备。
3 交互手段进一步强化,物理碰撞、触发等功能(已完成,待发布)。
4 工具能力强化,包括标签属性自动补全等。
本文以该解决方案的官方demo为参考开发微信小程序的图片识别并叠加模型动作的功能,具体使用的是Face识别模式,去识别出摄像头画面中的会通过图像算法识别出人面部的特征点,然后变换到3D空间,继而进行追踪,可用于一些脸部换装(眼镜、面具和口罩等)应用等场景。这里以面部识别的鼻梁位置上添加一个面罩模型,同时,在下巴和两眼眉毛位置添加一个带动作的蝴蝶模型。此外,在屏幕的画面上增加了案例中的全屏后处理效果。
效果
识别中:
模型叠加:
硬广
自制3D版三维搭建俄罗斯方块WX小游戏,走过路过可以扫描支持。
三维的消除,地狱难度:
实现功能
该功能基本是使用官方的微信小程序xr-frame系统的示例集中的"人脸识别案例"(/pages/ar/scene-ar-face-3d)修改而来,组件使用了components/xr-ar-face-3d,基本的代码都是沿用的,只不过修改了识别的展示,将云上的模型资源用本地的素材替换,并使用javascript工程代替了微信小程序 案例的typescript 。
素材准备
本demo较为简单计划只有两个界面,一个主界面和一个人脸识别界面,主要就是一个主页背景(AI生成)、一个全局后期效果的动画和识别叠加的模型(蝴蝶、人脸面具等),资源如下:
主页搭建
主页的设计较为简单,一个背景图,附加一个标题,一个"AR识脸"的按钮,点击后进入人脸识别页面。
html
<!--pages/home/index.wxml-->
<view class="home-container">
<image class="home-bg" src="../../assets/bgimg.png"/>
<view class="title">畅游AR世界</view>
<view class="btns">
<navigator class="btn-nav" url="/pages/facear/index">
<button class="btn green">AR识脸</button>
</navigator>
</view>
</view>
识别组件
由于"目前不支持和小程序传统标签比如混写"的限制,所以识别的功能需要制作成组件放入到页面,识别的组件参考的是components/xr-ar-face-3d。
首先人脸识别需要使用模型为Face和手机的前置摄像头,需要修改xr-scene的 ar-system属性:
javascript
ar-system="modes:Face;camera:Front"
这里我们将ar-system的modes改为了Face,并且新增设置了camera属性为Front,表示开启前置相机(注意前置相机在客户端8.0.31后才支持)。
Json文件设定组件,并指定渲染为xr-frame渲染:
javascript
{
"component": true,
"usingComponents": {},
"renderer": "xr-frame"
}
wxml中修改了xr的资源加载如下:
html
<xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
<xr-asset-load type="gltf" asset-id="fox_mask" src="/assets/mask.glb" />
<xr-asset-load type="gltf" asset-id="hudie" src="/assets/hudie.glb"/>
<xr-asset-load type="gltf" asset-id="joker_mask" src="/assets/joker_mask.glb" />
<xr-asset-load asset-id="anim" type="keyframe" src="/assets/animation.json"/>
</xr-assets>
这里就将面具和蝴蝶glb的模型加载进入场景,类型是"gltf"模型,asset-id可以自定义编号,不过识别跟踪的时候需要绑定,src是资源的地址可以是远程或者本地地址,这里模型是放到assets文件夹下所以路径是/assets/***.glb。animation.json是全局的后处理效果动画。
创建AR追踪器实现如下:
html
<xr-ar-tracker id='tracker' mode="Face" auto-sync="45 16 35 40">
<xr-node name="nose" >
<xr-gltf node-id="fox_mask" position="0 0 0" rotation="0 180 0" scale=".0045 .0045 .0045" model="fox_mask"></xr-gltf>
</xr-node>
<xr-node name="chin" >
<xr-gltf model="hudie" rotation="0 90 -90" anim-autoplay scale="1 1 1" ></xr-gltf>
</xr-node>
<xr-node name="l_eye" >
<xr-gltf model="hudie" position="0 0 -0.2" rotation="0 90 -90" anim-autoplay scale="0.4 0.4 0.4" ></xr-gltf>
</xr-node>
<xr-node name="r_eye" >
<xr-gltf model="hudie" position="0 0 -0.2" rotation="0 90 -90" anim-autoplay scale="0.4 0.4 0.4" ></xr-gltf>
</xr-node>
</xr-ar-tracker>
其中mode是ar在追踪的模式,这里是Face(人脸)识别模式,auto-sync属性是一个数字数组,用于将对应顺序的子节点绑定到某个特征点上,其中-1表示忽略该节点,在运行过程中会自动同步变换信息,后续人脸特征点模块详细概述。
追踪器的子节点是xr-gltf 即识别后的模型展示,model就是关联asset-id,rotation修改模型旋转值,scale修改模型缩放,这两个值可能需要多次调整才能达到需要的效果,还有position用于位置修改。anim-autoplay设置自动播放模型动画(有动画才生效)。
后处理
为相机应用了一个渐晕vignette后处理效果,并为其加上了帧动画控制参数:
javascript
{
"keyframe": {
"vignette": {
"0": {
"asset-post-process.assetData.intensity": 0
},
"100": {
"asset-post-process.assetData.intensity": 1
}
}
},
"animation": {
"vignette": {
"keyframe": "vignette",
"duration": 2,
"ease": "ease-in-out",
"loop": -1,
"direction": "both"
}
}
}
之前在资源加载的处理已经加载了animation.json文件,这里场景中直接加入一个xr-asset-post-process后处理资源,并将相机的 post-process 赋值为vignette(asset-id):
html
<xr-asset-post-process asset-id="vignette" type="vignette" data="intensity:1,smoothness:4,color:1 0 0 1" anim-keyframe="anim" anim-autoplay/>
<xr-camera
id="camera" node-id="camera" clear-color="0.925 0.925 0.925 1"
background="ar" is-ar-camera near="0.01" post-process="vignette"
></xr-camera>
人脸特征点
人脸(Face)模式的特征点和模型的对应关系是通过auto-sync属性来对应关联的,目前官网给出的完整人脸特征点以及值如下图:
如上的人脸识别组件中,auto-sync属性设置如下:
auto-sync="45 16 35 40
这个属性的值表示一个数组,数组的值用空格隔开,也就是说将xr-ar-tracker的对应顺序的子节点绑定到某个特征点,这里就是nose模型绑定到识别出来的人脸的鼻梁(45)位置,chin模型绑定到识别出来的人脸的下巴(16)位置,其他依次按节点和面部特征点关联上。
识别界面
上一步已经将ar人脸识别的功能弄成了组件,在识别界面的搭建主要是组件的使用,这里先在json中引用组件:
javascript
{
"usingComponents": {
"xr-face-ar": "../../components/xr-face-ar/index"
},
"navigationBarTitleText": "AR识脸",
"disableScroll": true,
"renderer": "webview"
}
这里将components/xr-face-ar组件引用为xr-face-ar标签,设置标题和页面不可滑动。
在wxml中插入xr-face-ar:
html
<view class="ar-page">
<xr-face-ar
disable-scroll
id="main-frame"
class="main-ar-frame"
width="{{renderWidth}}"
height="{{renderHeight}}"
style="width:{{width}}px;height:{{height}}px;top:{{top}}px;left:{{left}}px;display:block;"
bind:arTrackerState="handleARTrackerState"
/>
</view>
其中
javascript
bind:arTrackerState="handleARTrackerState"
将ar追踪器的状态(arTrackerState)绑定到js中的handleARTrackerState函数:
javascript
handleARTrackerState({detail}) {
const {state, error} = detail;
console.log(" handleARTrackerState 状态变更:"+ state);
this.setData({
arTrackerShow: state == 2,
arTrackerState: wx.getXrFrameSystem().EARTrackerState[state],
arTrackerError: error
});
}
在handleARTrackerState中可以根据识别状态的变更编写更细节的交互逻辑。