基于Three.js制作一個(gè)3D中國(guó)地圖
不想看繁瑣步驟的,可以直接去github下載項(xiàng)目,如果可以順便來個(gè)star哈哈
本項(xiàng)目使用vue-cli創(chuàng)建,但不影響使用,主要繪制都已封裝成類
1.使用geoJson繪制3d地圖
1.1 創(chuàng)建場(chǎng)景相關(guān)
// 創(chuàng)建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;
// 根據(jù)自己的需要調(diào)整顏色模式
// 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);
// 場(chǎng)景
this.scene = new THREE.Scene();
this.scene.background = null
// 相機(jī) 透視相機(jī)
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 根據(jù)json繪制地圖
利用THREE.Shape繪制地圖的平面邊數(shù)據(jù),再用THREE.ExtrudeGeometry將一個(gè)面拉高成3d模型,3d餅圖同理也可以這么制作
let jsonData = require('./json/china.json')
this.initMap(jsonData);
// initMap 方法主要部分
initMap(chinaJson) {
/* ...省略
...
*/
chinaJson.features.forEach((elem, index) => {
// 定一個(gè)省份3D對(duì)象
const province = new THREE.Object3D();
// 每個(gè)的 坐標(biāo) 數(shù)組
const { coordinates } = elem.geometry;
const color = COLOR_ARR[index % COLOR_ARR.length]
// 循環(huán)坐標(biāo)數(shù)組
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);
// 平面部分材質(zhì)
const material = new THREE.MeshStandardMaterial( {
metalness: 1,
color: color,
} );
// 拉高部分材質(zhì)
const material1 = new THREE.MeshStandardMaterial( {
metalness: 1,
roughness: 1,
color: color,
} );
const mesh = new THREE.Mesh(geometry, [
material,
material1
]);
// 設(shè)置高度將省區(qū)分開來
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的坐標(biāo)需要進(jìn)行墨卡托投影轉(zhuǎn)換才能轉(zhuǎn)換成平面坐標(biāo),這里需要用到d3
// 墨卡托投影轉(zhuǎn)換 const projection = d3.geoMercator().center([104.0, 37.5]).scale(80).translate([0, 0]);
2.增加光照
我們把各種光都打上,環(huán)境光,半球光,點(diǎn)光,平行光。以平行光為例,增加投影,調(diào)整投影分辨率,避免投影出現(xiàn)馬賽克
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.增加陰影模糊
默認(rèn)的陰影沒有模糊效果,看起來像白熾燈照射的樣子,沒有柔和感。使用官方示例中的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.增加鼠標(biāo)事件
在3d空間中,鼠標(biāo)事件主要通過射線來獲取鼠標(biāo)所在位置,可以想象成鼠標(biāo)放出一道射線,照射到的第一個(gè)物體就是鼠標(biāo)所在位置。此時(shí)用的threejs的Raycaster,通過Raycaster給對(duì)應(yīng)的省份增加鼠標(biāo)移入高亮效果和省份民懸浮展示效果
this.raycaster = new THREE.Raycaster(); // 傳入需要檢測(cè)的對(duì)象 group,group下的所有對(duì)象都會(huì)被檢測(cè)到,如果被射線照到,則intersects有值,表示鼠標(biāo)當(dāng)前在這些物體上 const intersects = this.raycaster.intersectObject( this.group, true ); // 代碼太多就不貼了,見 GitHub源碼
5.渲染
threejs的渲染一般調(diào)用原生的requestAnimationFrame,主要做的事就是調(diào)用renderer的render方法,當(dāng)然因?yàn)槲覀冏隽岁幱澳:幚恚赃€有別的需要做的:
this.camera.updateMatrixWorld(); this.csm.update(); this.renderer.render(this.scene, this.camera);
6.動(dòng)畫效果
地圖上如果有一些動(dòng)畫效果,可以使用TWEEN.js,github地址,比如地圖標(biāo)注的出現(xiàn)動(dòng)畫:

最后再奉上項(xiàng)目地址
到此這篇關(guān)于基于Three.js制作一個(gè)3D中國(guó)地圖的文章就介紹到這了,更多相關(guān)Three.js 3D中國(guó)地圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用javascript實(shí)現(xiàn)在小方框中瀏覽大圖的代碼
用javascript實(shí)現(xiàn)在小方框中瀏覽大圖的代碼...2007-08-08
基于openlayers4實(shí)現(xiàn)點(diǎn)的擴(kuò)散效果
這篇文章主要為大家詳細(xì)介紹了基于openlayers4實(shí)現(xiàn)點(diǎn)的擴(kuò)散效果 ,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
JavaScript設(shè)計(jì)模式之策略模式實(shí)例
這篇文章主要介紹了JavaScript設(shè)計(jì)模式之策略模式實(shí)例,本文分析了Jquery源碼并給出了自己的實(shí)現(xiàn),需要的朋友可以參考下2014-10-10
js實(shí)現(xiàn)三張圖(文)片一起切換的banner焦點(diǎn)圖
這篇文章主要介紹了js實(shí)現(xiàn)三張圖(文)片一起切換的banner焦點(diǎn)圖,推薦給大家,有需要的小伙伴可以參考下。2015-08-08
對(duì)象特征檢測(cè)法判斷瀏覽器對(duì)javascript對(duì)象的支持
就是將需要檢測(cè)的方法/對(duì)象作為if語句的判斷條件,具體做法如下2009-07-07
JavaScript實(shí)現(xiàn)帶并發(fā)限制的異步調(diào)度器
這篇文章主要為大家詳細(xì)介紹了如何基于JS實(shí)現(xiàn)一個(gè)帶并發(fā)限制的異步調(diào)度器?Scheduler,保證同時(shí)運(yùn)行的任務(wù)最多有N個(gè),感興趣的小伙伴可以了解下2024-03-03
淺談JavaScript的push(),pop(),concat()方法
下面小編就為大家?guī)硪黄獪\談JavaScript的push(),pop(),concat()方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06
Js 利用正則表達(dá)式和replace函數(shù)獲取string中所有被匹配到的文本(推薦)
這篇文章主要介紹了Js 利用正則表達(dá)式和replace函數(shù)獲取string中所有被匹配到的文本,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-10-10
解決layui 三級(jí)聯(lián)動(dòng)下拉框更新時(shí)回顯的問題
今天小編就為大家分享一篇解決layui 三級(jí)聯(lián)動(dòng)下拉框更新時(shí)回顯的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09

