vue3+ts+uniapp微信小程序xr-frame实现AR追踪器(ARTracker)

xr-frame 是一套小程序官方提供的XR/3D应用解决方案,基于混合方案实现,性能逼近原生、效果好、易用、强扩展、渐进式、遵循小程序开发标准,官方文档:https://developers.weixin.qq.com/miniprogram/dev/component/xr-frame/overview/#%E6%A6%82%E8%BF%B0

这次我们产品有一个需求,要根据不同的卡片内容,展示对应的视频,并在画面中展示出来,这就用到了小程序的AR追踪器技术。非常非常不巧的是,我们的小程序用的框架是uniapp,而且还是vue3写的,所以你懂的,新技术就是不太会适配,好在查遍整个互联网,还是被我找到了解决办法,使用vue3+uniapp的时候很多人都会遇到各种奇奇怪怪的问题,我也是,这里就记录一下踩坑经历。演示项目已开源,开源地址:https://github.com/Sjj1024/uniapp-vue3

创建xr微信模块

在项目根目录wxcomponents中创建xr-2d-video组件,并创建小程序的文件:

文件包含:index.js + index.json + index.wxml三个

index.js内容如下:

javascript 复制代码
Component({
    behaviors: [require('../common/share-behavior').default],
    properties: {
        markerImg: {
            type: String,
        },
    },
    data: {
        loaded: false,
        arReady: false,
    },
    lifetimes: {
        async attached() {
            console.log('data', this.data)
        },
    },
    methods: {
        handleReady({ detail }) {
            const xrScene = (this.scene = detail.value)
            console.log('xr-scene', xrScene)
        },
        handleAssetsProgress: function ({ detail }) {
            console.log('assets progress', detail.value)
        },
        handleAssetsLoaded: function ({ detail }) {
            this.setData({ loaded: true })
        },
        handleTrackerSwitch: function (event) {
            console.log('handleTrackerSwitch', event)
            const detail = event.detail
            const active = detail.value
            const video = this.scene.assets.getAsset('video-texture', 'hikari')
            active ? video.play() : video.stop()
        },
        handleTracker2Switch: function (event) {
            console.log('handleTracker2Switch', event)
            const detail = event.detail
            const active = detail.value
            const video = this.scene.assets.getAsset('video-texture', 'fire')
            active ? video.play() : video.stop()
        },
        handleARReady: function ({ detail }) {
            console.log('arReady')
            this.setData({
                arReady: true,
            })
        },
        handleLog: function ({ detail }) {
            console.log('log', detail.value)
        },
    },
})

index.json:

javascript 复制代码
{
    "component": true,
    "usingComponents": {},
    "renderer": "xr-frame"
}

index.wxml:

javascript 复制代码
<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://devusage.oss-cn-shanghai.aliyuncs.com/songjiangjiang/test/jian.mp4"
        />
        <xr-asset-material
            asset-id="mat"
            effect="simple"
            uniforms="u_baseColorMap: video-hikari"
        />
        <!-- 第二个视频 -->
        <xr-asset-load
            type="video-texture"
            asset-id="fire"
            options="loop:true"
            src="https://devusage.oss-cn-shanghai.aliyuncs.com/songjiangjiang/test/fire.mp4"
        />
        <xr-asset-material
            asset-id="mat2"
            effect="simple"
            uniforms="u_baseColorMap: video-fire"
        />
    </xr-assets>

    <xr-node wx:if="{{ loaded }}">
        <xr-ar-tracker
            mode="Marker"
            bind:ar-tracker-switch="handleTrackerSwitch"
            src="https://devusage.oss-cn-shanghai.aliyuncs.com/songjiangjiang/static/cat.jpg"
        >
            <xr-mesh node-id="mesh-plane" geometry="plane" material="mat" />
        </xr-ar-tracker>
        <xr-ar-tracker
            mode="Marker"
            bind:ar-tracker-switch="handleTracker2Switch"
            src="https://devusage.oss-cn-shanghai.aliyuncs.com/songjiangjiang/test/yuji.jpg"
        >
            <xr-mesh node-id="mesh-plane2" geometry="plane" material="mat2" />
        </xr-ar-tracker>
    </xr-node>

    <xr-camera clear-color="0.4 0.8 0.6 1" background="ar" is-ar-camera />
</xr-scene>

在pages.json中添加这个组件:

Vue3中引入并使用

在vue3页面中创建并引入这个组件,注意要先获取到 screenWidth, screenHeight, renderWidth, renderHeight 这四个变量,分别是屏幕的宽高和渲染的宽高。通过uni.uni.getSystemInfo可以获取到设备的信息。

获取设备信息的代码:

