vue使用maptalks地图+three加载video视频obj+mtl和gltf模型

Posted 瞌睡虫、、

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue使用maptalks地图+three加载video视频obj+mtl和gltf模型相关的知识,希望对你有一定的参考价值。

效果图:2D

效果图:3D

maptalks地图官网案例
https://maptalks.org/examples/cn/map/load/#map_load
1、安装maptalks.three包
npm install maptalks.three
2、安装three包
npm install three
3、安装obj-loader和mtl-loader包
npm i --save three-obj-mtl-loader
4、安装vue-video-player视频包
npm install vue-video-player --save
5、安装maptalks 地图包
npm install maptalks --save

<template>
  <div id="map" class="container"></div>
</template>

<script>
import * as maptalks from "maptalks";
import videojs from "video.js";
import "video.js/dist/video-js.css";
import "vue-video-player/src/custom-theme.css";
import "videojs-flash";
import * as THREE from "three";
import  ThreeLayer  from "maptalks.three";
import  MTLLoader, OBJLoader  from "three-obj-mtl-loader";
import  GLTFLoader  from "three/examples/jsm/loaders/GLTFLoader";
export default 
  name: "BaseMap",
  data() 
    return 
      videoPlayer: null,
      map: null,
      layer_monitor: null,
      layer_fire: null,
      monitor: [],
      fire: [],
      three_flag: false,
    ;
  ,
  mounted() 
    const that = this;
    // 初始化maptalks地图
    this.map = new maptalks.Map("map", 
      center: [116.267462, 40.046213],
      zoom: 18,
      baseLayer: new maptalks.TileLayer("base", 
        urlTemplate: "https://s.basemaps.cartocdn.com/light_all/z/x/y.png",
        subdomains: ["a", "b", "c", "d"],
        attribution:
          '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
      ),
      // spatialReference: 
      //   projection: "EPSG:4326",
      // ,
      // baseLayer: new maptalks.WMSTileLayer("wms", 
      //   tileSystem: [1, -1, -180, 90],
      //   urlTemplate: "https://ows.terrestris.de/osm/service",
      //   crs: "EPSG:4326",
      //   layers: "OSM-WMS",
      //   styles: "",
      //   version: "1.3.0",
      //   format: "image/png",
      //   transparent: true,
      //   uppercase: true,
      // ),
      // attribution: 
      //   // 左下角info
      //   content: "&copy ows.terrestris.de",
      // ,
    );
    // 声明放置监控设备的图层
    this.layer_monitor = new maptalks.VectorLayer("monitor").addTo(this.map);
    // 声明放置消防设施的图层
    this.layer_fire = new maptalks.VectorLayer("fire").addTo(this.map);
    // 监听地图点击事件
    this.map.on("click", function (e) 
      if (that.videoPlayer) 
        that.videoPlayer.dispose();
        that.videoPlayer = null;
      
    );
    // 监控设备上图
    this.getMarks();
    // 加载模型
    this.draw3D();
  ,
  methods: 
    // 渲染三维
    draw3D() 
      const that = this;
      // 三维地图
      // 加载gltf
      // the ThreeLayer to draw buildings
      var threeLayergltf = new ThreeLayer("t", 
        forceRenderOnMoving: true,
        forceRenderOnRotating: true,
        animation: true,
      );
      threeLayergltf.prepareToDraw = function (gl, scene, camera) 
        // 环境光
        var light = new THREE.DirectionalLight(0xffffff);
        light.position.set(0, -10, 10).normalize();
        scene.add(light);
        camera.add(new THREE.PointLight("#fff", 4));
        // 模型路径 放到public下
        var modelName = "scene.gltf";
        var modelPath = "/gltf/";
        // 地图坐标
        var modellon = 116.267962;
        var modellat = 40.046893;
        addGltf(modelName, modelPath, modellon, modellat);
      ;
      // 添加到地图
      threeLayergltf.addTo(this.map).hide();
      // gltf模型渲染
      function addGltf(modelName, modelPath, modellon, modellat) 
        // 声明参数
        const me = threeLayergltf;
        const scene = me.getScene();
        const scale = 0.002;
        // 加载GLTFLoader模型
        var gltfloader = new GLTFLoader();
        gltfloader.setPath(modelPath);
        gltfloader.load(modelName, (gltf) => 
          // 获取模型参数
          var model = gltf.scene.children[0];
          // 控制模型大小
          model.scale.set(scale, scale, scale);
          // 模型在maptalks的位置
          var v = threeLayergltf.coordinateToVector3(
            new maptalks.Coordinate(modellon, modellat)
          );
          model.position.set(v.x, v.y, 0);
          // 模型在地图上角度
          model.rotation.set(Math.PI, Math.PI, 0);
          // 放进模型
          scene.add(model);
          // 渲染
          threeLayergltf.renderScene();
        );
      

      // 加载obj+mtl
      // ThreeLayer初始化
      var threeLayer = new ThreeLayer("t_forbcmp", 
        forceRenderOnMoving: true,
        forceRenderOnRotating: true,
        animation: true,
      );
      threeLayer.prepareToDraw = function (gl, scene, camera) 
        var me = this;
        var light0 = new THREE.DirectionalLight("#ffffff", 0.5);
        light0.position.set(800, 800, 800).normalize();
        light0.castShadow = true;
        camera.add(light0);
        // 环境光
        var light01 = new THREE.AmbientLight("#f7fdf9");
        light01.castShadow = true;
        scene.add(light01);
        // 相对路径参数
        var mtlPath = "/model/";
        var mtlName = "Shirley.mtl";
        var objPath = "/model/";
        var objName = "Shirley.obj";
        //116.267462, 40.046213
        var objlon = 116.266462;
        var objlat = 40.046893;
        addLoaderForObj(objlon, objlat, mtlPath, mtlName, objPath, objName);
      ;
      threeLayer.addTo(that.map).hide();
      // 加载模型相关
      function addLoaderForObj(lon, lat, mtlPath, mtlName, objPath, objName) 
        const me = threeLayer;
        const scene = me.getScene();
        const scale = 1;
        var mtlLoader = new MTLLoader();
        // 加载贴图mtl
        mtlLoader.setPath(mtlPath);
        mtlLoader.load(mtlName, function (materials) 
          materials.preload();
          var objLoader = new OBJLoader();
          objLoader.setMaterials(materials);
          // 加载模型obj  Math.PI*3/2
          objLoader.setPath(objPath);
          objLoader.load(objName, function (object) 
            // 控制模型大小
            var v = threeLayer.coordinateToVector3(new maptalks.Coordinate(lon, lat));
            object.scale.set(scale, scale, scale);
            // 模型角度
            object.rotation.set(Math.PI / 2, Math.PI / 7, 0);
            // 模型位置
            object.position.set(v.x, v.y, 0);
            // 渲染
            scene.add(object);
            threeLayer.renderScene();
          );
        );
      

      // 二三维图层切换
      var toolbar = new maptalks.control.Toolbar(
        position:  right: 40, bottom: 40 ,
        items: [
          
            item: "二三维图层切换",
            click: function () 
              if (that.three_flag === false) 
                that.map.animateTo(
                  
                    center: [116.267462, 40.046213],
                    zoom: 18,
                    pitch: 45,
                  ,
                  
                    duration: 2000,
                  
                );
                threeLayer.show();
                threeLayergltf.show();
                // 标注点显示隐藏
                that.layer_monitor.hide();
                that.layer_fire.hide();
                that.three_flag = true;
               else 
                that.map.animateTo(
                  
                    center: [116.267462, 40.046213],
                    zoom: 18,
                    pitch: 0,
                  ,
                  
                    duration: 2000,
                  
                );
                threeLayer.hide();
                threeLayergltf.hide();
                // 标注点显示隐藏
                that.layer_monitor.show();
                that.layer_fire.show();
                that.three_flag = false;
              
              console.log("obj模型");
            ,
          ,
        ],
      ).addTo(this.map);
    ,
    // 模拟数据
    getMarks() 
      const that = this;
      const res = [
        // 
        //   id: 11,
        //   type: "monitor",
        //   name: "奥克斯广场5楼H座",
        //   position: [116.267162, 40.046413],
        // ,
        
          id: 12,
          type: "fire",
          name: "奥克斯广场4楼H座",
          position: [116.267462, 40.046213],
        ,
        
          id: 14,
          type: "fire",
          name: "奥克斯广场4楼H座",
          position: [116.267162, 40.046413],
        ,
        
          id: 13,
          type: "monitor",
          name: "奥克斯广场3楼H座",
          position: [116.267762, 40.046613],
        ,
      ];
      const monitor = [];
      const fire = [];
      res.forEach((item, index) => 
        if (item.type === "monitor") 
          monitor.push(item);
        
        if (item.type === "fire") 
          fire.push(item);
        
      );
      that.monitor = monitor;
      that.fire = fire;
      that.markerInMap();
    ,
    // 地图标注点
    markerInMap() 
      const that = this;
      for (var m = 0; m < that.monitor.length; m++) 
        // lon and lat in here
        var markerm = new maptalks.Marker(that.monitor[m].position, 
          // 图形样式
          symbol: 
            markerFile: require("../assets/logo.png"),
            markerWidth: 28,
            markerHeight: 36,
            markerDx: 0,
            markerDy: 0,
            markerOpacity: 1,
          ,
        ).addTo(that.layer_monitor);
        markerm
          .setInfoWindow(
            autoPan: true,
            width: 330,
            minHeight: 330,
            dy: 4,
            custom: false, // 只使用定制自定义true
            autoOpenOn: "click", // set to null if not to open when clicking on marker
            autoCloseOn: "click",
            // 支持自定义html内容
            content:
              '<div class="content equip-content">' +
              '<div class="pop-video"><video id="video_' +
              that.monitor[m].id +
              '" class="video-js vjs-default-skin vjs-big-play-centered" controls fluid="true" width="485" height="275">' +
              '  <source src="rtmp://212.64.34.125:10935/hls/stream_27" type="rtmp/flv">' +
              "</video></div>" +
              '<div class="pop-bottom">' +
              that.monitor[m].name +
              '<a id="moreMonitor" style="cursor:pointer;" data-id="' +
              that.monitor[m].id +
              '">查看更多<i class="el-icon-arrow-right"></i></a></div>' +
              "</div>",
          )
          .on("mousedown", onClick);
        function onClick(e) 
          setTimeout(function () 
            const moreMonitor = document.getElementById("moreMonitor");
            moreMonitor.onclick = function () 
              that.$router.push(
                path: "/video/realMonitor",
                query:  id: moreMonitor.dataset

使用 Vue-cli 和 Three.js 加载 STL 文件

【中文标题】使用 Vue-cli 和 Three.js 加载 STL 文件【英文标题】:Loading STL files with Vue-cli and Three.js 【发布时间】:2021-05-26 15:29:06 【问题描述】:

我目前遇到的问题是我无法将 STL 文件加载到通过 vue-cli 创建的 three.js 场景中。

使用 vue-cli 'vue init webpack ProjectName', 'cd ProjectName', 'npm install three --save' 设置项目,并用此代码替换 'HelloWorld' 组件。

stl 文件和这个 vue 组件在同一个文件夹中。

<template>
  <div id="container"></div>
</template>
<script>
import * as THREE from 'three'
import  STLLoader  from 'three/examples/jsm/loaders/STLLoader.js';

export default 
  name: 'ThreeTest',
  data() 
    return 
      cube: null,
      renderer: null,
      scene: null,
      camera: null
    
  ,
  methods: 
    init: function() 
      this.scene = new THREE.Scene()
      this.camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      )

      this.renderer = new THREE.WebGLRenderer()
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      document.body.appendChild(this.renderer.domElement)

      const geometry = new THREE.BoxGeometry(1, 1, 1)
      const material = new THREE.MeshBasicMaterial( color: 0x00ff00 )
      this.cube = new THREE.Mesh(geometry, material)
      var loader = new STLLoader();
            loader.load( 'test.stl', function ( geometry ) 
                var material = new THREE.MeshPhongMaterial( 
                      ambient: 0xff5533, 
                      color: 0xff5533, 
                      specular: 0x111111,
                      shininess: 200                                          
        );
        mesh = new THREE.Mesh( geometry, material );
        mesh.position.set(0, 100, 0);
        this.scene.add(mesh)
      , undefined, function ( error ) console.error( error ); );
      // this.scene.add(this.cube)

      this.camera.position.z = 5

      const animate = function() 
    ,
    animate: function() 
      requestAnimationFrame(this.animate)

      this.cube.rotation.x += 0.01
      this.cube.rotation.y += 0.01

      this.renderer.render(this.scene, this.camera)
    
  ,
  mounted() 
    this.init()
    this.animate()
  

</script>

我不知道为什么我有这个错误的黑屏:

RangeError: Invalid typed array length: 5202511335
    at new Float32Array (<anonymous>)
    at parseBinary (STLLoader.js?e2c6:199)
    at STLLoader.parse (STLLoader.js?e2c6:396)
    at Object.eval [as onLoad] (STLLoader.js?e2c6:87)
    at XMLHttpRequest.eval

有人可以帮我吗?

谢谢! :)

