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:

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

相关推荐
Q_Q51100828517 小时前
python+uniapp基于微信小程序的旅游信息系统
spring boot·python·微信小程序·django·flask·uni-app·node.js
2501_9160074719 小时前
iOS 混淆工具链实战,多工具组合完成 IPA 混淆与加固(iOS混淆|IPA加固|无源码混淆|App 防反编译)
android·ios·小程序·https·uni-app·iphone·webview
游戏开发爱好者821 小时前
FTP 抓包分析实战,命令、被动主动模式要点、FTPS 与 SFTP 区别及真机取证流程
运维·服务器·网络·ios·小程序·uni-app·iphone
2501_915909061 天前
iOS 26 文件管理实战,多工具组合下的 App 数据访问与系统日志调试方案
android·ios·小程序·https·uni-app·iphone·webview
盛夏绽放1 天前
uni-app Vue 项目的规范目录结构全解
前端·vue.js·uni-app
2501_915918412 天前
掌握 iOS 26 App 运行状况,多工具协作下的监控策略
android·ios·小程序·https·uni-app·iphone·webview
知识分享小能手2 天前
uni-app 入门学习教程,从入门到精通,uni-app基础扩展 —— 详细知识点与案例(3)
vue.js·学习·ui·微信小程序·小程序·uni-app·编程
2501_915909062 天前
iOS 混淆实战,多工具组合完成 IPA 混淆与加固(源码 + 成品 + 运维一体化方案)
android·运维·ios·小程序·uni-app·iphone·webview
赵庆明老师2 天前
Uniapp微信小程序开发:EF Core 中级联删除
uni-app
Javashop_jjj2 天前
三勾软件| 用SpringBoot+Element-UI+UniApp+Redis+MySQL打造的点餐连锁系统
spring boot·ui·uni-app