javascript 复制代码
    // 获取顶部状态栏高度
    uni.getSystemInfo({
        success: (result: any) => {
            // 获取手机系统的状态栏高度(不同手机的状态栏高度不同)  ( 不要使用uni-app官方文档的var(--status-bar-height) 官方这个是固定的20px  不对的 )
            console.log('当前手机设备信息', result)
            let statusBarHeight = result.statusBarHeight + 'px'

            // 获取右侧胶囊的信息 单位px
            const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
            console.log('胶囊信息', menuButtonInfo)

            //bottom: 胶囊底部距离屏幕顶部的距离
            //height: 胶囊高度
            //left:   胶囊左侧距离屏幕左侧的距离
            //right:  胶囊右侧距离屏幕左侧的距离
            //top:    胶囊顶部距离屏幕顶部的距离
            //width:  胶囊宽度
            // console.log(menuButtonInfo.width, menuButtonInfo.height, menuButtonInfo.top)
            // console.log('计算胶囊右侧距离屏幕右边距离', result.screenWidth - menuButtonInfo.right)
            let menuWidth = menuButtonInfo.width + 'px'
            let menuHeight = menuButtonInfo.height + 'px'
            let menuBorderRadius = menuButtonInfo.height / 2 + 'px'
            let menuRight = result.screenWidth - menuButtonInfo.right + 'px'
            let menuTop = menuButtonInfo.top + 'px'
            let contentTop = result.statusBarHeight + 44 + 'px'
            let menuLeft = menuButtonInfo.left + 'px'

            let menuInfo = {
                statusBarHeight: statusBarHeight, //状态栏高度----用来给自定义导航条页面的顶部导航条设计padding-top使用:目的留出系统的状态栏区域
                menuWidth: menuWidth, //右侧的胶囊宽度--用来给自定义导航条页面的左侧胶囊设置使用
                menuHeight: menuHeight, //右侧的胶囊高度--用来给自定义导航条页面的左侧胶囊设置使用
                menuBorderRadius: menuBorderRadius, //一半的圆角--用来给自定义导航条页面的左侧胶囊设置使用
                menuRight: menuRight, //右侧的胶囊距离右侧屏幕距离--用来给自定义导航条页面的左侧胶囊设置使用
                menuTop: menuTop, //右侧的胶囊顶部距离屏幕顶部的距离--用来给自定义导航条页面的左侧胶囊设置使用
                contentTop: contentTop,
                screenHeight: result.screenHeight,
                screenWidth: result.screenWidth,
                devicePixelRatio: result.devicePixelRatio,
                windowWidth: result.windowWidth, // 屏幕宽高,绘制海报时候使用
                windowHeight: result.windowHeight,
                menuLeft: menuLeft,
            }
            uni.setStorageSync('menuInfo', menuInfo)
        },
        fail: (error) => {
            console.log(error)
        },
    })

还有最重要的,就是修改 node_modules/@dcloudio/uni-mp-weixin/dist/uni.compiler.js 这个文件中的一个变量:customElements,在里面添加上 xr-2d-video:

运行后,使用手机测试即可看到效果:

相关推荐
海鸥两三3 小时前
uniapp 小程序引入 uview plus 框架,获得精美的UI框架
前端·vue.js·ui·小程序·uni-app
郑州光合科技余经理13 小时前
乡镇外卖跑腿小程序开发实战:基于PHP的乡镇同城O2O
java·开发语言·javascript·spring cloud·uni-app·php·objective-c
2501_9160088920 小时前
iOS 跨平台开发实战指南,从框架选择到开心上架(Appuploader)跨系统免 Mac 发布全流程解析
android·macos·ios·小程序·uni-app·iphone·webview
QuantumLeap丶2 天前
《uni-app跨平台开发完全指南》- 06 - 页面路由与导航
前端·vue.js·uni-app
用户9714171814272 天前
uniapp页面路由
vue.js·uni-app
Kingsaj2 天前
uni-app打包app -- 在用户首次启动 App 时,强制弹出一个“用户协议与隐私政策”的确认对话框。
服务器·ubuntu·uni-app
Vue10242 天前
uniapp 使用renderjs 封装 video-player 视频播放器, html5视频播放器-解决视频层级、覆盖、播放卡顿
uni-app·音视频·html5
钱端工程师2 天前
uniapp封装uni.request请求,实现重复接口请求中断上次请求(防抖)
前端·javascript·uni-app
茶憶2 天前
uni-app app移动端实现纵向滑块功能,并伴随自动播放
javascript·vue.js·uni-app·html·scss
dcloud_jibinbin2 天前
【uniapp】解决小程序分包下的json文件编译后生成到主包的问题
前端·性能优化·微信小程序·uni-app·vue·json