Navegación interior AR-Three.js

descripción general

Si no lo entiende, puede agregar QQ: 2781128388
Adquisición del código fuente : https://mbd.pub/o/bread/Y5uck5lr

Esta vez, la navegación interior AR se realiza utilizando Hummingbird Cloud Map más tres.js, con cambio de piso interior, cambio de modelo 2D/3D, control de brújula y encendido/apagado de AR. Simule la función de navegación interior, primero mire el efecto de video

Navegación interior AR

Inicializar el mapa interior

Es muy simple inicializar el mapa interior de Hummingbird Cloud, y los datos del mapa que vienen con Hummingbird Cloud también se usan para
llamar a mapCreate en el archivo vue para crear un mapa.

this.$nextTick(() => {
    
    
        this.mapCreate();
});

Parámetros de configuración del mapa, debe crear el valor clave usted mismo

options: {
    
    
          appName: '蜂鸟研发SDK_2_0',
          key: '',
          mapID: '1321274646113083394',
          // 缩放级别
          mapZoom: 20,
          // 显示楼层
          visibleLevels: [1, 2, 3, 4, 5],
          // 默认显示几楼
          level: 3
        }

window.map = new fengmap.FMMap(this.options);

En este punto, la creación del mapa muestra éxito
inserte la descripción de la imagen aquí

Crear controles de piso

Después de crear el mapa, se generan los controles de piso, la brújula y los controles de navegación.

//监听地图加载完成
        map.on('loaded', () => {
    
    
          //创建导航对象
          this.creatNavigation();
          //创建楼层控件
          this.creatFloorControl();
          //创建指北针控件
          this.creatCompassControl();
        });

control de piso

creatFloorControl() {
    
    
        let toolbar = new fengmap.FMToolbar({
    
    
          //默认在右上角
          position: fengmap.FMControlPosition.RIGHT_TOP,
          //初始是否是多层显示,默认单层显示
          allLayer: false,
          //是否显示多层/单层切换按钮
          needAllLayerBtn: true,
          //控件位置x,y的偏移量
          offset: {
    
    
            x: -10,
            y: 320
          }
        });
        toolbar.addTo(map);
      },

Brújula

let compass = new fengmap.FMCompass({
    
    
          position: fengmap.FMControlPosition.LEFT_TOP,
          width: 40,
          height: 40,
          offset: {
    
    
            x: 12,
            y: 460
          }
        });
        compass.addTo(map);
        compass.on('click', function() {
    
    
          map.setRotation({
    
    
            rotation: 0,
            animate: true,
            duration: 0.3
          });
        });

controles de navegación

// FMNaviAnalyser 是可分析最短路径、最快路径并返回分析结果的路径类。可独立于地图工作,支持Web Worker 和 Node
        let analyser = new fengmap.FMNaviAnalyser(
          this.options,
          function() {
    
    
            // FMNavigation 是导航相关的功能类, 可用于模拟导航和真实导航使用
            window.navi = new fengmap.FMNavigation({
    
    
              map: map,
              analyser: analyser,
              locationMarkerUrl: './img/导航.png',
              locationMarkerSize: 32
            });
          },
          (error) => {
    
    
            console.log(error);
          }
        );

inserte la descripción de la imagen aquí
En este punto, puede cambiar la visualización del piso y controlar la conversión 2D/3D

navegación

Una interfaz de usuario para ingresar la dirección de inicio y la ubicación final, solo puede escribir y escribir,
inserte la descripción de la imagen aquí
luego debe ingresar el punto de inicio y el punto final cuando hace clic en el mapa, debe vincular el evento de clic
isNavBoxShow en el mapa como la pantalla estado del componente, startPointSelect es el estado del punto de inicio y endPointSelect es el estado del punto final

// //路径规划
        map.on('click', (event) => {
    
    
          if (this.$store.state.isNavBoxShow === true) {
    
    
            if (this.$store.state.startPointSelect === true) {
    
    
              window.routeOpiton.start = {
    
    
                x: event.coords.x,
                y: event.coords.y,
                level: event.targets[0].level,
                url: './img/start.png',
                height: 3
              };
              navi.setStartPoint(window.routeOpiton.start);
              if (event.targets[0].name) {
    
    
                document.getElementById('startInput').value = event.targets[0].name;
              } else {
    
    
                document.getElementById('startInput').value = '当前起点位置';
              }
              this.$store.commit('startPointSelectFalse');
            } else if (this.$store.state.endPointSelect === true) {
    
    
              window.routeOpiton.end = {
    
    
                x: event.coords.x,
                y: event.coords.y,
                level: event.targets[0].level,
                url: './img/end.png',
                height: 3
              }
              navi.setDestPoint(window.routeOpiton.end);

              if (event.targets[0].name) {
    
    
                document.getElementById('endInput').value = event.targets[0].name;
              } else {
    
    
                document.getElementById('endInput').value = '当前终点位置';
              }
              this.$store.commit('endPointSelectFalse');
            }
          }
        });

