xr-frame是一套微信小程序官方提供的XR/3D应用解决方案,基于混合方案实现,性能逼近原生、效果好、易用、强扩展、渐进式、遵循微信小程序开发标准。
在这一章中,我们将会带大家从头开始,用它构建一个XR微信小程序。
本文只是开始指南,更加详细的信息请见组件框架文档和API文档。
⚠
xr-frame在基础库v2.32.0开始基本稳定,发布为正式版,但仍有一些功能还在开发,请见限制和展望。
xr-frame是一套微信小程序官方提供的XR/3D应用解决方案,基于混合方案实现,性能逼近原生、效果好、易用、强扩展、渐进式、遵循微信小程序开发标准。
在这一章中,我们将会带大家从头开始,用它构建一个XR微信小程序。
本文只是开始指南,更加详细的信息请见组件框架文档和API文档。
⚠
xr-frame在基础库v2.32.0开始基本稳定,发布为正式版,但仍有一些功能还在开发,请见限制和展望。
至此,我们简单体验了一下微信小程序框架的各种能力,但主要是wxml为主,逻辑很少。对于入门的开发者,我们倾向于提供给开发者非常简单就能实现不错的效果,这也是渐进式开发的基础。更多详细的文档教程可见组件文档。
但除了这些简单的用法外,微信小程序框架还提供了高度灵活的组件化特性。开发者可以按照自身需求,定制属于自己的组件、元素、所有的资源等等,甚至如果有需求,我们还可以开放底层的RenderGraph来定制渲染流程。详细的定制开发能力可见接下来各个部分的文档,我们都做了比较详细的说明和引导。
好,入门就到此为止了,技术始终只是一个工具,剩下的就交给身为创作者的你了!在此之前,不如先看看这些DEMO吧:

