记录--可视化大屏-用threejs撸一个3d中国地图
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

不想看繁琐步骤的,可以直接去github下载项目,如果可以顺便来个star哈哈
本项目使用vue-cli创建,但不影响使用,主要绘制都已封装成类
1、使用geoJson绘制3d地图
1.1 创建场景相关
// 创建webGL渲染器
this.renderer = new THREE.WebGLRenderer( { antialias: true,alpha: true} );
this.renderer.shadowMap.enabled = true; // 开启阴影
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
this.renderer.toneMappingExposure = 1.25; // 根据自己的需要调整颜色模式
// this.renderer.outputEncoding = THREE.sRGBEncoding; this.renderer.outputEncoding = THREE.sHSVEncoding;
this.renderer.setPixelRatio( window.devicePixelRatio );
// 清除背景色,透明背景
this.renderer.setClearColor(0xffffff, 0);
this.renderer.setSize(this.width, this.height); // 场景
this.scene = new THREE.Scene();
this.scene.background = null
// 相机 透视相机
this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, 0.1, 5000);
this.camera.position.set(0, -40, 70);
this.camera.lookAt(0, 0, 0);
1.2 根据json绘制地图
利用THREE.Shape绘制地图的平面边数据,再用THREE.ExtrudeGeometry将一个面拉高成3d模型,3d饼图同理也可以这么制作
let jsonData = require('./json/china.json')
this.initMap(jsonData);
// initMap 方法主要部分
initMap(chinaJson) {
/* ...省略
...
*/
chinaJson.features.forEach((elem, index) => {
// 定一个省份3D对象
const province = new THREE.Object3D();
// 每个的 坐标 数组
const { coordinates } = elem.geometry;
const color = COLOR_ARR[index % COLOR_ARR.length]
// 循环坐标数组
coordinates.forEach(multiPolygon => {
multiPolygon.forEach((polygon) => {
const shape = new THREE.Shape();
for (let i = 0; i < polygon.length; i++) {
let [x, y] = projection(polygon[i]);
if (i === 0) {
shape.moveTo(x, -y);
}
shape.lineTo(x, -y);
}
const extrudeSettings = {
depth: 4,
bevelEnabled: true,
bevelSegments: 1,
bevelThickness: 0.2
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
// 平面部分材质
const material = new THREE.MeshStandardMaterial( {
metalness: 1,
color: color,
} );
// 拉高部分材质
const material1 = new THREE.MeshStandardMaterial( {
metalness: 1,
roughness: 1,
color: color,
} );
const mesh = new THREE.Mesh(geometry, [
material,
material1
]);
// 设置高度将省区分开来
if (index % 2 === 0) {
mesh.scale.set(1, 1, 1.2);
}
// 给mesh开启阴影
mesh.castShadow = true
mesh.receiveShadow = true
mesh._color = color
province.add(mesh);
})
})
_this.map.add(province);
})
}
geoJson的坐标需要进行墨卡托投影转换才能转换成平面坐标,这里需要用到d3
// 墨卡托投影转换
const projection = d3.geoMercator().center([104.0, 37.5]).scale(80).translate([0, 0]);
2、增加光照
我们把各种光都打上,环境光,半球光,点光,平行光。以平行光为例,增加投影,调整投影分辨率,避免投影出现马赛克
const light = new THREE.DirectionalLight( 0xffffff, 0.5 );
light.position.set( 20, -50, 20 ); light.castShadow = true;
light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024; this.scene.add(light);
castShadow = true表示开启投影
3、增加阴影模糊
默认的阴影没有模糊效果,看起来像白炽灯照射的样子,没有柔和感。使用官方示例中的csm来增加阴影模糊
import { CSM } from 'three/examples/jsm/csm/CSM.js';
this.csm = new CSM( {
maxFar: params.far,
cascades: 4,
mode: params.mode,
parent: this.scene,
shadowMapSize: 1024,
lightDirection: new THREE.Vector3( params.lightX, params.lightY, params.lightZ ).normalize(),
camera: this.camera
} );
4、增加鼠标事件
在3d空间中,鼠标事件主要通过射线来获取鼠标所在位置,可以想象成鼠标放出一道射线,照射到的第一个物体就是鼠标所在位置。此时用的threejs的Raycaster,通过Raycaster给对应的省份增加鼠标移入高亮效果和省份民悬浮展示效果
this.raycaster = new THREE.Raycaster();
// 传入需要检测的对象 group,group下的所有对象都会被检测到,如果被射线照到,则intersects有值,表示鼠标当前在这些物体上
const intersects = this.raycaster.intersectObject( this.group, true );
// 代码太多就不贴了,见 GitHub源码
5、渲染
threejs的渲染一般调用原生的requestAnimationFrame,主要做的事就是调用renderer的render方法,当然因为我们做了阴影模糊处理,所以还有别的需要做的:
this.camera.updateMatrixWorld();
this.csm.update();
this.renderer.render(this.scene, this.camera);
6、动画效果
地图上如果有一些动画效果,可以使用TWEEN.js,github地址,比如地图标注的出现动画:
最后再奉上项目地址
本文转载于:
https://juejin.cn/post/7057808453263163422
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--可视化大屏-用threejs撸一个3d中国地图的更多相关文章
- 可视化大屏的终极解决方案居然这么简单,vue-autofit一行全搞定!
可视化大屏适配/自适应现状 可视化大屏的适配是一个老生常谈的话题了,现在其实不乏一些大佬开源的自适应插件.工具但是我为什么还要重复造轮子呢?因为目前市面上适配工具每一个都无法做到完美的效果,做出来的东 ...
- 使用DataV制作实时销售数据可视化大屏(实验篇)
课时1:背景介绍 任务说明 ABC是一家销售公司,其客户可以通过网站下单订购该公司经营范围内的商品,并使用信用卡.银行卡.转账等方式付费.付费成功后,ABC公司会根据客户地址依据就近原则选择自己的货仓 ...
- Qt编写数据可视化大屏界面电子看板系统
一.前言 目前大屏大数据可视化UI这块非常火,趁热也用Qt来实现一个,Qt这个一站式超大型GUI超市,没有什么他做不了的,大屏电子看板当然也不在话下,有了QSS和QPainter这两个无敌的工具组合, ...
- Qt编写数据可视化大屏界面电子看板13-基础版
一.前言 之前发布的Qt编写的可视化大屏电子看板系统,很多开发者比较感兴趣,也收到了很多反馈意见,纵观市面上的大屏系统,基本上都是B/S结构的web版本,需要在后台进行自定义配置模块,绑定数据源等,其 ...
- Qt编写数据可视化大屏界面电子看板12-数据库采集
一.前言 数据采集是整个数据可视化大屏界面电子看板系统核心功能,没有数据源,这仅仅是个玩具UI,没啥用,当然默认做了定时器模拟数据,产生随机数据,这个可以直接配置文件修改来选择采用何种数据采集方法,总 ...
- Qt编写数据可视化大屏界面电子看板11-自定义控件
一.前言 说到自定义控件,我是感觉特别熟悉的几个字,本人亲自原创的自定义控件超过110个,都是来自各个行业的具体应用真实需求,而不是凭空捏造的,当然有几个小控件也有点凑数的嫌疑,在编写整个数据可视化大 ...
- Qt编写数据可视化大屏界面电子看板9-曲线效果
一.前言 为了编写数据可视化大屏界面电子看板系统,为了能够兼容Qt4和嵌入式linux系统,尤其是那种主频很低的,但是老板又需要在这种硬件上(比如树莓派.香橙派.全志H3.imx6)展示这么华丽的界面 ...
- Qt编写数据可视化大屏界面电子看板8-调整间距
一.前言 在数据可视化大屏界面电子看板系统中,前期为了使用目标客户机,调整间距是必不可少的工作,QMainWindow中的QDockWidget,会默认生成布局和QSplitter调整宽高大小,鼠标移 ...
- Qt编写数据可视化大屏界面电子看板5-恢复布局
一.前言 恢复布局这个功能在整个数据可视化大屏界面电子看板系统中非常有用,很多时候不小心把现有布局拖动乱了,(当然如果不想布局被拖动改动,可以修改配置文件中的MoveEnable参数来控制,默认为真表 ...
- Qt编写数据可视化大屏界面电子看板4-布局另存
一.前言 布局另存是数据可视化大屏界面电子看板系统中的额外功能之一,主要用于有时候用户需要在现有布局上做个微调,然后直接将该布局另存为一个布局配置文件使用,可以省略重新新建布局重新来一次大的调整的工作 ...
随机推荐
- NVM Feature— Reservation(NVME 学习笔记五)
8.8 Reservations 预订 NVMe的reservation预订功能,用于让两个或多个主机能够协调配合的访问共享namespace.使用这些功能的协议和方式超出了本规格说明书的范围.对这些 ...
- mysql 8.0 配置文件my.cnf中文注解【转载】
########################################################################### ## my.cnf for MySQL 8.0. ...
- 【Unity3D】Transform组件
1 前言 每个游戏对象有且仅有一个 Transform 组件,Transform 组件保存了游戏对象的位置信息,用户可以通过操作 Transform 组件实现对游戏对象的平移.旋转.缩放等变换.每 ...
- Java操作EasyExcel实现导入导出入门
介绍 EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单.节省内存著称.EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从 ...
- 非常好用的VS Code插件
Auto-Collapse Explorer 如果希望在VS Code编辑器中打开文件的时候自动展开对应的目录结构,需要开启"Auto Reveal". 具体设置步骤: 1.打开设 ...
- .NET周刊【2月第3期 2024-02-25】
国内文章 4.1k Star!全面的C#/.NET/.NET Core学习.工作.面试指南 https://www.cnblogs.com/Can-daydayup/p/18027117 DotNet ...
- heapq.merge()高效合并有序序列
import heapq import random # 针对较大的数据集,采用heapq中的merge()方法 # merge()不是对整个合并后的序列排序,而是使用一个堆一次一个元素的生成一个新序 ...
- 现代 CSS 解决方案:accent-color 强调色
accent-color 是从 Chrome 93 开始被得到支持的一个不算太新属性.之前一直没有好好介绍一下这个属性.直到最近在给一些系统整体切换主题色的时候,更深入的了解了一下这个属性. 简单而言 ...
- 学会了Java 8 Lambda表达式,简单而实用
OneAPM 摘要:此篇文章主要介绍Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系OneAPM工程师编译整理. Java是一流的面向对象语言,除了 ...
- 第一百一十六篇: JavaScript理解对象
好家伙,本篇为<JS高级程序设计>第八章"对象.类与面向对象编程"学习笔记 1.关于对象 ECMA-262将对象定义为一组属性的无序集合.严格来说,这意味着对象就是 ...