
vue2+three.js做出一个精美的3D地图——2.创建地图
创建地图
·
前言
代码地址 : https://gitee.com/txcst/3-dmap.git 只想好好做开源。
上一期我们已经把基础的three.js环境搭建好了,现在我们准备往里面加地图进去吧
一、加入中国地图
想要构建地图必须要要有地图的数据,我是从
阿里云的地图可视化构建平台
获取的,这个还比较好用一些,获取数据之后,把获取到的json数据加到public文件下,要不然调用会出问题
- 首先我们解析数据
getMapData(){
let loader = new THREE.FileLoader()
//地图对象
map = new THREE.Object3D();
loader.load('/data/map.json', (data) => {
const jsondata = JSON.parse(data)
this.generateGeometry(jsondata)
})
}
- 接下来就是构建地图,我们先把准备工作做好
引用 d3和gui,d3需要外部引用,直接去npm里面下载就好了,gui在three包里可以找到
import * as dat from 'three/examples/jsm/libs/lil-gui.module.min.js';
import * as d3 from 'd3';
- 通过解析的数据然后循环去构建一个个模块,我会加上大量注释,帮助大家理解
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;
});
经过一番调整,终于有皮肤啦
二、加入亿点细节
- 单单的地图 显得太单调了,我们给他来个叠穿,丰富一下地图模型
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
效果很明显了 ,真不错
下一期,我们再增添一些细节,给他加上边线,并让边线发光
点击阅读全文
更多推荐
活动日历
查看更多
直播时间 2025-02-26 16:00:00


直播时间 2025-01-08 16:30:00


直播时间 2024-12-11 16:30:00


直播时间 2024-11-27 16:30:00


直播时间 2024-11-21 16:30:00


所有评论(0)