maptalks+three.js+vue webpack项目实现二维地图上贴三维模型

小编 2026-07-13 阅读:841 评论:0
我们不是走在坑里就是走在前往坑的路上_(:зゝ∠)_ 最终效果如图:(地图上添加一个“三维地图”的toolbar按钮,点击后在二维地图上贴上建好的三维模型点击显示弹框) 以下都在已经引入并且初始...

我们不是走在坑里就是走在前往坑的路上_(:зゝ∠)_

最终效果如图:(地图上添加一个“三维地图”的toolbar按钮,点击后在二维地图上贴上建好的三维模型点击显示弹框)

\"\"

以下都在已经引入并且初始化maptalks地图的基础上,如何引入使用maptalks可以查看博客https://blog.csdn.net/liona_koukou/article/details/84316065

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、引入model模型文件到public下(放在这里是因为打包后读取路径问题,目前发现放在这里才能在打包后正确读取)

\"\"

5、Vue页面代码

引入包

import * as THREE from \'three\'
import * as maptalks from \'maptalks\'
import { ThreeLayer } from \'maptalks.three\'
import { MTLLoader, OBJLoader } from \'three-obj-mtl-loader\'

初始化的地图对象是

this.map

下面是渲染三维模型的方法

// 渲染三维
draw3D() {
  const that = this
  // 三维地图
  var three_flag = false
  // ///单体化交互开始
  var INTERSECTED
  this.map.on(\'click\', function(e) {
    //    console.log(e)
    var raycaster = new THREE.Raycaster()
    var mouse = new THREE.Vector2()
    const camera = threeLayer.getCamera()
    const scene = threeLayer.getScene()
    if (!scene) return

    const size = that.map.getSize()
    const width = size.width; const height = size.height
    mouse.x = (e.containerPoint.x / width) * 2 - 1
    mouse.y = -((e.containerPoint.y) / height) * 2 + 1

    raycaster.setFromCamera(mouse, camera)
    raycaster.linePrecision = 3

    var intersects = raycaster.intersectObjects(scene.children, true)
    // var intersects = raycaster.intersectObject(points);
    if (!intersects) return
    if (Array.isArray(intersects) && intersects.length === 0) return
    console.log(intersects)
    // 这里我们操作第一个相交的物体
    if (intersects.length > 0) {
      if (INTERSECTED != intersects[0].object) {
        if (INTERSECTED) {
          // INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
          // INTERSECTED.scale.set(1,1,1);
          if (INTERSECTED.material.length === undefined) {
            INTERSECTED.material.color.setHex(INTERSECTED.currentHex)
          } else {
            for (var i = 0; i < INTERSECTED.material.length; i++) {
              INTERSECTED.material[i].color.setHex(INTERSECTED.currentHex)
            }
          }
        }
        INTERSECTED = intersects[0].object

        // 设置相交的第一个物体的颜色
        // INTERSECTED.currentHex = INTERSECTED.material[0].color.getHex();
        INTERSECTED.currentHex = 16777215
        // 将该物体设为随机的其他颜色
        // INTERSECTED.material.opacity = 0.2;

        // INTERSECTED.material.transparent = true;
        // INTERSECTED.material.opacity = 0.2;
        // INTERSECTED.material.needsUpdate = true;
        // INTERSECTED.material.transparent = false;

        // INTERSECTED.material.color.setHex(0xff0000);
        if (INTERSECTED.material.length === undefined) {
          INTERSECTED.material.color.setHex(0x1E90FF)
        } else {
          for (var i = 0; i < INTERSECTED.material.length; i++) {
            INTERSECTED.material[i].color.setHex(0x1E90FF)
          }
        }
      }
      // //////////////
      var lonlat = e.coordinate
      if (true) {
        var options = {
          \'autoOpenOn\': \'null\', // set to null if not to open window when clicking on map
          \'single\': true,
          \'width\': 410,
          \'height\': 190,
          \'custom\': true,
          \'autoCloseOn\': \'click\',
          \'dy\': -316,
          \'content\': \'<div class=\"content build-content\">\' +
            \'<div class=\"pop-img\"><img src=\"http://pde56fqkk.bkt.clouddn.com/1544760152593.jpg\"/><p class=\"pop-name build-pop-name\" id=\"viewDetial\"><span class=\"text-ellipsis\" title=\"浦软大厦\">浦软大厦</span><a>详情<i class=\"el-icon-arrow-right\"></i></a></p></div>\' +
            \'<div class=\"pop-txt\"><ul><li>入驻企业:<span>12 家</span> </li><li>登记人员:<span>1000 人</span> </li><li>今日访客:<span>100 人</span> </li><li>登记车辆:<span>500 辆</span> </li><li>实时人数:<span>0 人</span> </li><li>监控点位:<span>0 个</span> </li><li>人脸门禁:<span>0 个</span> </li><li>消防设施:<span>0 个</span></li></ul></div>\' +
            \'</div>\'
        }
        var infoWindow = new maptalks.ui.InfoWindow(options)
        infoWindow.addTo(that.map).show(lonlat)
      }
    } else {
      // 当射线离开的时候变为原来的颜色
      if (INTERSECTED) {
        // INTERSECTED.material.color.set(INTERSECTED.currentHex);
        if (INTERSECTED.material.length === undefined) {
          INTERSECTED.material.color.setHex(INTERSECTED.currentHex)
        } else {
          for (var i = 0; i < INTERSECTED.material.length; i++) {
            INTERSECTED.material[i].color.setHex(INTERSECTED.currentHex)
          }
          // INTERSECTED.scale.set(1,1,1);
        }
      }
      INTERSECTED = null
    }
    threeLayer.renderScene()
  })

  function closeBox() {
    var theClose = document.getElementById(\'close_id\')
    var cont = document.getElementById(\'infow\')
    cont.style.display = \'None\'
  }

  // ///单体化交互结束
  // the ThreeLayer to draw buildings
  // //ThreeLayer初始化
  var threeLayer = new ThreeLayer(\'t_forbcmp\', {
    forceRenderOnMoving: true,
    forceRenderOnRotating: true,
    animation: true
  })

  threeLayer.prepareToDraw = function(gl, scene, camera) {
    var me = this
    // var light = new THREE.PointLight(0xffffff);
    // camera.add(light);
    // let axes=new THREE.AxesHelper(200000000);
    // scene.add(axes);
    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 light1 = new THREE.DirectionalLight(\"#ffffff\");
    // light1.position.set(-800,-800,800).normalize();
    // light1.castShadow = true;
    // camera.add(light1);

    // 测试加载obj和mtl贴图
    // addmtlLoaderTest(13.438186479666001,52.530305072175594);
    // addmtlLoaderTestforMTL(13.436186479666001,52.530305072175594);
    // 相对路径参数,
    var mtlPath = process.env.BASE_URL + \'model/obj/\'
    var mtlName = \'3d_puruan_new.mtl\'
    var objPath = process.env.BASE_URL + \'model/obj/\'
    var objName = \'3d_puruan3.obj\'
    var objlon = 121.60499979860407
    var objlat = 31.20150084741559
    addLoaderForObj(objlon, objlat, mtlPath, mtlName, objPath, objName)
  }

  threeLayer.addTo(that.map).hide()

  // ////////////////加载模型相关
  // 加载obj+mtl
  function addLoaderForObj(lon, lat, mtlPath, mtlName, objPath, objName) {
    const me = threeLayer
    const scene = me.getScene()
    const scale = -0.0007
    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) {
        object.traverse(function(child) {
          if (child instanceof THREE.Mesh) {
            child.scale.set(scale, scale, scale)
            child.rotation.set(-Math.PI / 2, Math.PI, 0)
            // 赋予基础材质的颜色,无色(0xFFFFFF)调试色0x0000FF
            for (var i = 0; i < child.material.length; i++) {
              child.material[i].color.setHex(0x0000FF)
            }
          }
        })

        var v = threeLayer.coordinateToVector3(new maptalks.Coordinate(lon, lat))
        object.position.set(v.x, v.y, 0)
        scene.add(object)
        mtlLoaded = true
        threeLayer.renderScene()
      })
      // var mm = new THREE.MeshPhongMaterial({color:0xFF0000});
      // objLoader.setMaterials( mm );
      // objLoader.setMaterials(materials);
    })
  }
  var toolbar = new maptalks.control.Toolbar({
    position: { \'right\': 40, \'bottom\': 40 },
    items: [
      {
        item: \'二三维图层切换\',
        click: function() {
          if (three_flag === false) {
            that.map.animateTo({
              center: [121.6050804009, 31.2015354151],
              zoom: 18,
              pitch: 45
            }, {
              duration: 2000
            })
            threeLayer.show()
            three_flag = true
          } else {
            that.map.animateTo({
              center: [121.6050804009, 31.2015354151],
              zoom: 18,
              pitch: 0
            }, {
              duration: 2000
            })
            threeLayer.hide()
            three_flag = false
          }
          console.log(\'obj模型\')
        }
      }
    ]
  }).addTo(this.map)
}

上面这段代码需要注意的是模型数据文件的读取路径

// 相对路径参数,
var mtlPath = process.env.BASE_URL + \'model/obj/\'
var mtlName = \'3d_puruan_new.mtl\'
var objPath = process.env.BASE_URL + \'model/obj/\'
var objName = \'3d_puruan3.obj\'

关于process.env.BASE_URL的值可以在vue.config.js里自定义设置(cli3.0)

baseUrl: process.env.NODE_ENV === \'production\' ? \'/bcmp-web/\' : \'/\',

关于draw3D的代码我没有进行详细的解释,如果需要会出一个详细版的方法使用介绍

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
标签列表