En este punto, podemos hacer clic en el módulo de mapa para ingresar el punto de inicio y el punto final.Haga
inserte la descripción de la imagen aquí
clic en Aceptar y llame a la función de cálculo de ruta
window.routeOpiton como los objetos punto de inicio y punto final.

navi.route(window.routeOpiton, function(result) {
    
    
          let line = navi.drawNaviLine();
          let coordinates = [];
          result.subs.forEach(item => {
    
    
            item.waypoint.points.forEach(point => {
    
    
              coordinates.push(point)
            })
          });
 })

inserte la descripción de la imagen aquí

El principio de usar Three.js para generar módulos AR

Explique los pasos de generación. El primer paso también es verificar si la cámara se puede encender, luego inicializar Three.js y luego usar el mapa de video para mapear la transmisión de video de la cámara al fondo de three.js, de modo que se puede presentar, y luego cómo No es difícil mostrar la ruta en la escena. La API de Hummingbird Cloud devolverá una matriz de la ruta más corta. Podemos calcular los datos de la ruta más corta. Primero, determine si el la distancia entre cada punto es mayor que 1. Cómo calcular dos puntos En cuanto a la distancia entre dos puntos, simplemente tome la raíz del cuadrado de los dos puntos. Si es mayor que 1 después del cálculo, hay una esquina. En este tiempo, necesitamos calcular el ángulo. El ángulo se calcula por el arco tangente. Aquí debemos prestar atención. Es la dirección de rotación del eje. Finalmente, es suficiente monitorear el giroscopio para cambiar el ángulo de los puntos generados. y líneas. En general, la idea está bien, y luego es suficiente para convertirlo en código. No es difícil implementar el código, principalmente la idea ~

Inicializar tres

//初始参数
    canvas = document.getElementById('webGL3d')
    arWidth = canvas.offsetWidth
    arHeight = canvas.offsetHeight
    scene = new THREE.Scene()
    camera = new THREE.PerspectiveCamera(60, arWidth / arHeight, 0.0001, 7000)
    camera.position.set(0, -7, 5)
    // //renderer参数
    let renderParam = {
    
    
      antialias: true, // true/false表示是否开启反锯齿
      // alpha: true, // true/false 表示是否可以设置背景色透明
      precision: 'highp', // highp/mediump/lowp 表示着色精度选择
      premultipliedAlpha: false, 
      maxLights: 3, 
      canvas: canvas 
    }
    renderer = new THREE.WebGLRenderer(renderParam)
    renderer.setSize(arWidth, arHeight)
    orbitControls = new OrbitControls(camera, renderer.domElement)

Determine si la cámara es compatible y devuelva la transmisión de video. Aquí hay un pequeño detalle. Para determinar si es un teléfono móvil o una PC, el teléfono móvil está obligado a usar la cámara trasera.

let video = document.createElement('video');
  // navigator.mediaDevices.getUserMedia 提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。

  const stream = await navigator.mediaDevices.getUserMedia({
    
    
    // 关闭音频
    audio: false,
    video: {
    
    
      // 在移动设备上面,表示优先使用前置摄像头
      // facingMode: 'user',
      facingMode: isMobile() ? {
    
     exact: "environment" } : 'user',
      width: width,
      height: height
    }
  });

  video.srcObject = stream;
  video.play();
  video.width = width;
  video.height = height;

  return new Promise((resolve) => {
    
    
    // 在视频的元数据加载后执行 JavaScript
    video.onloadedmetadata = () => {
    
    
      resolve(video);
    };
  });
function isMobile() {
    
    
  const isAndroid = /Android/i.test(navigator.userAgent);
  const isiOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
  return isAndroid || isiOS;
}

Pegue el video en el fondo de three.js después de obtener la transmisión de video

let video = await openCamera(arWidth, arHeight);
    console.log(video);
    videoTexture = new THREE.Texture(video);
    videoTexture.minFilter = THREE.LinearFilter;
    scene.background = videoTexture;