好,终于到了这里,当我们做出了一些令人满意的效果后最重要的什么?当然是分享给好友!下面就让我们用xr-frame内置的分享系统来完成这个功能:
......
<xr-mesh node-id="mesh-plane" geometry="plane" material="mat" cube-shape="autoFit:true" bind:touch-shape="handleShare" />
......
handleShare: function() {
this.scene.share.captureToFriends();
}
给识别后显示的视频Mesh加上了上面说过的shape绑定了触摸事件,然后在事件处理函数中直接用this.scene.share.captureToFriends()即可,效果如下:
当然,很多时候我们只是需要图片,然后用它接入微信小程序的其他分享接口比如
onShareAppMessage生命周期,此时使用share.captureToLocalPath接口即可,详细可见组件文档。
在主体渲染结束后,好像还是有些单调,缺乏一种和现实世界的明确分离感,这时候就可以用全屏后处理来实现一些更好玩的效果:
......
<xr-asset-load asset-id="anim" type="keyframe" src="/assets/animation.json"/>
......
<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 clear-color="0.4 0.8 0.6 1" background="ar" is-ar-camera post-process="vignette" />
这里我为相机应用了一个渐晕vignette后处理效果,并为其加上了帧动画控制参数:
{
"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"
}
}
}
最终效果如下:
光是播放视频似乎还是有点单调,这里我们可以请出粒子系统制造一些魔法来让整个场景更加生动:
......
<xr-asset-load type="texture" asset-id="point" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/particles/point.png" />
......
<xr-node wx:if="{{loaded}}">
<xr-ar-tracker
mode="Marker" bind:ar-tracker-switch="handleTrackerSwitch"
src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/xr-frame-team/2dmarker/hikari.jpg"
>
<xr-mesh node-id="mesh-plane" geometry="plane" material="mat" />
<xr-particle
capacity="500" emit-rate="20"
size="0.03 0.06" life-time="2 3" speed="0.04 0.1"
start-color="1 1 1 0.8" end-color="1 1 1 0.2"
emitter-type="BoxShape"
emitter-props="minEmitBox:-0.5 0 0.5,maxEmitBox:0.5 0.2 0,direction:0 0 -1,direction2:0 0 -1"
texture="point"
/>
</xr-ar-tracker>
</xr-node>
......
在上一步2DMarker视频的基础上,我们加上了xr-particle元素,使用了新加载的贴图point和boxShape发射器以及其他参数来生成粒子,最终效果如下(当然限于本人美术功底效果非常一般,相信你可以随便调一调完爆我233):
最后的能力就是2D Marker,其用于精准识别有一定纹理的矩形平面,我们可以将其配合视频纹理,只需要非常简单的代码就可以完成一个效果,首先是wxml:
这里是默认示例资源,你可以换成自己的照片和视频,如果只是想要尝试,直接复制访问
src的地址到浏览器打开即可。
<xr-scene ar-system="modes:Marker" bind:ready="handleReady">
<xr-assets bind:loaded="handleAssetsLoaded">
<xr-asset-load
type="video-texture" asset-id="hikari" options="loop:true"
src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/xr-frame-team/2dmarker/hikari-v.mp4"
/>
<xr-asset-material asset-id="mat" effect="simple" uniforms="u_baseColorMap: video-hikari" />
</xr-assets>
<xr-node wx:if="{{loaded}}">
<xr-ar-tracker
mode="Marker" bind:ar-tracker-switch="handleTrackerSwitch"
src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/xr-frame-team/2dmarker/hikari.jpg"
>
<xr-mesh node-id="mesh-plane" geometry="plane" material="mat" />
</xr-ar-tracker>
</xr-node>
<xr-camera clear-color="0.4 0.8 0.6 1" background="ar" is-ar-camera />
</xr-scene>
这里我们把ar-system的模式改成了Marker,随后将ar-tracker的类型也改为了Marker,并且换了一个识别源,然后加载一个准备好的视频纹理,并将simple材质的颜色换为了纹理u_baseColorMap,同时关闭了混合。注意我们使用了变量loaded来控制ar-tracker的显示并绑定了事件ar-tracker-switch,这是为了在脚本中处理:
handleAssetsLoaded: function ({detail}) {
this.setData({loaded: true});
},
handleTrackerSwitch: function ({detail}) {
const active = detail.value;
const video = this.scene.assets.getAsset('video-texture', 'hikari');
active ? video.play() : video.stop();
}
在视频加载完成后再显示内容,并且在ar-tracker-switch事件也就是识别成功后在播放视频,优化体验,最终效果如下:
人体之外还有的能力就是两个marker了。其一是OSD Marker,一般以一个现实中物体的照片作为识别源,来识别出这个物体的在屏幕中的二维区域,我们已经做好了到三维空间的转换,但开发者需要自己保证tracker下模型的比例是符合识别源的。OSD模式在识别那些二维的、特征清晰的物体效果最好,比如广告牌。
这里是默认示例资源,你可以换成自己的照片和视频,如果只是想要尝试,直接复制访问
src的地址到浏览器打开即可。
<xr-scene ar-system="modes:OSD" bind:ready="handleReady">
<xr-assets bind:loaded="handleAssetsLoaded">
<xr-asset-material asset-id="mat" effect="simple" uniforms="u_baseColorFactor: 0.8 0.6 0.4 0.7" states="alphaMode:BLEND" />
</xr-assets>
<xr-node>
<xr-ar-tracker
mode="OSD" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/marker/osdmarker-test.jpg"
>
<xr-mesh geometry="plane" material="mat" rotation="-90 0 0" />
</xr-ar-tracker>
</xr-node>
<xr-camera clear-color="0.4 0.8 0.6 1" background="ar" is-ar-camera />
</xr-scene>
这里我们把ar-system的模式改为了OSD,相应的ar-tracker的模式也改为了OSD,这种模式下需要提供src,也就是要识别的图像。并且这次我们使用了一个效果为simple的材质,因为不需要灯光,同时为了更好看效果,在material的states设置了alphaMode:BLEND,即开启透明混合,然后将uniforms设置颜色u_baseColorFactor,并且注意其透明度为0.7。最终效果如下:
除了人脸之外,我们也提供了躯体和人手识别,用法都大同小异,但人手除了上面所属的特征点同步,还提供了“手势”识别,这个比较有趣,让我们来看看:
<xr-scene ar-system="modes:Hand" bind:ready="handleReady" bind:tick="handleTick">
<xr-assets bind:loaded="handleAssetsLoaded">
<xr-asset-load type="gltf" asset-id="cool-star" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/cool-star.glb" />
</xr-assets>
<xr-env env-data="xr-frame-team-workspace-day" />
<xr-light type="ambient" color="1 1 1" intensity="1" />
<xr-light type="directional" rotation="40 70 0" color="1 1 1" intensity="3" cast-shadow />
<xr-ar-tracker id="tracker" mode="Hand" auto-sync="4">
<xr-gltf model="cool-star" anim-autoplay />
</xr-ar-tracker>
<xr-camera clear-color="0.4 0.8 0.6 1" background="ar" is-ar-camera />
</xr-scene>
wxml这里我们换了个模型,并且将ar-system和ar-tracker的模式都换成了Hand,并修改了ar-tracker的特征点还加上了个id方便索引,最后还给scene绑定了tick事件,而接下来就是js逻辑了:
handleAssetsLoaded: function ({detail}) {
this.setData({loaded: true});
const el = this.scene.getElementById('tracker');
this.tracker = el.getComponent(wx.getXrFrameSystem().ARTracker);
this.gesture = -1;
},
handleTick: function() {
if (!this.tracker) return;
const {gesture, score} = this.tracker;
if (score < 0.5 || gesture === this.gesture) {
return;
}
this.gesture = gesture;
gesture === 6 && wx.showToast({title: '好!'});
gesture === 14 && wx.showToast({title: '唉...'});
}
最重要的是handleTick方法,在每一帧我们拿到tracker的引用,然后获得它的属性gesture和score,其中gesture为手势编号而score为置信度。具体的手势编号可见组件文档,这里我先用置信度过滤了一遍,随后依据手势gesture的值(6为赞,14为踩)来提示不同信息,效果如下:
在初步了解了AR系统后,我们便可以尝试更多不同的模式来玩做一些好玩的效果。接下来的是人脸识别模式,为此我们只需要在上面的代码中改几句,就可以给自己带上Joker的面具(逃):
⚠️ 手势、人脸、躯体识别都需要基础库v2.28.1以上。
<xr-scene ar-system="modes:Face;camera:Front" bind:ready="handleReady" bind:tick="handleTick">
<xr-assets bind:loaded="handleAssetsLoaded">
<xr-asset-load type="gltf" asset-id="mask" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/jokers_mask_persona5.glb" />
</xr-assets>
<xr-env env-data="xr-frame-team-workspace-day" />
<xr-light type="ambient" color="1 1 1" intensity="1" />
<xr-light type="directional" rotation="40 70 0" color="1 1 1" intensity="3" />
<xr-ar-tracker mode="Face" auto-sync="43">
<xr-gltf model="mask" rotation="0 180 0" scale="0.5 0.5 0.5" />
</xr-ar-tracker>
<xr-camera clear-color="0.4 0.8 0.6 1" background="ar" is-ar-camera />
</xr-scene>
这里我们将ar-system的modes改为了Face,并且新增设置了camera属性为Front,表示开启前置相机(注意前置相机在客户端8.0.31后才支持,这里仅做演示)。同时在ar-tracker这边,我们将mode改为了和ar-system一样的Face,并追加了属性auto-sync,这是一个数字数组,表示将识别出的面部特征点和对应顺序的子节点绑定并自动同步,具体的特征点可见组件文档详细描述。
到这里,我们实现了3D场景的渲染和交互,但框架毕竟是叫做XR-frame,所以接下来我们就用内置的AR系统来改造一下这个场景,让它具有AR能力吧。改造非常简单,我们首先将所有的无关物体移除,然后使用ar-system和ar-tracker,并修改一下xr-camera的相关属性is-ar-camera和background="ar"就好:
<xr-scene ar-system="modes:Plane" bind:ready="handleReady">
<xr-assets bind:loaded="handleAssetsLoaded">
<xr-asset-load type="gltf" asset-id="anchor" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/ar-plane-marker.glb" />
<xr-asset-load type="gltf" asset-id="miku" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/miku.glb" />
</xr-assets>
<xr-env env-data="xr-frame-team-workspace-day" />
<xr-light type="ambient" color="1 1 1" intensity="1" />
<xr-light type="directional" rotation="40 70 0" color="1 1 1" intensity="3" cast-shadow />
<xr-ar-tracker mode="Plane">
<xr-gltf model="anchor"></xr-gltf>
</xr-ar-tracker>
<xr-node node-id="setitem" visible="false">
<xr-gltf model="miku" anim-autoplay scale="0.08 0.08 0.08" rotation="0 180 0"/>
</xr-node>
<xr-camera clear-color="0.4 0.8 0.6 1" background="ar" is-ar-camera />
</xr-scene>
注意这里我们开启的ar-system的模式为Plane,即平面识别,这种模式下相机不能被用户控制,需要将控制器、target等都删掉,同时ar-tracker的mode要和ar-system的完全一致。之后再脚本中写一点简单的逻辑:
handleAssetsLoaded: function({detail}) {
wx.showToast({title: '点击屏幕放置'});
this.scene.event.add('touchstart', () => {
this.scene.ar.placeHere('setitem', true);
});
}