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

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

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

maptalks+three.js+vue webpack实现二维地图上贴三维模型操作_第1张图片

以下都在已经引入并且初始化maptalks地图的基础上,如何引入使用maptalks可以查看以下文章

https://www.jb51.net/article/192983.htm

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下(放在这里是因为打包后读取路径问题,目前发现放在这里才能在打包后正确读取)

maptalks+three.js+vue webpack实现二维地图上贴三维模型操作_第2张图片

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': '
' + '

浦软大厦详情

' + '
  • 入驻企业:12 家
  • 登记人员:1000 人
  • 今日访客:100 人
  • 登记车辆:500 辆
  • 实时人数:0 人
  • 监控点位:0 个
  • 人脸门禁:0 个
  • 消防设施:0 个
' + '
' } 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的代码我没有进行详细的解释,如果需要会出一个详细版的方法使用介绍

补充知识:Vue npm安装Vue常用依赖,axios、element ui、mockjs

添加axios依赖:

npm install axios

添加element-ui:

npm i element-ui -S

添加 mockjs:

npm install mockjs

以上这篇maptalks+three.js+vue webpack实现二维地图上贴三维模型操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

你可能感兴趣的:(maptalks+three.js+vue webpack实现二维地图上贴三维模型操作)