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:

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

相关推荐
游戏开发爱好者82 小时前
日常开发与测试的 App 测试方法、查看设备状态、实时日志、应用数据
android·ios·小程序·https·uni-app·iphone·webview
2501_915106324 小时前
app 上架过程,安装包准备、证书与描述文件管理、安装测试、上传
android·ios·小程序·https·uni-app·iphone·webview
2501_915106324 小时前
使用 Sniffmaster TCP 抓包和 Wireshark 网络分析
网络协议·tcp/ip·ios·小程序·uni-app·wireshark·iphone
宠友信息6 小时前
2025社交+IM及时通讯社区APP仿小红书小程序
java·spring boot·小程序·uni-app·web app
“负拾捌”6 小时前
python + uniapp 结合腾讯云实现实时语音识别功能(WebSocket)
python·websocket·微信小程序·uni-app·大模型·腾讯云·语音识别
局外人LZ1 天前
Uniapp脚手架项目搭建,uniapp+vue3+uView pro+vite+pinia+sass
前端·uni-app·sass
2501_915918411 天前
在 iOS 环境下查看 App 详细信息与文件目录
android·ios·小程序·https·uni-app·iphone·webview
前端呆头鹅1 天前
Websocket使用方案详解(uniapp版)
websocket·网络协议·uni-app
浮桥1 天前
uniapp+h5 公众号实现分享海报绘制
uni-app·notepad++
2501_916007471 天前
没有 Mac 用户如何上架 App Store,IPA生成、证书与描述文件管理、跨平台上传
android·macos·ios·小程序·uni-app·iphone·webview