vue2+three.js做出一个精美的3D地图——2.创建地图

前言

代码地址 : https://gitee.com/txcst/3-dmap.git 只想好好做开源。

上一期我们已经把基础的three.js环境搭建好了,现在我们准备往里面加地图进去吧


一、加入中国地图

想要构建地图必须要要有地图的数据,我是从
阿里云的地图可视化构建平台
获取的,这个还比较好用一些,获取数据之后,把获取到的json数据加到public文件下,要不然调用会出问题
在这里插入图片描述

  1. 首先我们解析数据
getMapData(){
        let loader = new THREE.FileLoader()
           //地图对象
            map = new THREE.Object3D();
                loader.load('/data/map.json', (data) => {
                    const jsondata = JSON.parse(data)
                    this.generateGeometry(jsondata)
                })
      }
  1. 接下来就是构建地图,我们先把准备工作做好
    引用 d3gui,d3需要外部引用,直接去npm里面下载就好了,gui在three包里可以找到
   import * as dat  from 'three/examples/jsm/libs/lil-gui.module.min.js';
   import * as d3  from  'd3';
  1. 通过解析的数据然后循环去构建一个个模块,我会加上大量注释,帮助大家理解
 generateGeometry(jsondata){
 
   //地图秃秃的不好看,我们给地图加个皮肤,使用three.js自带的文件加载器,加载一张图片
    var texture = new THREE.TextureLoader().load("/data/mapBack.png");
    //关闭 matrixAutoUpdate 属性,方便我们后面对贴图进行  矩阵转换
    texture.matrixAutoUpdate = false;
     //d3是另一种3d可视化库 ,这里我们需要引用他,用它的中心点去矫正我们的地图坐标
    //保证地图出现在我们想要的位置
    // 墨卡托投影转换
    const projection = d3
        .geoMercator()
        //this.centerX,this.centerY  代表我们屏幕的正中间出现的 地图中心点位置
        // centerX:108.5525 ,
       // centerY:34.3227,
       //随便百度的,你也可以根据你的需求来更改中心点
        .center([this.centerX,this.centerY])
        .translate([0, 0])
          jsondata.features.forEach((elem) => {
             // 定一个省份3D对象
       let  province = new THREE.Object3D()
        // 每个的 坐标 数组
        const coordinates = elem.geometry.coordinates  
        // 循环坐标数组
        coordinates.forEach((multiPolygon) => {
            multiPolygon.forEach((polygon) => {
                //构建几何图形
                const shape = new THREE.Shape()
                for (let i = 0; i < polygon.length; i++) {
                    const [x, y] = projection(polygon[i])
                    //如果有NvN的数据就让他跳过,要不然three.js会报错
                    if(!x){
                        continue;
                    }
                    //指定我们的起点
                    if (i === 0) {
                        shape.moveTo(x, -y)
                    }
                     //后续就开始从起点画线
                     //如果你使用过canvans画线,那你肯定秒懂,他们是一个道理
                    shape.lineTo(x, -y)
                }
                //构建地图的 正面贴图 ,这里使用基础材质,关于材质,大家可以去详细看看api
                material = new THREE.MeshBasicMaterial  ({
                    // color:'#144685',
                    transparent: true,
                    opacity:0.9,
                    map:texture,
                })
                   //构建地图的 侧面贴图 ,这里使用基础材质
                const material_1 = new THREE.MeshBasicMaterial   ({
                    color: '#558BAB',
                    transparent: true,
                    opacity: 0.45,

                })

                const extrudeSettings = {
                    depth: 2,
                    bevelEnabled: false,
                }
                //这里我们把先前构造的几何图形 通过ExtrudeGeometry 拉伸成几何体
                const geometry = new THREE.ExtrudeGeometry(
                    shape,
                    extrudeSettings
                )
                //把几何体和  我们两个贴图 合成一个 网格对象 mesh
                const mesh = new THREE.Mesh(geometry, [material, material_1])
              //把网格对象加入省份的3d对象
                province.add(mesh)
            })
        })
      //地图加入省份
      map.add(province)
    })
})       
 }

