效果(听很多童鞋反馈,代码复制到自己的项目中没法打开,或者存在其它问题,对此我用官方demo框架写了一个demo,可以去我的资源里面的看‘微信AR识别特定图片出现glb模型代码’,希望可以帮助到大家~~~~) demo页面(需要真机预览调试,注意更换自己的项目的appid)
ar案例视频
准备:需要准备要扫描的图片地址和扫描成功后显示的模型 1.在components创建组件 index.js文件代码
Component({
properties: {
title: {
type: String,
value: '',
},
intro: {
type: String,
value: '',
},
hint: {
type: String,
value: '',
},
code: {
type: String,
value: '',
},
json: {
type: String,
value: '',
},
js: {
type: String,
value: '',
},
showBackBtn: {
type: Boolean,
value: false,
},
},
data: {
},
lifetimes: {
attached() {
wx.xrTitle = this.data.title;
}
},
methods: {
onClickBack() {
wx.navigateBack()
},
}
})
index.json代码
{
"component": true,
"usingComponents": {}
}
index.wxml代码
index.wxss代码
.demo-wrap {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.demo-viewer {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.holder {
height: 60rpx;
}
.hint-wrap {
text-align: center;
}
.hint-words {
display: inline-block;
color: #000;
text-align:center;
font-weight:bold;
max-width: 300px;
padding: 10px 20px;
border: 2px dashed #000;
background-color: #fff;
}
.intro {
display: block;
margin: 20rpx 0;
background: #fff;
}
.intro .title {
font-size: 36rpx;
padding-bottom: 20rpx;
}
.intro .description {
color: #8f8f8f;
font-size: 28rpx;
}
.intro-detail {
padding: 30rpx;
}
.code-inner {
margin: 0rpx;
padding: 30rpx;
font-size: 30rpx;
background-color: #f9f9fa;
}
.code-inner rich-text {
word-wrap: break-word;
}
.block-name {
display: inline-block;
color: #b457ff;
}
.attr-name {
display: inline-block;
color: #ff4d00;
}
.ml20 {
margin-left: 20rpx;
}
.intro-title {
font-size: 30rpx;
font-weight: bold;
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 24rpx;
}
.share {
margin: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
padding: 0;
width: 160rpx !important;
background: none;
font-size: 28rpx;
color: #ff4d00;
}
.back-btn-wrap {
position: absolute;
left: 30rpx;
top: 100rpx;
width: 90rpx;
height: 80rpx;
}
.back-line-t {
position: absolute;
left: 20rpx;
top: 15rpx;
width: 30rpx;
height: 6rpx;
background-color: #000;
transform: rotate(-45deg);
border-radius: 5rpx;
}
.back-line-b {
position: absolute;
left: 20rpx;
top: 32rpx;
width: 30rpx;
height: 6rpx;
background-color: #000;
transform: rotate(45deg);
border-radius: 5rpx;
}
2.继续在components里面创建xr-ar-oceanWorld组件 index.js文件代码
Component({
behaviors: [require('../common/share-behavior').default],//路径按照自己项目路径来
miku: null,
mikuTransform: null,
mikuAnimator: null,
animationRuning: false,
isShow: false,
properties: {
//是否显示文字贴图默认不显示
isShowDolphin: {
type: false
},
},
wxball: null,
time1: null,
time2: null,
data: {
loaded: false,
arReady: false,
},
lifetimes: {
async attached() {
// console.log('data', this.data);
}
},
methods: {
handleReady({
detail
}) {
const xrScene = this.scene = detail.value;
const xrFrameSystem = wx.getXrFrameSystem();
},
handleAssetsProgress: function ({
detail
}) {
},
handleAssetsLoaded: function ({
detail
}) {
// console.log('assets loaded', detail.value);
this.setData({
loaded: true
});
},
handleTouchmiku: function() {
// console.log('miku TOUCH', this.animationRuning);
// if (!this.animationRuning) {
//
// this.animationRuning = true;
// this.mikuAnimator.pauseToFrame('gltfAnimation', 1);
// this.mikuAnimator.pauseToFrame('gltfAnimation#0', 1);
// this.mikuAnimator.resume('gltfAnimation');
// this.mikuAnimator.resume('gltfAnimation#0');
// }
},
handleAnimationStop: function() {
console.log('animation Stop');
},
// 识别模型状态
handleARTrackerState({detail}) {
// 事件的值即为`ARTracker`实例
const tracker = detail.value;
// 获取当前状态和错误信息
const {state, errorMessage} = tracker;
// const video = this.scene.assets.getAsset('video-texture', 'hikari', 'white');
console.log(state==2);
if(state==2){
console.log("状态识别成功", state)
this.time1 = setTimeout(() => {
this.setData({
isShow: true
})
}, 1000)
// this.time2 = setTimeout(() => {
// console.log("暂停动画")
// const animator1 = this.scene.getElementById('wxball-1').getComponent("animator");
// animator1.pause();
// const animator2 = this.scene.getElementById('wxball-2').getComponent("animator");
// animator2.pause();
// }, 7000)
}else{
// clearTimeout(this.time1);
// clearTimeout(this.time2);
this.setData({
isShow: false
})
}
},
// 识别海豚
handleARTrackerState1({detail}) {
// 事件的值即为`ARTracker`实例
const tracker = detail.value;
// 获取当前状态和错误信息
const {state, errorMessage} = tracker;
// const video = this.scene.assets.getAsset('video-texture', 'hikari', 'white');
console.log(state==2);
if(state==2){
console.log("识别海豚", state);
// this.triggerEvent('传递给父组件的自定义事件名称 newValue',传给父组件的数据 valueText)
this.time1 = setTimeout(() => {
this.triggerEvent('changeDolphin',{isShowDolphin:true})
this.setData({
isShow: true,
isShowDolphin:true
})
}, 1000)
// this.time2 = setTimeout(() => {
// console.log("暂停动画")
// const animator1 = this.scene.getElementById('wxball-1').getComponent("animator");
// animator1.pause();
// const animator2 = this.scene.getElementById('wxball-2').getComponent("animator");
// animator2.pause();
// }, 7000)
}else{
this.triggerEvent('changeDolphin',{isShowDolphin:false})
// clearTimeout(this.time1);
// clearTimeout(this.time2);
this.setData({
isShow: false
})
}
},
handleARReady({detail}) {
const xrFrameSystem = wx.getXrFrameSystem();
const tracker = this.scene.getElementById('ar-tracker').getComponent(xrFrameSystem.ARTracker);
// 初始状态
const {state, errorMessage} = tracker;
// 绑定事件
tracker.el.event.add('ar-tracker-state', tracker => {
const {state, errorMessage} = tracker;
});
},
handleGLTFLoaded({detail}) {
// console.log("进来了")
// const el = detail.value.target;
// const animator = el.getComponent("animator");
// console.log("1111",animator)
// setTimeout(function(){
// console.log("暂停了")
// animator.pause();
// },3000)
}
}
})
index.json文件代码
{
"component": true,
"usingComponents": {
"xr-demo-viewer": "../xr-demo-viewer/index"
},
"renderer": "xr-frame"
}
index.wxml
id="camera" node-id="camera" position="1 1 1" clear-color="0.925 0.925 0.925 1" far="2000" background="ar" is-ar-camera >
3.pages文件夹里创建scene-ar-oceanWorld文件 index.js代码
var sceneReadyBehavior = require('../../behavior-scene/scene-ready');//路径按照自己项目路径来
Page({
behaviors: [sceneReadyBehavior],
data: {
isShowDolphin:false,//默认不是海豚
isShow: false,
show: false,
video: false,
progressFlag: 0,
loadingAni: false,
isbegin: true,
time1: null,
time2: null,
time3: null,
rotation: {
x:0,
y: 0,
z: 0,
},
op_n:0,
meshCount: 0,
loading: 0,
barIsShow: true,
endShow:false,
timer:"",
deflautWidth:0,
musicbg:null
},
onUnload(){
this.musicbg.stop();
// 清除video定时器
// clearTimeout(this.data.time3);
},
onLoad(options) {
wx.setNavigationBarTitle({
title: "潜入海洋的梦里"
})
let that = this;
// 背景音乐
this.musicbg = wx.createInnerAudioContext()
this.musicbg.src ="背景音乐地址";
this.musicbg.volume=0.6;
this.musicbg.loop = true;
this.musicbg.play();
let index = 0;
this.data.timer=setInterval(() => { //注意箭头函数!!
index += 1;
that.setData({
deflautWidth: index
})
if (that.data.deflautWidth == 100) {
clearInterval(this.data.timer);
}
}, 1000);
setTimeout(res=>{
that.setData({
deflautWidth: 100
})
},3000)
// 关闭主页按钮
wx.hideHomeButton();
},
// 场景加载成功回调
loadedInfo(){
},
//获取海豚状态
changeDolphin(e){
console.log('获取海豚状态',e.detail);
this.setData({
isShowDolphin:e.detail.isShowDolphin
})
},
end() {
console.log("1111")
},
// 获取微信头像
handleReady: function ({detail}) {
this.scene = detail.value;
// 该接口已废弃,请授权后,采用 getUserInfo 代替。
wx.getUserInfo()({
desc: '获取头像',
success: (res) => {
console.log("微信授权", res);
this.scene.assets.loadAsset({
type: 'texture', assetId: 'avatar', src: res.userInfo.avatarUrl
}).then(() => this.setData({avatarTextureId: 'avatar'}));
}
})
},
/**
* 获取识别状态
* Detected识别成功
* Detecting未识别
*/
handleARTrackerState({
detail}) {
console.log(detail,"识别");
const {
state,
error
} = detail;
this.tracker = wx.getXrFrameSystem().ARTracker
const {
gesture
} = this.tracker;
this.gesture = gesture;
let states = wx.getXrFrameSystem().EARTrackerState[state];
if (states == "Detected") {
// if (this.data.progressFlag == 0) {
this.setData({
progressFlag: 1
})
// 修改加载界面展示
this.setData({
show: true
})
//识别成功
this.data.time1 = setTimeout(() => {
this.setData({
show: false
})
}, 1000)
//识别成功
// this.data.time2 = setTimeout(() => {
// this.setData({
// isShow: true,
// });
// // 在定时器回调中判断 isShow 的值
// if (this.data.isShow) {
// this.data.time3 = setTimeout(() => {
// console.log("进入if");
// this.setData({
// video: true,
// });
// // 关闭音乐
// this.musicbg.stop();
// }, 4500);
// }
// }, 10000);
// } else{
// this.setData({
// show: false
// })
// }
} else {
//识别失败
console.log("识别失败", states);
this.setData({
show: false,
// isShow:false,
// video: false
});
clearTimeout(this.data.time1);
clearTimeout(this.data.time2);
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
onShow() {
/**
* 设置页面常亮
*/
wx.setKeepScreenOn({
keepScreenOn: true,
fail() {
//如果失败 再进行调用
wx.setKeepScreenOn({
keepScreenOn: true
});
}
});
},
onHide() {
this.musicbg.stop();
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
index.json代码
{
"usingComponents": {
"xr-demo-viewer": "../../../components/xr-demo-viewer/index",//路径按照自己项目路径来
"xr-ar-oceanWorld": "../../../components/xr-ar-oceanWorld/index"//路径按照自己项目路径来
},
"disableScroll": true
}
index.wxml文件代码
isShowDolphin="{{isShowDolphin}}" bindchangeDolphin="changeDolphin" disable-scroll id="main-frame" width="{{renderWidth}}" height="{{renderHeight}}" style="width:{{width}}px;height:{{height}}px;top:{{top}}px;left:{{left}}px;display:block;" bind:arTrackerState="handleARTrackerState" /> index.wxss代码 page{width: 100%;height: 100%;} .mask_bg{width: 100%;height: 100%; background: rgba(0,0,0,0.3); position: absolute; top:0; left: 0; z-index: 10;} .mask_Img{width: 100%; height: 100%;} .mask_Box{width: 100%; position: relative; } .rote{width: 100%; height: 100%;position: absolute; top:0;left: 0;} .rote image{width: 95%;animation:rotate_music 5s linear infinite; transform-origin: 50% 50%;} @keyframes rotate_music{0%{transform: rotate(0deg);} 50%{transform: rotate(180deg);} 100%{transform: rotate(360deg);}} .Detecting{position: absolute;top:0; left: 0; width: 100%; height: 100%; overflow: hidden; border-radius: 100%;} .Detecting image{animation:d1 4s linear infinite;} @keyframes d1{0%,100%{transform: translateY(0);} 50%{transform: translateY(65vw);}} .ar3d{width: 100%; height: 100%; position: absolute;top:0;left: 0; z-index: 10; display: none; } .ar3d_box{width: 100%; height:90%;perspective:1px; perspective-origin:center center;} .ar3d_box text{font-size: 1em;animation:tz 5s linear infinite; color:#fff;} @keyframes tz{0%{transform: translateZ(-3px);} 100%{transform: translateZ(1px);}} .loading{width: 100%; text-align: center; margin-top: 20%;} .loading .box{width: 60%; margin: 0 auto; position: relative;} .loading .bar{width: 100%; position: absolute; bottom: 2%; left: 0; height:40%;} .loading .bar_loading{width: 100%; height: 100%; } .tips{width: 100%; text-align: center; margin-top: 5%;} .tips image{width: 70%;} .EndBox{position: absolute;top:0; left: 0; z-index: 2; width: 100%;height: 100%;} .EndBox .box{width: 100%; height: 100%; background: url(https://cyvideo.i-oranges.com/ar/cdxg/index/ai1.gif) center no-repeat; background-size:cover} .faceMask{width: 100%; height: 100%;position: absolute;top:0;left: 0; z-index: 999999;} /* .faceMask .head1{position: absolute;top:0; left: 0; width: 20%;} */ .faceMask .bottom1{position: absolute;bottom:0; left: 0; width: 100%;} .faceMask .bottom1 image{vertical-align: middle;} .faceMask .tips{position: absolute; bottom: 5%; width: 100%;} .faceMask .tips .box{width: 45%; position: relative; margin: 0 auto;} .faceMask .tips .close{position: absolute; width: 20%; right: -7%; top:-30%;} 4.在components组件里面创建common文件share-behavior.js share-behavior.js代码 export default Behavior({ created: function () { this.checkInitShare(); }, methods: { checkInitShare() { wx.xrScene = undefined; if (!this.scene) { setTimeout(() => { this.checkInitShare() }, 100); return; } if (this.scene.ar) { if (this.scene.ar.ready) { this.initARTrackerState(this.scene); } else { this.scene.event.add('ar-ready', () => this.initARTrackerState(this.scene)); } } if (!this.scene.share.supported) { console.warn('Not support xr-frame share system now!'); return; } this.sharing = false; wx.xrScene = this.scene; }, initARTrackerState(scene) { const xrFrameSystem = wx.getXrFrameSystem(); scene.dfs(() => {}, undefined, true, el => { const comp = el.getComponent(xrFrameSystem.ARTracker); if (comp) { if (typeof comp.state === 'number') { this.triggerEvent('arTrackerState', {state: comp.state, error: comp.errorMessage}); el.event.add('ar-tracker-state', tracker => { this.triggerEvent('arTrackerState', {state: tracker.state, error: tracker.errorMessage}); }); } return true; } }); } } }) 4.在pages中创建behavior-scene项目 scene-ready.js文件代码 module.exports = Behavior({ behaviors: [], properties: { }, data: { left: 0, top: 0, width: 0, height: 0, renderWidth: 0, renderHeight: 0, windowHeight: 1000, heightScale: 1, showBackBtn: false, activeValues: [1], arTrackerShow: false, arTrackerState: 'Init', arTrackerError: '' }, attached: function(){}, ready() { const info = wx.getSystemInfoSync(); const width = info.windowWidth; const windowHeight = info.windowHeight; const height = windowHeight * this.data.heightScale; const dpi = info.pixelRatio; this.setData({ width, height, renderWidth: width * dpi, renderHeight: height * dpi, windowHeight }); }, methods: { onLoad(options) { wx.reportEvent("xr_frame", { "xr_page_path": options.path }); }, // onShareAppMessage() { // try { // if (wx.xrScene) { // const buffer = wx.xrScene.share.captureToArrayBuffer({quality: 0.5}); // const fp = `${wx.env.USER_DATA_PATH}/xr-frame-share.jpg`; // wx.getFileSystemManager().writeFileSync(fp, buffer, 'binary'); // return { // title: this.getTitle(), // imageUrl: fp // }; // } // } catch (e) { // return { // title: this.getTitle() // }; // } // }, // onShareTimeline() { // try { // if (wx.xrScene) { // const buffer = wx.xrScene.share.captureToArrayBuffer({quality: 0.5}); // const fp = `${wx.env.USER_DATA_PATH}/xr-frame-share.jpg`; // wx.getFileSystemManager().writeFileSync(fp, buffer, 'binary'); // return { // title: this.getTitle(), // imageUrl: fp // }; // } // } catch (e) { // return { // title: this.getTitle() // } // } // }, getTitle() { return wx.xrTitle ? `${wx.xrTitle}` : 'AR'; }, handleARTrackerState({detail}) { const {state, error} = detail; this.setData({ arTrackerShow: true, arTrackerState: wx.getXrFrameSystem().EARTrackerState[state], arTrackerError: error }); } } }) utils.js代码 var handleDecodedXML = function(decodedXml) { let rerurnXml = ''; const blockArr = decodedXml.split('<'); for (let i = 0; i < blockArr.length; i++) { let blockStr = blockArr[i]; let handleBlockStr = ''; let returnBlockStr = ''; const sliceBlockStr = blockStr.split(' '); for(let j = 0; j < sliceBlockStr.length; j++) { const subBlockStr = sliceBlockStr[j]; const eIndex = subBlockStr.indexOf('='); if (eIndex !== -1) { handleBlockStr += ' ' + subBlockStr.slice(0, eIndex) +'' + subBlockStr.slice(eIndex); } else { handleBlockStr += subBlockStr; } } // console.log(sliceBlockStr); const blockEndIndexB = handleBlockStr.indexOf(' '); const blockEndIndexR = handleBlockStr.indexOf('>'); // Handle XMLTag if (blockEndIndexB === -1 && blockEndIndexR === -1) { continue; } const endBlockFlag = handleBlockStr[0] === '/'; if (blockEndIndexR !== -1) { handleBlockStr += ' } if (blockEndIndexR < blockEndIndexB) { returnBlockStr = '<' + (endBlockFlag ? '/' : '') + '' + handleBlockStr.slice(endBlockFlag ? 1 : 0, blockEndIndexR) + '' + handleBlockStr.slice(blockEndIndexR); } else if (blockEndIndexB !== -1) { returnBlockStr = '<' + (endBlockFlag ? '/' : '') +'' + handleBlockStr.slice(endBlockFlag ? 1 : 0, blockEndIndexB) + '' + handleBlockStr.slice(blockEndIndexB); } else if (blockEndIndexR !== -1) { returnBlockStr = '<' + (endBlockFlag ? '/' : '') + '' + handleBlockStr.slice(endBlockFlag ? 1 : 0, blockEndIndexR) + '' + handleBlockStr.slice(blockEndIndexR); } rerurnXml += returnBlockStr; } return rerurnXml; } var escapeMarkup = function(dangerousInput) { const dangerousString = String(dangerousInput); const matchHtmlRegExp = /["'&<>]/; const match = matchHtmlRegExp.exec(dangerousString); if (!match) { return dangerousInput; } const encodedSymbolMap = { '"': '"', '\'': ''', '&': '&', '<': '<', '>': '>' }; const dangerousCharacters = dangerousString.split(''); const safeCharacters = dangerousCharacters.map(function (character) { return encodedSymbolMap[character] || character; }); const safeString = safeCharacters.join(''); return safeString; } module.exports = { handleDecodedXML, escapeMarkup } 推荐链接
'
发表评论