《权力的游戏》3d地图-基于Mapbox customlayer
栏目: JavaScript · 发布时间: 5年前
内容简介:权力游戏最终季正在热播,本人为了追剧果断买了腾讯会员,跳广告。不过说真的权游的所以才有了下面的 3d 地形图层,在线把玩地址:其实在几年前,我就借助Threejs 复现过谷歌一款精美的中土地图,那个app做得太精致了,开场动效、音效,都很“中土”,原汁原味的托尔金味道。其实技术也很简单,就是一个bufferPlane + texture图 + 高程图,根据高程图去修改bufferPlane 对应顶点的 z 值。在线地址
权力游戏最终季正在热播,本人为了追剧果断买了腾讯会员,跳广告。不过说真的权游的 架空世界确实很令人着迷,广袤寒冷的北境,温暖富饶的多恩,面朝黑水湾的君临城 。巧了么,前段时间正好看到一个 github项目 是权游的地理要素和 mbtile数据,是广大爱好者和官方合力贡献且维护的。作为热心观众,必须得添砖加瓦啊。
所以才有了下面的 3d 地形图层,在线把玩地址:
其实在几年前,我就借助Threejs 复现过谷歌一款精美的中土地图,那个app做得太精致了,开场动效、音效,都很“中土”,原汁原味的托尔金味道。其实技术也很简单,就是一个bufferPlane + texture图 + 高程图,根据高程图去修改bufferPlane 对应顶点的 z 值。在线地址
概述技术过程
类似于上一篇 mapbox extrude 文章中描述的类似,我们用到的数据就一张地表影像和一张高程图(权游的这个高程图是我自己先根据影像图波段运算之后ps 修正过的,具体过程有点意思)
首先我们利用 Threejs 建立一个和影像图宽高一致的bufferPlaneGeometry,然后拿到这个bufferPlane 的所有顶点,这时候我们要通过一个canvas去读取高程图中对应像素的高度,从红波段读取高度,set 给bufferPlane 顶点的position.z,这就可以把平面设置为高低起伏的地形了(如下图)
// 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...
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 权力下放:万维网的下一个重要阶段
- Java 在「权力的游戏」里,能活到第几集?
- 追剧有险!黑客盯上《权力的游戏》第八季:各种勒索诈骗
- [译] 对权力说真话:CEO 萨蒂亚•纳德拉与微软的三两事
- 极益发布地图插件,用于背景地图与业务地图
- Java - 调用 echarts 提供的地图压缩方法压缩地图
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。