《权力的游戏》3d地图-基于Mapbox customlayer

写在前面

最终季!!转自豆瓣,如侵权请联系... https://movie.douban.com/photos/photo/2549876231/

权力游戏最终季正在热播,本人为了追剧果断买了腾讯会员,跳广告。不过说真的权游的架空世界确实很使人着迷,广袤寒冷的北境,温暖富饶的多恩,面朝黑水湾的君临城。巧了么,前段时间正好看到一个 github项目 是权游的地理要素和 mbtile数据,是广大爱好者和官方协力贡献且维护的。做为热心观众,必须得添砖加瓦啊。html

因此才有了下面的<权力的游戏3d地图导览>,在线把玩地址git

screenshot

其实在几年前,我就借助Threejs 复现过谷歌一款精美的中土地图,那个app作得太精致了,开场动效、音效,都很“中土”,原汁原味的托尔金味道。其实技术也很简单,就是一个bufferPlane + texture图 + 高程图,根据高程图去修改bufferPlane 对应顶点的 z 值。在线地址github

概述技术过程

相似于上一篇 mapbox extrude 文章中描述的相似,咱们用到的数据就一张地表影像和一张高程图(权游的这个高程图是我本身先根据影像图波段运算以后ps 修正过的,具体过程有点意思) web

左边高程图+右边影像图

首先咱们利用 Threejs 创建一个和影像图宽高一致的bufferPlaneGeometry,而后拿到这个bufferPlane 的全部顶点,这时候咱们要经过一个canvas去读取高程图中对应像素的高度,从红波段读取高度,set 给bufferPlane 顶点的position.z,这就能够把平面设置为高低起伏的地形了(以下图)canvas

根据高程图设置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就俩,能够参考官方文档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...bash

最近更新

  • 根据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-…app

custom layer官方文档dom

Game_of_Thrones_Wiki 资源hin 丰富,包括地图影像函数

相关文章
相关标签/搜索