threejs教程:绘制3D地图(广东省区划图)

一、效果展示:

二、开发准备

Three.js中文文档:Three.js中文网

Three.js文本渲染插件:Troika 3D Text - Troika JS

行政区划边界数据查询(阿里云数据可视化平台):DataV.GeoAtlas地理小工具系列

1. 在项目中添加 `threejs` 依赖

npm install three

2. 添加相关声明依赖,为Typescript项目提供类型提示和类型检查的支持

npm install @types/three -D

3. 添加 `troika-three-text` 依赖,本案例中用于绘制所有市名文字,如无需绘制文字可不用

npm install troika-three-text

4.  使用阿里云数据可视化平台的范围选择器工具查询你所需要的区划边界数据,点击右下角其他类型的蓝色下载图标下载JSON文件,并导入项目中。本案例以广东省为例, `@/src/assets/广东省.json`。

三、代码实现

1.  添加canvas组件和基础样式


<template><div><canvas id="three" /></div>
</template><style scoped>
#three {width: 100vw;height: 100vh;position: absolute;top: 0;left: 0;
}
</style>

2. 导入three,创建三维场景并设置背景颜色,案例中的蓝底即为此处设置的颜色。

import * as THREE from 'three';
import { onMounted } from 'vue';onMounted(() => {// 创建3D场景对象Sceneconst scene = new THREE.Scene();// 设置背景颜色scene.background = new THREE.Color("#a4cdff");
});

3. Threejs要把三维场景Scene渲染到web网页上需创建个虚拟相机

// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera(30,window.innerWidth / window.innerHeight,0.1,1000
);
// 设置相机在Three.js三维坐标系中的位置,此处修改z坐标为调整正面远近,值越小越近
camera.position.z = 200;

THREE.PerspectiveCamera构造函数的参数说明

4.  有了场景和相机后,关键还需要一个渲染器去生成影像

// 创建渲染器对象
const threeDemo = document.getElementById("three");
const renderer = new THREE.WebGLRenderer({ canvas: threeDemo, antialias: true });

5. 处理每一帧动画和分辨率问题

function resizeDevicePixel(renderer: THREE.WebGLRenderer) {const canvas = renderer.domElementconst width = window.innerWidthconst height = window.innerHeightconst devicePixelWidth = canvas.width / window.devicePixelRatioconst devicePixelHeight = canvas.height / window.devicePixelRatioconst needResize = devicePixelWidth !== width || devicePixelHeight !== heightif (needResize) {renderer.setSize(width, height, false)}return needResize
}// Three.js 需要一个动画循环函数,Three.js 的每一帧都会执行这个函数
function annimate() {renderer.render(scene, camera);requestAnimationFrame(annimate);// 矫正设备的物理像素分辨率与CSS像素分辨率的比值,解决模糊问题if(resizeDevicePixel(renderer)) {const canvas = renderer.domElement;camera.aspect = canvas.clientWidth / canvas.clientHeight;camera.updateProjectionMatrix();}
}
annimate();

6. 要让模型动起来还需添加轨道控制器

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
const controls = new OrbitControls(camera, renderer.domElement);
controls.update();

7.以上便完成了所有初始配置,开始进入正题,渲染3D广东省区划图

导入之前下载的广东省区划边界数据:

import GuangDong from './assets/广东省.json';

遍历所有城市边界数据生成对应板块模型 

