基于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)
[7]OpenLayers中切片图层TileLayer的渲染解析 - 简书 (jianshu.com)
[8]OpenLayers地图渲染机制解析 - 简书 (jianshu.com)
基于WebGL的方式使用OpenLayers的更多相关文章
- 基于WebGL的三维的物联网平台技术
参加工作三年了,从一个搞调试的民工进阶为程序员,收获还是有那么一点的.慢慢讲一些. 去年在网上发现了https://hightopo.com/cn-index.html图扑软件的基于WebGL的三维j ...
- Mybatis框架基于注解的方式,实对数据现增删改查
编写Mybatis代码,与spring不一样,不需要导入插件,只需导入架包即可: 在lib下 导入mybatis架包:mybatis-3.1.1.jarmysql驱动架包:mysql-connecto ...
- 转-springAOP基于XML配置文件方式
springAOP基于XML配置文件方式 时间 2014-03-28 20:11:12 CSDN博客 原文 http://blog.csdn.net/yantingmei/article/deta ...
- struts_20_对Action中所有方法、某一个方法进行输入校验(基于XML配置方式实现输入校验)
第01步:导包 第02步:配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app ...
- struts2视频学习笔记 22-23(基于XML配置方式实现对action的所有方法及部分方法进行校验)
课时22 基于XML配置方式实现对action的所有方法进行校验 使用基于XML配置方式实现输入校验时,Action也需要继承ActionSupport,并且提供校验文件,校验文件和action类 ...
- ASP.NET WEB API 如何使用基于Post的方式传递多个值(二)
前面我曾经写过一篇文章,是基于HttpContext的请求上下文中读取表单参数,其实还可以将其单独拆分出来. 基于Filter的方式 获取表单值:(核心代码) public void OnActi ...
- spring与hibernate整合配置基于Annotation注解方式管理实务
1.配置数据源 数据库连接基本信息存放到properties文件中,因此先加载properties文件 <!-- jdbc连接信息 --> <context:property-pla ...
- PixiJS - 基于 WebGL 的超快 HTML5 2D 渲染引擎
Pixi.js 是一个开源的HTML5 2D 渲染引擎,使用 WebGL 实现,不支持的浏览器会自动降低到 Canvas 实现.PixiJS 的目标是提供一个快速且轻量级的2D库,并能兼容所有设备.此 ...
- ssm整合(基于xml配置方式)
本文是基于xml配置的方式来整合SpringMVC.Spring和Mybatis(基于注解的方式会再写一篇文章),步骤如下: (1)首先自然是依赖包的配置文件 pom.xml <project ...
- eureka集群基于DNS配置方式
https://www.cnblogs.com/relinson/p/eureka_ha_use_dns.html 最近在研究spring cloud eureka集群配置的时候碰到问题:多台eu ...
随机推荐
- Semaphore信号量源码解析(基于jdk11)
目录 1.Semaphore信号量源码解析(基于jdk11) 1.1 Semaphore概述 1.2 Semaphore的原理 1.2.1 基本结构(jdk11) 1.2.2 可中断获取信号量 1.2 ...
- Curve 块存储应用实践 -- iSCSI
Curve 是云原生计算基金会 (CNCF) Sandbox 项目,是网易数帆发起开源的高性能.易运维.云原生的分布式存储系统. 为了让大家更容易使用以及了解 Curve,我们期望接下来通过系列应用实 ...
- java逻辑运算中 | | 和 | 的区别
本文主要阐明逻辑运算中 | |(短路或) 和 |(逻辑或) 的异同 | | 和 | 的相同之处: 只有二者都是假时,结果才为假,否则结果为true. | | 和 | 的不同之处在于: a | | b: ...
- Pytorch 基本操作
Pytorch 基础操作 主要是在读深度学习入门之PyTorch这本书记的笔记.强烈推荐这本书 1. 常用类numpy操作 torch.Tensor(numpy_tensor) torch.from_ ...
- cs231n__2. K-nearest Neighbors
CS231n 2 K-Nearest Neighbors note ---by Orangestar 1. codes: import numpy as np class NearestNeighbo ...
- JavaScript:操作符:空值合并运算符(??)
这是一个新增的运算符,它的功能是: 对于表达式1 ?? 表达式2,如果表达式1的结果是null或者undefined时,返回表达式b的结果:否则返回表达式a的结果: 它与赋值运算符结合使用,即??=, ...
- 10、比较Bigdecimal类型是否相等的方法
一.Bigdecimal.equals()详解: Bigdecimal的equals方法不仅仅比较值的大小是否相等,首先比较的是scale(scale是bigdecimal的保留小数点位数),也就是说 ...
- 控制台运行java
控制台执行java 新建java代码 新建一个记事本文件,将文件名改为HelloWorld.java,注意:后缀是.java. 若没有显示文件后缀,可以在资源管理器打开显示后缀,然后再次修改文件名,一 ...
- Redis缓存何以一枝独秀?——从百变应用场景与热门面试题中感受下Redis的核心特性与使用注意点
大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 作为<深入理解缓存原理与实战设计 ...
- 题解P4474 王者之剑
双倍经验 简要题意 给你一个 \(n\times m\) 的网格,数字在格子里,你需要取出一些格子,使得任意两个格子之间没有公共边,输出格子中的数字和的最大值. \(1 \le n,m \le 100 ...