123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- import getBehavior from './behavior'
- import yuvBehavior from './yuvBehavior'
- import { getCachedImage, hash } from '../../utils/index'
- import { MARKER_MAP } from './constants'
- const NEAR = 0.01
- const FAR = 1000
- Component({
- behaviors: [getBehavior, yuvBehavior],
- data: {
- widthScale: 1, // canvas宽度缩放值
- heightScale: 1, // canvas高度缩放值
- markerImgList: [], // 使用的 marker 列表
- chooseImgList: [], // 使用的 图片 列表
- hintBoxList: [], // 显示提示盒子列表
- },
- markerIndex: 0, // 使用的 marker 索引
- hintInfo: undefined, // 提示框信息
- methods: {
- // 对应案例的初始化逻辑,由统一的 behavior 触发
- init() {
- // 初始化 Three.js,用于模型相关的渲染
- this.initTHREE()
- // 初始化 GL,基于 Three.js 的 Context,用于相机YUV渲染
- this.initYUV()
- // 初始化VK
- // start完毕后,进行更新渲染循环
- this.initVK()
- this.markerIndex = 0
- // 添加 识别包围盒子
- // this.add3DBox()
- },
- initVK() {
- // VKSession 配置
- const session = this.session = wx.createVKSession({
- track: {
- plane: {
- mode: 1
- },
- marker: true,
- },
- version: 'v1',
- gl: this.gl
- })
- session.start(err => {
- if (err) return console.error('VK error: ', err)
- console.log('@@@@@@@@ VKSession.version', session.version)
- try {
- const promises = [
- 'https://houseoss.4dkankan.com/project/kelamayi/ylzt-1.png',
- ].map(url => {
- const cacheKey = 'image_marker_' + hash(url)
- return getCachedImage(url, cacheKey)
- })
- Promise.all(promises).then(paths => {
- for (const path of paths) {
- session.addMarker(path)
- }
- })
- } catch(err) {
- console.log(err)
- }
- // VKSession EVENT resize
- session.on('resize', () => {
- this.calcCanvasSize()
- })
- // VKSession EVENT addAnchors
- // session.on('addAnchors', anchors => {
- // this.left.visible = true
- // this.right.visible = true
- // this.top.visible = true
- // this.bottom.visible = true
- // })
- // VKSession EVENT updateAnchors
- session.on('updateAnchors', anchors => {
- // marker 模式下,目前仅有一个识别目标,可以直接取
- const anchor = anchors[0]
- const markerId = anchor.id
- const size = anchor.size
- this.hintInfo = {
- markerId,
- size
- }
- if (MARKER_MAP[markerId]) {
- wx.navigateTo({
- url: '/pages/webview/index?url=' + encodeURIComponent(`https://sit-kelamayi.4dage.com/zuan/#/info/${MARKER_MAP[markerId]}?x=h`),
- })
- }
- })
- // VKSession removeAnchors
- // 识别目标丢失时,会触发一次
- session.on('removeAnchors', anchors => {
- // this.left.visible = false
- // this.right.visible = false
- // this.top.visible = false
- // this.bottom.visible = false
- if (this.data.hintBoxList && this.data.hintBoxList.length > 0) {
- // 清理信息
- this.hintInfo = undefined
- // 存在列表的情况,去除remove
- this.setData({
- hintBoxList: []
- })
- }
- })
- console.log('ready to initloop')
- // start 初始化完毕后,进行更新渲染循环
- this.initLoop()
- })
- },
- loop() {
- // console.log('loop')
- // 获取 VKFrame
- const frame = this.session.getVKFrame(this.canvas.width, this.canvas.height)
- // 成功获取 VKFrame 才进行
- if (!frame) { return }
- // 更新相机 YUV 数据
- this.renderYUV(frame)
- // 获取 VKCamera
- const VKCamera = frame.camera
- // 相机
- if (VKCamera) {
- // 接管 ThreeJs 相机矩阵更新,Marker模式下,主要由视图和投影矩阵改变渲染效果
- this.camera.matrixAutoUpdate = false
- // 视图矩阵
- this.camera.matrixWorldInverse.fromArray(VKCamera.viewMatrix)
- this.camera.matrixWorld.getInverse(this.camera.matrixWorldInverse)
- // 投影矩阵
- const projectionMatrix = VKCamera.getProjectionMatrix(NEAR, FAR)
- this.camera.projectionMatrix.fromArray(projectionMatrix)
- this.camera.projectionMatrixInverse.getInverse(this.camera.projectionMatrix)
- }
- // 绘制而为提示框的逻辑
- if (this.hintInfo) {
- // 存在提示信息,则更新
- const THREE = this.THREE
- // 原点偏移矩阵,VK情况下,marker 点对应就是 0 0 0,世界矩阵可以认为是一个单位矩阵
- // marker 右侧点可以理解是 0.5 0 0
- const center = new THREE.Vector3()
- const right = new THREE.Vector3(0.5, 0, 0)
- // 获取设备空间坐标
- const devicePos = center.clone().project(this.camera)
- // 转换坐标系,从 (-1, 1) 转到 (0, 100),同时移到左上角 0 0,右下角 1 1
- const screenPos = new THREE.Vector3(0, 0, 0)
- screenPos.x = devicePos.x * 50 + 50
- screenPos.y = 50 - devicePos.y * 50
- // 获取右侧点信息
- const deviceRightPos = right.clone().project(this.camera)
- const screenRightPos = new THREE.Vector3(0, 0, 0)
- screenRightPos.x = deviceRightPos.x * 50 + 50
- const markerHalfWidth = screenRightPos.x - screenPos.x
- this.setData({
- hintBoxList: [
- {
- markerId: this.hintInfo.markerId,
- left: screenPos.x - markerHalfWidth,
- top: screenPos.y - markerHalfWidth,
- width: markerHalfWidth * this.data.domWidth * 2 / 100,
- height: markerHalfWidth * this.data.domWidth * 2 / 100,
- }
- ]
- })
- }
- this.renderer.autoClearColor = false
- this.renderer.state.setCullFace(this.THREE.CullFaceBack)
- this.renderer.render(this.scene, this.camera)
- this.renderer.state.setCullFace(this.THREE.CullFaceNone)
- },
- add3DBox() {
- // 添加marker需要的 三维包围框
- const THREE = this.THREE
- const scene = this.scene
- const material = new THREE.MeshPhysicalMaterial({
- metalness: 0.0,
- roughness: 0.1,
- color: 0x64f573,
- })
- const geometry = new THREE.BoxGeometry(1, 1, 1)
- const borderSize = 0.1
- const left = new THREE.Mesh(geometry, material)
- left.position.set(-0.5, 0, 0)
- left.rotation.set(-Math.PI / 2, 0, 0)
- left.scale.set(borderSize, 1.1, borderSize)
- scene.add(left)
- left.visible = false
- this.left = left
- const right = new THREE.Mesh(geometry, material)
- right.position.set(0.5, 0, 0)
- right.rotation.set(-Math.PI / 2, 0, 0)
- right.scale.set(borderSize, 1.1, borderSize)
- scene.add(right)
- right.visible = false
- this.right = right
- const top = new THREE.Mesh(geometry, material)
- top.position.set(0, 0, 0.5)
- top.rotation.set(0, 0, 0)
- top.scale.set(1.1, borderSize, borderSize)
- scene.add(top)
- top.visible = false
- this.top = top
- const bottom = new THREE.Mesh(geometry, material)
- bottom.position.set(0, 0, -0.5)
- bottom.rotation.set(0, 0, 0)
- bottom.scale.set(1.1, borderSize, borderSize)
- scene.add(bottom)
- bottom.visible = false
- this.bottom = bottom
- console.log('add3DBox is finish')
- },
- },
- })
|