threejs生成3d地图

Three.js是一个使用webGL创建3d图形的JavaScript库。主要用于3d图形可视化。本篇文章以创建3d地图的例子,展示three.js的使用。
技术栈:vue3+three.js

使用threejs生成3d地图分为3步

  1. 获取地图数据
  2. 使用threejs创建地图形状
  3. 渲染创建的形状

获取地图数据

地图数据可以通过datav网站获取,获取的文件是一个json文件。

使用threejs创建地图形状

地图json数据中会有一个geomerey属性,这个属性用于描述地理形状,这个属性的值是一个多维数组,数组中每个元素都是一组经纬度坐标,但是threejs不能直接解析经纬度坐标所以需要把经纬度坐标转换为平面坐标。我们可以使用d3.js库把经纬度转换为平面坐标。

创建场景、相机、渲染器

创建场景、相机、渲染器之前,需要创建一个容器元素,用来承载three.js创建的场景

<template>
<div style="width:100%;height:100%" ref="container"></div>
</template>

接下来开始使用js创建场景、相机、渲染器

// 引入需要的库
import * as THREE from 'three'
import {onMounted} from 'vue'
import sichuanJson from '@/assets/map/sichuan.json?raw'
import * as D3 from 'd3'

const container = ref()
// 创建场景
 const scene = new THREE.Scene();
 // 创建渲染器
 const renderer = new THREE.WebGLRenderer({
    antialias: true,
  });
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 创建相机
   const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000);
  camera.position.set(-50,50,130);
  
  onMounted(()=>{
  // 把threejs渲染器创建的元素添加到容器元素中
    container.value!.appendChild(renderer.domElement);
  });
  // 渲染添加到场景中的物体
function render(){
	renderer.render(scene,camera);
	requestAnimationFrame(render);
}

场景、相机、渲染器目前创建完毕,接下来创建地图形状

根据geometry属性创建形状


// 声明一个函数用于创建地图形状
function createSichuanShape(){
	// 解析json数据
  const jsonData = JSON.parse(sichuanJson);
  // 创建一个分组,把地图中的多个图形放在一个组中,便于管理
  const sichuan = new THREE.Group();
  // 使用d3把经纬度转换成平面坐标
  const projection = D3.geoMercator().center([104.065735,30.659462])
  // 遍历json数据中的features
  jsonData.features.forEach((feature,i)=>{
  	// 获取feature中的geometry数据,方便引用
    const geometry = feature.geometry;
    const type = geometry.type;
    // 创建分组,把同一个市的形状放在一个分组,便于管理
    const city = new THREE.Group();
    if(type === 'MultiPolygon'){
    	// 遍历geometry中的数据
      geometry.coordinates.forEach((multipolygon)=>{
      	// 创建形状,用于展示地理形状
        const shape = new THREE.Shape()
        // 存储每个坐标,用于绘制边界线
        const arr = []
        multipolygon.forEach((polygon)=>{
          polygon.forEach((item,index) => {
          	// 使用d3转换坐标
             const [x,y]= projection.translate([0,0])(item);
             // 根据转换后的坐标绘制形状
            if(index === 0){
              shape.moveTo(x,y)
            }else {
              shape.lineTo(x,y)
            }
            arr.push(x,y,3)
          });
        })
        // 绘制边界线
        createLine(arr,city)
        // 创建 ExtrudeGeometry用于显示3d效果
        const extrudGeometry = new THREE.ExtrudeGeometry(shape,{
            depth:2 // 地图的厚度
          })
          // 创建材质,用于显示地图的外观
          const material = new THREE.MeshBasicMaterial({
            color:'#ffff33'
          });
          // 创建物体,用于显示地图
          const mesh = new THREE.Mesh(extrudGeometry,material)
          mesh.position.set(0,0,0)
          // 添加到分组
          city.add(mesh)
      })
    }
    // 添加到分组
    sichuan.add(city)
  })
  // 添加到场景
  scene.add(sichuan)
}
// 用于创建边界线
function createLine(points,container){
  const buffGeometry =  new THREE.BufferGeometry();
  buffGeometry.setAttribute('position',new THREE.BufferAttribute(new Float32Array(points),3))
  const lineMaterial = new THREE.LineBasicMaterial({
    color:0xff0000
  })
  const line = new THREE.Line(buffGeometry,lineMaterial)
  container.add(line)
}

通过上面的操作我们已经把3d地图绘制出来,效果图:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端御书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值