更新时间:2023-04-26 GMT+08:00
开发指导
开发流程
图1 AR导航启动流程
开发过程
- 开启AR会话。
- 选定终点位置。
通过POI智能搜索(hwar.searchPoi)选定终点坐标。
// POI智能搜索 hwar.searchPoi({ "floor": "1F", "address": "xxx", "title": "xxx", "pageNum": 0, "pageSize": 50 }).then((res) => { // POI信息列表,包含POI的UTM坐标等信息 });
- 进行视觉定位。
通过设置AR会话状态(hwar.setARStatus)或者触发手动定位(hwar.requestVps)发送定位请求,定位成功结果通过回调函数返回。
// 触发手动定位请求 hwar.requestVps(); // 设置定位成功回调函数 hwar.registerGetNewVpsPose((dictPoseData, vpsOffset) => { // 可计算与上次定位的差值、与终点的距离。当有3D内容时可重置世界坐标原点重新渲染内容 });
- 获取导航路径。
传入起始点与终点的UTM坐标请求导航(hwar.requestNavi),获取该段路程的路径点。
// 请求导航路径 hwar.requestNavi("xxx", [xxx, xxx, xxx], [xxx, xxx, xxx], 1 ).then((res) => { // 获取导航路径点信息 }).catch((err) => { // 获取失败 }) // 路径点结构:其中xyz是UTM坐标,渲染路径时需要转换成渲染坐标(TS语言) export interface INaviPoint { linkID: number; x: number; y: number; z: number; floor: string; building: string; status: number; }
- 获取相机矩阵和视频流图像,完成空间位置追踪与渲染。
通过回调函数“hwar.registerRefreshCameraMat”获取相机矩阵和视频流图像。当3定位成功后输出相机矩阵,包含当前虚拟相机的位姿信息。视频流图像可通过Three.js、LayaAir等WebGL渲染引擎渲染成背景画面。
- 您可以根据相机矩阵、视频流图像及路径点,自定义渲染导航路径、虚拟数字内容。
- 自定义渲染导航路径时,建议您分段处理路径,及时移除失效路径点。渲染的每帧仅计算当前相机的位置和距离相机最近的点,且仅渲染当前路段。
// 设置接收相机矩阵的回调函数 hwar.registerRefreshCameraMat((cameraMat, imgData) => { if (cameraMat) { //VPS定位成功,输出相机矩阵 console.log(`相机矩阵:${cameraMat}`); } // 图像预览流默认宽:高=480:640,不同尺寸屏幕请自行适配 console.log(`接收到视频流图像:${imgData}`); }); //Three.js r144版本 相机渲染代码示例(TS语言) //图像作为3D场景的背景,渲染器的设置如下: this.renderer = new THREE.WebGLRenderer({ alpha: true, preserveDrawingBuffer: true, antialias: true }); this.renderer.autoClearColor = true; this.renderer.sortObjects = false; this.renderer.setPixelRatio(window.devicePixelRatio); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.localClippingEnabled = true; this.renderer.autoClear = false; this.renderer.debug.checkShaderErrors = false; document.body.appendChild(this.renderer.domElement); public updateARCameraMatrix(cameraMat: THREE.Matrix4, imgData: ImageData): void { if (cameraMat) { this.camera.matrix.fromArray(cameraMat.toArray()); this.camera.updateMatrixWorld(true); } if (imgData) { let buffer: Uint8Array = new Uint8Array(imgData.data.buffer); let tex: DataTexture = new DataTexture(buffer, imgData.width, imgData.height, THREE.RGBAFormat ); tex.needsUpdate = true; tex.matrixAutoUpdate = false; tex.magFilter = THREE.LinearFilter; tex.flipY = true; tex.encoding = THREE.sRGBEncoding; this.scene.background = tex; } } //LayaAir 2.12版本 相机渲染代码示例(TS语言) //图像作为舞台的背景,将video: Laya.Sprite添加到舞台,添加3D场景,并将场景相机设置如下: Laya.stage.addChild(this.video); this.mainScene.mouseThrough = false; this.mainCamera = this.mainScene.getChildByName("Main Camera") as Laya.Camera; this.mainCamera.enableHDR = false; this.mainCamera.clearColor = new Laya.Vector4(0, 0, 0, 255); this.mainCamera.clearFlag = Laya.CameraClearFlags.DepthOnly; this.mainCamera.fieldOfView = 66; this.mainCamera.depthTextureMode = Laya.DepthTextureMode.None; Laya.stage.addChild(this.mainScene); public updateARCameraMatrix(cameraMat: { elements: Float32Array, isMatrix4: boolean }, imgData: ImageData): void { if (cameraMat) { let mat: Laya.Matrix4x4 = new Laya.Matrix4x4(); mat.elements = cameraMat.elements; this.mainCamera.transform.worldMatrix = mat; } if (imgData) { if (this.stageHeight !== Laya.stage.height) { // 请自行对渲染尺寸(宽:高=480:640)做屏幕适配 this.onResize(); } if (this.videoTexture && this.videoTexture.bitmap) { this.videoTexture.disposeBitmap(); this.videoTexture2D.destroy(); this.videoTexture = null; this.videoTexture2D = null; } let buffer: Uint8Array = new Uint8Array(imgData.data.buffer); this.videoTexture2D = new Laya.Texture2D(imgData.width, imgData.height); this.videoTexture2D.setPixels(buffer); this.videoTexture = Laya.Texture.create(this.videoTexture2D, 0, 0, imgData.width, imgData.height); this.video.texture = this.videoTexture; } }
父主题: 实现AR导航