基于WebGL的方式使用OpenLayers
1. 引言
在绘制海量数据时,使用GPU进行绘制可有效减少CPU的负载,提升绘制时的速度在浏览器中,可以使用WebGL的方式与GPU交互
OpenLayers是一个常用的GIS相关的JavaScript前端库,支持Canvas和WebGL两种方式渲染地图,默认采用的是Canvas
OpenLayers 6支持不同的图层(Layer)使用不同的渲染方式,WebGL拥有更高的性能,更适合渲染大数据
本文这里结合官方示例,描述OpenLayers的WebGL渲染的使用方法
OpenLayers官网:OpenLayers - Welcome
OpenLayers的GitHub站点:openlayers/openlayers: OpenLayers (github.com)
OpenLayers API文档:OpenLayers v6.15.1 API - Index
2. 绘制Points
绘制大量点数据是最常规的需求,OpenLayers 在6.1.x的API文档中提出了使用WebGL直接绘制点图层的API:
然而,在之后的版本中(截至目前版本为6.15.1), ol.layer.WebGLPoints
这个API没有在API文档中显示,但是API还是存在的
OpenLayers的issue中显示,这个API还在测试中,没有正式发布:
OpenLayers的官方示例中多处使用这个API:
- Filtering features with WebGL (openlayers.org)
- WebGL points layer (openlayers.org)
- WebGL points layer (openlayers.org)
参考这几个示例,我们使用WebGL绘制点图层的核心代码如下:
map.addLayer(new ol.layer.WebGLPoints({ source: new ol.source.Vector({ url: 'https://openlayers.org/en/latest/examples/data/geojson/world-cities.geojson', format: new ol.format.GeoJSON(), wrapX: true, }), style: { symbol: { symbolType: 'circle', size: 8, color: 'rgb(255, 0, 0)', opacity: 0.2, }, } }));
WebGLPoints
图层需要矢量点数据源(Source)和绘制的样式(Style)
这里的样式区别于Canvas图层,是一个symbol
对象,主要指定绘制的类型、尺寸、颜色、透明度等
更具体的参数可以参考:
- WebGL points layer (openlayers.org)
- openlayers/WebGLPoints.js at main · openlayers/openlayers (github.com)
- openlayers/literal.js at main · openlayers/openlayers (github.com)
- Rendering points · HonKit (openlayers.org)
绘制WebGLPoints
图层的完整代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- openlayers cdn --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/css/ol.css" type="text/css"> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/build/ol.js"></script> <style> html, body { height: 100%; } body { margin: 0; padding: 0; } #map { height: 100%; } </style> </head> <body> <div id="map"></div> <script> var map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ], view: new ol.View({ center: ol.proj.fromLonLat([-119.644, 34.5158]), zoom: 2 }) }); // var vectorLayer = new ol.layer.Vector({ // source: new ol.source.Vector({ // url: 'https://openlayers.org/en/latest/examples/data/geojson/world-cities.geojson', // format: new ol.format.GeoJSON(), // wrapX: true, // }) // }); // map.addLayer(vectorLayer); map.addLayer(new ol.layer.WebGLPoints({ source: new ol.source.Vector({ url: 'https://openlayers.org/en/latest/examples/data/geojson/world-cities.geojson', format: new ol.format.GeoJSON(), wrapX: true, }), style: { symbol: { symbolType: 'circle', size: 8, color: 'rgb(255, 0, 0)', opacity: 0.2, }, } })); </script> </body> </html>
其中:
- 数据来源是OpenLayers示例数据
- 地图瓦片是来自OSM,使用Canvas绘制
- 注释部分的代码是使用Canvas绘制点图层,可以感受到使用WebGL的方式更流畅
最后,渲染的结果如下:
这个API毕竟还是在实验阶段,并且只是点图层,如果不满足需求,可以进行进一步定制重写
可以参考:
创建扩展的Layer类并使用WebGL Renderer进行重写createRenderer
方法
当然,上述这个博客的方法目前并不适用,现在的WebGL Renderer必须设置好着色器代码:
但是实现原理是基本一致,参考官方实现的ol.layer.WebGLPoints
:
其Render为WebGLPointsLayerRenderer
:
createRenderer() { return new WebGLPointsLayerRenderer(this, { vertexShader: this.parseResult_.builder.getSymbolVertexShader(), fragmentShader: this.parseResult_.builder.getSymbolFragmentShader(), hitVertexShader: !this.hitDetectionDisabled_ && this.parseResult_.builder.getSymbolVertexShader(true), hitFragmentShader: !this.hitDetectionDisabled_ && this.parseResult_.builder.getSymbolFragmentShader(true), uniforms: this.parseResult_.uniforms, attributes: this.parseResult_.attributes, }); }
2. 绘制Tiles
绘制大量的瓦片也是日常所需,OpenLayers提供了使用WebGL绘制Tile的API:
参考OpenLayers官方的几个示例:
- Layer Swipe (WebGL) (openlayers.org)
- WebGL Tile Layer Styles (openlayers.org)
- WebGL Tiles (openlayers.org)
- Sea Level (with WebGL) (openlayers.org)
参考这几个示例,我们使用WebGL绘制Tile图层的核心代码如下:
map.addLayer(new ol.layer.WebGLTile({ source: new ol.source.OSM() }));
可设置的参数主要有Style、Source、Opacity等,更多参数的设置请参考:
绘制WebGLTile
图层的完整代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- openlayers cdn --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/css/ol.css" type="text/css"> <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/build/ol.js"></script> <style> html, body { height: 100%; } body { margin: 0; padding: 0; } #map { height: 100%; } </style> </head> <body> <div id="map"></div> <script> var map = new ol.Map({ target: 'map', layers: [], view: new ol.View({ center: ol.proj.fromLonLat([-119.644, 34.5158]), zoom: 2 }) }); map.addLayer(new ol.layer.WebGLTile({ source: new ol.source.OSM() })); // map.addLayer(new ol.layer.WebGLTile({ // source: new ol.source.OSM() // })); // map.addLayer(new ol.layer.WebGLTile({ // source: new ol.source.OSM() // })); // map.addLayer(new ol.layer.WebGLTile({ // source: new ol.source.OSM() // })); // map.addLayer(new ol.layer.Tile({ // source: new ol.source.OSM() // })); // map.addLayer(new ol.layer.Tile({ // source: new ol.source.OSM() // })); // map.addLayer(new ol.layer.Tile({ // source: new ol.source.OSM() // })); // map.addLayer(new ol.layer.Tile({ // source: new ol.source.OSM() // })); </script> </body> </html>
其中:
- 地图瓦片来源于OSM
- 注释部分的代码是与Canvas绘制Tile图层(四个图层)对比,可以感受到使用WebGL的方式更流畅
最后,渲染的结果如下:
4. 参考资料
[2]OpenLayers v6.15.1 API - Index
[3]openlayers/openlayers: OpenLayers (github.com)
[4]Openlayers指南-WebGL - 简书 (jianshu.com)
[5]Rendering points · HonKit (openlayers.org)
[6]openlayers6实现webgl点图层渲染效果(附源码下载) - 知乎 (zhihu.com)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了