權力遊戲最終季正在熱播,本人爲了追劇果斷買了騰訊會員,跳廣告。不過說真的權遊的架空世界確實很使人着迷,廣袤寒冷的北境,溫暖富饒的多恩,面朝黑水灣的君臨城。巧了麼,前段時間正好看到一個 github項目 是權遊的地理要素和 mbtile數據,是廣大愛好者和官方協力貢獻且維護的。做爲熱心觀衆,必須得添磚加瓦啊。html
因此纔有了下面的<權力的遊戲3d地圖導覽>,在線把玩地址:git
其實在幾年前,我就藉助Threejs 復現過谷歌一款精美的中土地圖,那個app作得太精緻了,開場動效、音效,都很「中土」,原汁原味的托爾金味道。其實技術也很簡單,就是一個bufferPlane + texture圖 + 高程圖,根據高程圖去修改bufferPlane 對應頂點的 z 值。在線地址github
相似於上一篇 mapbox extrude 文章中描述的相似,咱們用到的數據就一張地表影像和一張高程圖(權遊的這個高程圖是我本身先根據影像圖波段運算以後ps 修正過的,具體過程有點意思) web
首先咱們利用 Threejs 創建一個和影像圖寬高一致的bufferPlaneGeometry,而後拿到這個bufferPlane 的全部頂點,這時候咱們要經過一個canvas去讀取高程圖中對應像素的高度,從紅波段讀取高度,set 給bufferPlane 頂點的position.z,這就能夠把平面設置爲高低起伏的地形了(以下圖)canvas
// geometry is bufferPlaneGeometry in THREEJS
// position flatArray [x,y,z,x1,y1,z1...] in geometry
var flatArray = geometry.attributes.position.array;
var verticesCount = flatArray.length / 3.0;
console.warn('bufferGeom Vertices Array length: '+ verticesCount);
for ( var i = 0, j = 0; i < verticesCount; i ++, j += 3 ) {
if (data[i] === undefined) {
console.warn(`data[${i}] is undefined..`);
break;
} else {
// set each vertice z-depth value with height
flatArray[ j-1 ] = data[i] * extrusionRatio;
}
}
複製代碼
爲了給三維地形加入文字標註以及興趣點 icon 等要素,咱們直接把這個Threejs 圖層集成爲 mapbox 的customlayer。customlayer是 mapbox 開放給webgl 開發者的一個重要接口,能夠在原有的圖層列表中插入customlayer。 構造customlayer最重要的api就倆,能夠參考官方文檔api
// configuration of the custom layer for a 3D model per the CustomLayerInterface
var customLayer = {
id: '3d-terrain',
type: 'custom', // 指定是自定義圖層,否則就是 fill,symbol 等圖層.
renderingMode: '3d',
onAdd: function (map, gl) {
this.camera = new THREE.Camera();
this.scene = new THREE.Scene();
this.map = map;
// use the Mapbox GL JS map canvas for three.js
this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl // 用mapbox 的webgl做爲threejs 的上下文.
});
// 把Threejs 的scene,camera以及renderer 傳入自定義的terrainLoader中,以便add(bufferPlaneMesh)
this.terrainLoader = new TerrainLoader({
scene: this.scene,
camera: this.camera,
renderer: this.renderer
});
},
render: function (gl, matrix) {
// ..省略部分 如下是將mapbox的matrix 參數同步給threejs 實例
// sync mapbox matrix with THREE camera Matrix.
var m = new THREE.Matrix4().fromArray(matrix);
var l = new THREE.Matrix4().makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ)
.scale(new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale))
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
// sync mapbox matrix with THREE camera. 更新threejs camera的投影矩陣,從新渲染,再強制觸發下mapbox 的repaint,這樣動畫就能夠繼續進行了
this.camera.projectionMatrix.elements = matrix;
this.camera.projectionMatrix = m.multiply(l);
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
this.map.triggerRepaint();
}
}
// 把customlayer 加入label 之下,這樣文字標註就能夠浮在地形圖層之上
map.on('style.load', function () {
map.addLayer(customLayer, 'roads labels');
});
複製代碼
github項目地址 後續有空的話,會加上權力遊戲部分文檔和故事線動畫,這個比較有趣一點。歡迎繼續完善3d地形的範疇,必定得會photoshop...bash
var timelines = [{
"id": "1",
"title": "White Walkers Emerge",
"description": "已經數千年未見蹤影的異鬼在北境出現, 他們攻擊了守夜人軍團的一隊遊騎兵以及野人",
"location": 'Castle Black',
"camera": {
center: [18.853961295738596, 34.89038102283956],
zoom: 5.21,
pitch: 41,
bearing: 0
}
}
// ...
];
複製代碼