maptalks+three.js+vue webpack实现二维地图上贴三维模型操作
我们不是走在坑里就是走在前往坑的路上_(:зゝ∠)_
最终效果如图:(地图上添加一个“三维地图”的toolbar按钮,点击后在二维地图上贴上建好的三维模型点击显示弹框)
以下都在已经引入并且初始化maptalks地图的基础上,如何引入使用maptalks可以查看以下文章
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的代码我没有进行详细的解释,如果需要会出一个详细版的方法使用介绍
补充知识: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实现二维地图上贴三维模型操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。