Aquí podemos ver el video y
luego creamos un marcador de punto de partida

let plane = new THREE.PlaneGeometry(1, 1)
    let map = new THREE.TextureLoader().load(require('@/assets/img/WechatIMG1129.png'))
    let material = new THREE.MeshBasicMaterial({
    
    
      map: map,
      alphaTest: 0.1,
      color: 0xffffff,
      side: THREE.DoubleSide,
    })
    nowPosPic = new THREE.Mesh(plane, material)
    nowPosPic.position.set(0, offsetY, 0)
    scene.add(nowPosPic)
    //添加坐标轴
    let axes = new THREE.AxesHelper(500)
    scene.add(axes)

inserte la descripción de la imagen aquí
dibujar línea de navegación

if (coordinates.length !== 0) {
    
    
      group = new THREE.Group()
      let starPoint = {
    
    
        x: 0,
        y: 0
      }
      for (let i = 1; i < coordinates.length; i++) {
    
    
        let x = coordinates[i].x - coordinates[0].x
        let y = coordinates[i].y - coordinates[0].y
        // 计算两点的距离
        let distance = Math.sqrt(Math.pow(x - starPoint.x, 2) + Math.pow(y - starPoint.y, 2))
        if (distance >= 1) {
    
    
        // 计算弧度
          let angle = calAngleX(x - starPoint.x, y - starPoint.y)
          // 生成线
          createLine(starPoint, distance, angle)
          starPoint.x = x
          starPoint.y = y
        }
      }
      scene.add(group)
      group.position.y = offsetY
      group.rotation.z = -alpha * Math.PI / 180
    }

Calcular código de radianes

//计算偏转角度(X逆时针)
  function calAngleX(x, y) {
    
    
    let angle = Math.atan(Math.abs(y) / Math.abs(x))
    if (x >= 0 && y >= 0) {
    
    

    } else if (x <= 0 && y >= 0) {
    
    
      angle = Math.PI - angle
    } else if (x <= 0 && y <= 0) {
    
    
      angle = Math.PI + angle
    } else {
    
    
      angle = Math.PI * 2 - angle
    }
    return angle
  }

generar línea

let plane = new THREE.PlaneGeometry(1, 1)
    let map = new THREE.TextureLoader().load(require('@/assets/img/WechatIMG1123.png'))
    let material = new THREE.MeshBasicMaterial({
    
    
      map: map,
      alphaTest: 0.1,
      color: 0xffffff,
      side: THREE.DoubleSide,
    })
    for (let i = 0.6; i <= length; i++) {
    
    
      let mesh = new THREE.Mesh(plane, material)
      let x = starPoint.x + i * Math.cos(angle)
      let y = starPoint.y + i * Math.sin(angle)
      mesh.position.set(x, y, 0)
      let obj = {
    
    
        x: x + coordinates[0].x,
        y: y + coordinates[0].y
      }
      lingMeshArray.push(obj)
      mesh.rotation.z = angle - Math.PI / 2
      group.add(mesh)
    }

Puede ver la línea generada aquí
inserte la descripción de la imagen aquí
Monitoree la ventana del giroscopio.DeviceOrientationEvent
window.DeviceOrientationEvent Descripción
DeviceOrientationEvent.absolute Valor booleano de solo lectura
utilizado para indicar si los datos de rotación proporcionados por el dispositivo son de posicionamiento absoluto.
DeviceOrientationEvent.alpha solo lectura
Un número que representa el ángulo de rotación del dispositivo alrededor del eje z (rango entre 0-360)
DeviceOrientationEvent.beta Solo lectura
un número que representa la rotación del dispositivo alrededor del eje x (rango entre - 180 y 180), la dirección de adelante hacia atrás es la dirección positiva.
DeviceOrientationEvent.gamma solo lectura
Un número que representa la rotación del dispositivo alrededor del eje y (que va de -90 a 90), dirección positiva de izquierda a derecha.
el acelerador es solo una función de aceleración

if (window.DeviceOrientationEvent) {
    
    
      window.addEventListener('deviceorientation', throttle(setMeshCamera, 100), false)
    } else {
    
    
      console.log('你的浏览器不支持陀螺仪')
    }

Finalmente, calcule el ángulo de rotación del punto de partida y la línea según el giroscopio.

Supongo que te gusta

Origin blog.csdn.net/qq_39503511/article/details/121062399
Recomendado
Clasificación