地图此时已经初步出来了,但我们的正面贴图没有起效,我明明用的是这张图片作为正面贴图
在这里插入图片描述还记得之前引用的 gui吗 ,我们现在来使用它调整我们的 贴图

let  gui = {
        offsetX: 0,
        offsetY: 0,
        repeatX: 0.006,
        repeatY: 0.006,
        rotation:-0.1,
        centerX: 0.582,
        centerY: 0.398,
        RepeatWrapping:false
    };
    //定义gui对象
    let guisd=new dat.GUI()
    //更新纹理贴图的方法
    function updateUV() {
        material.map.matrix
            .identity() //矩阵重置
            .translate( - gui.centerX, - gui.centerY ) //设置中心点
            .rotate( gui.rotation ) // 旋转
            .scale( gui.repeatX, gui.repeatY ) //缩放
            .translate( gui.centerX, gui.centerY ) //设置中心点
            .translate( gui.offsetX, gui.offsetY ); //偏移
    };

使用 gui去控制我们的 贴图属性,进行矩阵重置 写在 generateGeometry循环外面就可以

    updateUV()
    guisd.add(gui, "offsetX", 0.0, 1.0 ).onChange(updateUV);
    guisd.add(gui, "offsetY", 0.0, 1.0).onChange(updateUV);
    guisd.add(gui, "repeatX", -10.0, 10.0).onChange(updateUV);
    guisd.add(gui, "repeatY", -10.0, 10.0).onChange(updateUV);
    guisd.add(gui, "rotation", - 10.0, 10.0).onChange(updateUV);
    guisd.add(gui, "centerX", 0.0, 1.0).onChange(updateUV);
    guisd.add(gui, "centerY", 0.0, 1.0).onChange(updateUV);
    guisd.add(gui, "RepeatWrapping").onChange(function (e) {
        console.log(gui,"ssssss")
        if(e){
            material.map.wrapS = material.map.wrapT = THREE.RepeatWrapping; //设置为可循环
        }
        else{
            material.map.wrapS = material.map.wrapT = THREE.ClampToEdgeWrapping; //设置会默认的最后一像素伸展
        }
    
        material.map.needsUpdate = true;
    });

经过一番调整,终于有皮肤啦
在这里插入图片描述

二、加入亿点细节

  1. 单单的地图 显得太单调了,我们给他来个叠穿,丰富一下地图模型
                const  extrudeSettings_2={
                    depth: 1,
                    bevelEnabled: false,
                }
                const geometry_2 = new THREE.ExtrudeGeometry(
                    shape,
                    extrudeSettings_2
                )
                const material_2 = new THREE.MeshBasicMaterial   ({
                    color: '#ffffff',
                    transparent: true,
                    opacity: 0,

                })

按照上面的步骤再创造一个拉伸的几何体,不过他的厚度只有1,为他在创建新的贴图,为他换个皮肤,出来一点层次感,

//把几何体和  我们两个贴图 合成一个 网格对象 mesh
                const mesh = new THREE.Mesh(geometry, [material, material_1])

                const mesh_2 = new THREE.Mesh(geometry_2, [material_1,material_2])
               
                const mesh_3= mesh_2.clone()
                mesh.castShadow=true
              //把网格对象加入省份的3d对象
                mesh.position.z=4
                mesh_2.position.z=1
                mesh_3.position.z=-2
                province.add(mesh)
                province.add(mesh_2)
                province.add(mesh_3)

在创建两个新的网格对象,让他贴在地图下面,然后调整一下他们z轴的高度,把他们三个网格对象拉开,加入省份对象
这样看不是很明显啊,我们来调整一下 地图对象的坐标

  map.rotation.x=-0.82

效果很明显了 ,真不错
在这里插入图片描述

下一期,我们再增添一些细节,给他加上边线,并让边线发光

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值