问候

【问题讨论】:

您能否通过浏览器的开发控制台从后端实际加载一个 STL 文件(而不是 HTML)?有时,用户将资产放入错误的目录,从而导致服务不正确。 你能解释一下我如何验证我实际加载了一个 stl 文件吗?我是网络开发新手,所以我没有所有技巧:/。我在 init 函数的开头放置了一个运行良好的 console.log("Model") (它不在这篇文章中,因为我是在之后做的)。 【参考方案1】:

回答

我安装了最新版本的 vue-cli,它有一个“公共”文件夹。我还安装了hujiulong的“vue-3d-model”,现在它工作正常! :D

我不知道是什么问题,也许 Vue 在没有公用文件夹的情况下具有受限权限?

【讨论】:

以上是关于vue使用maptalks地图+three加载video视频obj+mtl和gltf模型的主要内容,如果未能解决你的问题,请参考以下文章

maptalks+three实战项目 智慧城市项目

THREE.JS学习使用THREEJS加载GeoJSON地图数据

基于Echarts+百度地图+Three.js的数据可视化系统

使用 Vue-cli 和 Three.js 加载 STL 文件

百度地图threejs相关

使用vue学习three.js之加载和使用纹理-加载DDSPVRTGA格式的纹理,使用纹理材质创建模型