《權力的遊戲》3d地圖-基於Mapbox customlayer

alex2wong發表於2019-05-02

寫在前面

最終季!!轉自豆瓣,如侵權請聯絡... https://movie.douban.com/photos/photo/2549876231/

權力遊戲最終季正在熱播,本人為了追劇果斷買了騰訊會員,跳廣告。不過說真的權遊的架空世界確實很令人著迷,廣袤寒冷的北境,溫暖富饒的多恩,面朝黑水灣的君臨城。巧了麼,前段時間正好看到一個 github專案 是權遊的地理要素和 mbtile資料,是廣大愛好者和官方合力貢獻且維護的。作為熱心觀眾,必須得添磚加瓦啊。

所以才有了下面的<權力的遊戲3d地圖導覽>,線上把玩地址

screenshot

其實在幾年前,我就藉助Threejs 復現過谷歌一款精美的中土地圖,那個app做得太精緻了,開場動效、音效,都很“中土”,原汁原味的托爾金味道。其實技術也很簡單,就是一個bufferPlane + texture圖 + 高程圖,根據高程圖去修改bufferPlane 對應頂點的 z 值。線上地址

概述技術過程

類似於上一篇 mapbox extrude 文章中描述的類似,我們用到的資料就一張地表影像和一張高程圖(權遊的這個高程圖是我自己先根據影像圖波段運算之後ps 修正過的,具體過程有點意思)

左邊高程圖+右邊影像圖

首先我們利用 Threejs 建立一個和影像圖寬高一致的bufferPlaneGeometry,然後拿到這個bufferPlane 的所有頂點,這時候我們要通過一個canvas去讀取高程圖中對應畫素的高度,從紅波段讀取高度,set 給bufferPlane 頂點的position.z,這就可以把平面設定為高低起伏的地形了(如下圖)

根據高程圖設定bufferPlane 的頂點高度

// 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;
        }
    }

複製程式碼

與 mapbox 整合

為了給三維地形加入文字標註以及興趣點 icon 等要素,我們直接把這個Threejs 圖層整合為 mapbox 的customlayer。customlayer是 mapbox 開放給webgl 開發者的一個重要介面,可以在原有的圖層列表中插入customlayer。 構造customlayer最重要的api就倆,可以參考官方文件

  • onAdd(map, gl),初始化 webgl
  • render(gl, matrix), 每一幀都會call 這個render函式,可以在這裡注入需要在 webgl 上下文中渲染的操作
// 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...

最近更新

  • 根據GOT wiki,在介面左上角增加了故事線皮膚
  • 增加了事件點的動畫效果
  • 各位想加故事線的同學,只要clone下來並增補timelines.js 就可以自動增加故事點。
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
    }
}
// ...
];
複製程式碼

參考資源

github.com/mapbox/GOT-…

custom layer官方文件

Game_of_Thrones_Wiki 資源hin 豐富,包括地圖影像

相關文章