let xy = [0, 0, 0, 0];
GuangDong.features.forEach((city, index) => {let boundingBox, x = 0, y = 0;// 遍历城市的所有块边界数据(城市可能包含陆和岛多个块组成)city.geometry.coordinates.forEach((coordinate, cindex) => {const data = coordinate[0];// 一组二维向量表示一个多边形轮廓坐标const pointsArr = data.map(e => new THREE.Vector2(e[0] * 10, e[1] * 10));// Shape表示一个平面多边形轮廓,参数是二维向量构成的数组pointsArrconst shape = new THREE.Shape(pointsArr);// 多边形shape轮廓作为ShapeGeometry参数,生成一个多边形几何体const geometry = new THREE.ExtrudeGeometry(shape, {depth: 2, // 这里设置形状的厚度bevelEnabled: false, // 是否开启倒角,默认关闭});// 计算几何体的中心点并居中geometry.computeBoundingBox();// 计算平面几何体的中心点const { min, max } = geometry.boundingBox;xy[2] = (min.x + max.x) / 2;xy[3] = (min.y + max.y) / 2;if (index === 0) { // 记录第一个几何体的位置,作为其他几何体的位置参考点xy[0] = xy[2];xy[1] = xy[3];}// 移动几何体以便中心点位于原点const center = new THREE.Vector3();geometry.boundingBox!.getCenter(center);geometry.translate(-center.x + (xy[2] - xy[0]), -center.y + (xy[3] - xy[1]), -1);// 记录每个城市核心板块的位置信息if (cindex === 0) {boundingBox = geometry.boundingBox;x = xy[2];y = xy[3];}let material = new THREE.MeshBasicMaterial({ color: "#fcf9f2" });let mesh = new THREE.Mesh(geometry, material);scene.add(mesh);// 从原始几何体中获取边缘几何体const edgesGeometry = new THREE.EdgesGeometry(geometry);// 创建一个具有宽度的线条材质(这里我们使用LineBasicMaterial并设置linewidth)const edgeMaterial = new THREE.LineBasicMaterial({color: 0xcccccc, // 白色边缘linewidth: 1, // 边缘宽度});// 创建线段对象来渲染边缘线条const edgeLines = new THREE.LineSegments(edgesGeometry, edgeMaterial);scene.add(edgeLines);});// 渲染市名const text = new Text();text.text = city.properties.name;text.fontSize = 1;text.color = 0x333333;text.geometry.computeBoundingBox();const textCenter = new THREE.Vector3();text.geometry.boundingBox.getCenter(textCenter);// 计算市中心位置const point = city.properties.centerconst { min: { x: minX, y: minY }, max: { x: maxX, y: maxY } } = boundingBox;const c1 = [(minX + maxX) / 2, (minY + maxY) / 2];const c2 = [(point[0] * 10 - x) + c1[0], (point[1] * 10 - y) + c1[1]];// 把市名文字绘制到市中心点text.position.set(c2[0] + 0.3, c2[1] + 0.3, 1.2);scene.add(text);// 在场景中创建圆环const ringGeometry = new THREE.RingGeometry(0.4, 0.3, 32);// 创建圆环的材质const ringMaterial = new THREE.MeshBasicMaterial({color: 0xff0000, side: THREE.DoubleSide});const ring = new THREE.Mesh(ringGeometry, ringMaterial);// 把圆环绘制到市中心点ring.position.set(c2[0]-0.2, c2[1]-0.2, 1.1);scene.add(ring);// 在场景中创建圆形const circleGeometry = new THREE.CircleGeometry(0.2, 32);// 创建圆形的材质const circleMaterial = new THREE.MeshBasicMaterial({color: 0xff0000});const circle = new THREE.Mesh(circleGeometry, circleMaterial);// 把圆形直接加到圆环的中心点ring.add(circle);
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/29534.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习300问】123、什么是GRU?GRU网络的基本结构是怎样的?

在之前的文章中&#xff0c;我们谈到了标准RNN所面临的诸多困境&#xff0c;你也可以理解为RNN的缺点。其中最让人苦恼的就是梯度消失问题&#xff0c;正是由于梯度消失问题的存在&#xff0c;导致RNN无法获得上下文的长期依赖信息。那么就没有办法解决了吗&#xff1f;非也&am…

Linux实现: 客户端(cli01)通过TCP(或UDP)连接到聊天服务器(serv)进行聊天?(伪代码版本)

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

Flutter 小技巧之面试题里有意思的异步问题

很久没更新小技巧系列了&#xff0c;本次简单介绍一下 Flutter 面试里我认为比较有意思的异步基础知识点。 首先我们简单看一段代码&#xff0c;如下代码所示&#xff0c;是一个循环定时器任务&#xff0c;这段代码里&#xff1a; testFunc 循环每 1 秒执行一次 asyncWorkasy…

C++ 60 之 虚析构和纯虚析构

#include <iostream> #include <string> #include <cstring> using namespace std;class Animal13{ public:Animal13(){cout << "Animal的默认构造函数" << endl;}virtual void speak(){cout << "动物叫" << en…

?? 与 || 在 JavaScript 中的微妙差别

起初&#xff0c;你可能会认为你可以随意替换任何你喜欢的人&#xff0c;对吗&#xff1f; 错误。他们并非你所想的那样。 我们必须一劳永逸地学习这个区别&#xff0c;以避免日后出现痛苦的错误。 这个差别是什么&#xff1f; 这是他们对待真值和假值的令人难以置信的对比。这…

C++ 61 之 函数模版

#include <iostream> #include <string> using namespace std;void swapInt(int &a,int &b){int temp a;a b;b temp; }void swapDou(double& a, double& b){double temp a;a b;b temp; }// T代表通用数据类型&#xff0c;紧接着后面的代码&a…

科技前沿:Web3技术驱动下的物联网创新

随着Web3技术的迅猛发展&#xff0c;物联网&#xff08;IoT&#xff09;作为连接和互操作性的关键&#xff0c;正迎来一场前所未有的革命。本文将深入探讨Web3技术如何驱动物联网的创新&#xff0c;以及这种创新如何重新定义我们对智能设备、数据安全和网络架构的理解。 1. Web…

PR软件视频抠图换背景

1 新建项目 2 新建序列 在项目的右下角有个图标&#xff0c;新建 序列 序列是视频的制作尺寸&#xff0c;根据自己的需要选择 3 新建颜色遮罩 在项目的右下角--新建颜色遮罩--选择黑色--确定 4 导入视频 把要导入视频的文件夹打开&#xff0c;把视频拖到 项目 里 把黑色遮罩拖…

56.SAP MII开发的一个系统响应错误 Error code: ICMETIMEOUT

问题 一个SAP MII开发的项目&#xff0c;最近新增了一个功能&#xff0c;查询数据源量比较大&#xff0c;逻辑有点复杂&#xff0c;大约7-8分钟。发布到生产系统后&#xff0c;发生响应错误&#xff0c;返回 Error code: ICMETIMEOUT <!-- Error code: ICMETIMEOUT -->\r…

Camunda 7.x 系列【68】实战篇之我的待办任务

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址:https://gitee.com/pearl-organization/camunda-study-demo 前后端基于若依:https://gitee.com/y_project/RuoYi-Vue 流程设计器基于RuoYi-flowable:https://gi…

智能网站管理系统

智能网站管理系统&#xff0c;即智能化的网站管理工具&#xff0c;是为了提高网站管理效率和简化操作流程而开发的一种软件系统。它集合了各种先进的技术和功能&#xff0c;为网站管理员提供了一套强大而可靠的解决方案。 智能网站管理系统的核心功能是网站内容管理。传统的网站…

shell命令(进程管理和用户管理)

一、进程处理相关命令 1、进程的概念 进程的概念主要有两点&#xff1a; 进程是一个实体。每一个进程都有它自己的地址空间&#xff0c;一般情况下&#xff0c;包括文本区域&#xff08; text region &#xff09;、数据区域&#xff08; data region &#xff09;和堆栈&am…

【STM32】使用标准库点亮LED

1.硬件设计 LED1的阴极接到了PC13引脚上&#xff0c;我们控制PC13引脚的电平输出状态&#xff0c;即可控制LED1的亮灭。 2.编程要点 使能GPIO端口时钟&#xff1b;初始化GPIO目标引脚为推挽输出模式&#xff1b;编写简单测试程序&#xff0c;控制GPIO引脚输出高、低电平。 查…

Tomcat Websocket应用实例研究

概述 本文介绍了如何根据Tomcat给出的websocket实例&#xff0c;通过对实例的学习&#xff0c;定制自己基于websocket的应用。 环境及版本&#xff1a; Ubuntu 22.04.4 LTSApache Tomcat/10.1.20openjdk 11.0.23 2024-04-16浏览器&#xff1a;Chrome 相关资源及链接 Class…

python连接数据库,相关数据处理

随机生成一千个数据插入large_db中 # 这是一个示例 Python 脚本。# 按 ShiftF10 执行或将其替换为您的代码。 # 按 双击 Shift 在所有地方搜索类、文件、工具窗口、操作和设置。 import pandas as pd from sqlalchemy import create_engine from faker import Faker# 初始化fa…

【价值主张画布】以产品思维,将自己打造成“爆款”

经营自己等于经营公司&#xff1a; 1.客户细分&#xff1a;我能帮助谁&#xff1f;谁是我们最重要的客户&#xff1f; 2. 客户关系&#xff1a;怎样和对方打交道&#xff1f;一次交付还是持续交付&#xff1f; 3.渠道通路&#xff1a;怎样宣传自己和服务&#xff1f; 4. 价值主…

Jmeter 性能测试步骤是什么?

性能测试是软件开发过程中非常重要的一环。它可以帮助我们评估软件系统在不同负载下的性能表现&#xff0c;找出系统中的性能瓶颈&#xff0c;并提供改进方案。而JMeter作为一款功能强大且广泛使用的性能测试工具&#xff0c;可以帮助我们实现这一目标。 下面&#xff0c;我将…

银河麒麟4.0.2安装带有opengl的Qt5.12.9

银河麒麟4.0.2下载地址&#xff1a;银河麒麟-银河麒麟(云桌面系统)-银河麒麟最新版下载v4.0.2-92下载站 VirtualBox:https://www.virtualbox.org/wiki/Downloads qt下载&#xff1a;Index of /archive/qt/5.12/5.12.9 1安装VirtualBox:网上教材比较多 1&#xff09;安装完后安…

干货 | 使用 Navicat BI 解锁数据的力量

商业智能&#xff08;BI&#xff09;是一种将数据转化为可执行洞察的实践&#xff0c;能够帮助业务领导者提升整体业绩。这个过程中最重要的一个阶段是数据探索和可视化阶段&#xff0c;它涉及通过报告将数据组织并转化为有意义的信息。为了让数据更易于理解&#xff0c;BI 专业…

DashText-进阶使用

前置知识 BM25简介 BM25算法&#xff08;Best Matching 25&#xff09;是一种广泛用于信息检索领域的排名函数&#xff0c;用于在给定查询&#xff08;Query&#xff09;时对一组文档&#xff08;Document&#xff09;进行评分和排序。BM25在计算Query和Document之间的相似度…