Skip to content

Commit 65b38c3

Browse files
Merge pull request #211781 from stevemunk/SM-webgl-custom-layer
New article on how to add a WebGL layer to a map.
2 parents b7d48dd + ce8fb28 commit 65b38c3

File tree

5 files changed

+243
-0
lines changed

5 files changed

+243
-0
lines changed
5.77 MB
Loading
490 KB
Loading
297 KB
Loading

articles/azure-maps/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ items:
191191
href: map-add-image-layer.md
192192
- name: Add tile layers
193193
href: map-add-tile-layer.md
194+
- name: Add a WebGL layer
195+
href: webgl-custom-layer.md
194196
- name: Show traffic
195197
href: map-show-traffic.md
196198
- name: Cluster point data
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
---
2+
title: Add a custom WebGL layer to a map
3+
titleSuffix: Microsoft Azure Maps
4+
description: How to add a custom WebGL layer to a map using the Azure Maps Web SDK.
5+
author: stevemunk
6+
ms.author: v-munksteve
7+
ms.date: 09/23/2022
8+
ms.topic: how-to
9+
ms.service: azure-maps
10+
services: azure-maps
11+
---
12+
13+
# Add a custom WebGL layer to a map
14+
15+
The Azure Maps Web SDK supports creating custom layers
16+
using [WebGL][getting_started_with_webgl]. WebGL is based
17+
on [OpenGL ES][OpenGL ES] and enables rendering 2D and 3D
18+
graphics in web browsers.
19+
20+
Using WebGL, you can build high-performance interactive
21+
graphics that render in the browser in real-time that support
22+
scenarios like simulations, data visualization, animations and
23+
3D modeling.
24+
25+
Developers can access the WebGL context of the map during
26+
rendering and use custom WebGL layers to integrate with other
27+
libraries such as [three.js][threejs] and [deck.gl][deckgl]
28+
to provide enriched and interactive content on the map.
29+
30+
## Add a WebGL layer
31+
32+
Before you can add a WebGL layer to a map, you need to have an object
33+
that implements the `WebGLRenderer` interface. First, create a WebGL
34+
layer by providing an `id` and `renderer` object to the constructor,
35+
then add the layer to the map to have it rendered.
36+
37+
The following sample code demonstrates how to add a WebGL layer to a map:
38+
39+
```js
40+
var myRenderer = {
41+
/**
42+
* Either "2d" or "3d". Defaults to "2d".
43+
* - "3d" to use the depth buffer and share it with other layers
44+
* - "2d" to add a layer with no depth. If you need to use the depth buffer for a "2d"
45+
* layer you must use an offscreen framebuffer and the prerender method.
46+
*/
47+
renderingMode: "2d",
48+
49+
/**
50+
* Optional method called when the layer has been added to the Map.
51+
* This gives the layer a chance to initialize gl resources and register event listeners.
52+
* @param map The Map this custom layer was just added to.
53+
* @param gl The gl context for the map.
54+
*/
55+
onAdd: function (map, gl) {},
56+
57+
/**
58+
* Optional method called when the layer has been removed from the Map.
59+
* This gives the layer a chance to clean up gl resources and event listeners.
60+
* @param map The Map this custom layer was just added to.
61+
* @param gl The gl context for the map.
62+
*/
63+
onRemove: function (map, gl) {},
64+
65+
/**
66+
* Optional method called during a render frame to allow a layer to prepare resources
67+
* or render into a texture.
68+
*
69+
* The layer cannot make any assumptions about the current GL state and must bind a framebuffer before rendering.
70+
*
71+
* @param gl The map's gl context.
72+
* @param matrix The map's camera matrix.
73+
*/
74+
prerender: function (gl, matrix) {},
75+
76+
/**
77+
* Required. Called during a render frame allowing the layer to draw into the GL context.
78+
*
79+
* The layer can assume blending and depth state is set to allow the layer to
80+
* properly blend and clip other layers. The layer cannot make any other
81+
* assumptions about the current GL state.
82+
*
83+
* If the layer needs to render to a texture, it should implement the prerender
84+
* method to do this and only use the render method for drawing directly into the
85+
* main framebuffer.
86+
*
87+
* The blend function is set to gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA).
88+
* This expects colors to be provided in premultiplied alpha form where the r, g and b
89+
* values are already multiplied by the a value. If you are unable to provide colors in
90+
* premultiplied form you may want to change the blend function to
91+
* gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA).
92+
*
93+
* @param gl The map's gl context.
94+
* @param matrix The map's camera matrix.
95+
*/
96+
render: function (gl, matrix) {}
97+
};
98+
99+
//Add the layer to the map.
100+
map.layers.add(new atlas.layer.WebGLLayer("layerId", { renderer: myRenderer }));
101+
```
102+
103+
> [!NOTE]
104+
> The `WebGLLayer` class supports the `minZoom`, `maxZoom`, and `visible` layer options.
105+
106+
```js
107+
//Add the layer to the map with layer options.
108+
map.layers.add(new atlas.layer.WebGLLayer("layerId",
109+
{
110+
renderer: myRenderer,
111+
minZoom: 10,
112+
maxZoom: 22,
113+
visible: true
114+
}
115+
));
116+
```
117+
118+
This sample renders a triangle on the map using a WebGL layer.
119+
120+
<!-------------------- Insert example here ----------------------------------->
121+
122+
![A screenshot showing a triangle rendered on a map, using a WebGL layer.](./media/how-to-webgl-custom-layer/triangle.png)
123+
124+
The map's camera matrix is used to project spherical Mercator point to
125+
gl coordinates. Mercator point \[0, 0\] represents the top left corner
126+
of the Mercator world and \[1, 1\] represents the bottom right corner.
127+
When the `renderingMode` is `"3d"`, the z coordinate is conformal.
128+
A box with identical x, y, and z lengths in Mercator units would be
129+
rendered as a cube.
130+
131+
The `MercatorPoint` class has `fromPosition`, `fromPositions`, and
132+
`toFloat32Array` static methods that can be used to convert a geospatial
133+
Position to a Mercator point. Similarly the `toPosition` and `toPositions`
134+
methods can be used to project a Mercator point to a Position.
135+
136+
## Render a 3D model
137+
138+
Use a WebGL layer to render 3D models. The following example shows how
139+
to load a [glTF][glTF] file and render it on the map using [three.js][threejs].
140+
141+
You need to add the following script files.
142+
143+
```html
144+
<script src="https://unpkg.com/[email protected]/build/three.min.js"></script>
145+
146+
<script src="https://unpkg.com/[email protected]/examples/js/loaders/GLTFLoader.js"></script>
147+
```
148+
149+
This sample renders an animated 3D parrot on the map.
150+
151+
<!-------------------- Insert example here ----------------------------------->
152+
153+
![A screenshot showing an an animated 3D parrot on the map.](./media/how-to-webgl-custom-layer/3d-parrot.gif)
154+
155+
The `onAdd` function loads a `.glb` file into memory and instantiates
156+
three.js objects such as Camera, Scene, Light, and a `THREE.WebGLRenderer`.
157+
158+
The `render` function calculates the projection matrix of the camera
159+
and renders the model to the scene.
160+
161+
>[!TIP]
162+
>
163+
> - To have a continuous and smooth animation, you can trigger the repaint of
164+
a single frame by calling `map.triggerRepaint()` in the `render` function.
165+
> - To enable anti-aliasing simply set `antialias` to `true` as
166+
one of the style options while creating the map.
167+
168+
## Render a deck.gl layer
169+
170+
A WebGL layer can be used to render layers from the [deck.gl][deckgl]
171+
library. The following sample demonstrates the data visualization of
172+
people migration flow in the United States from county to county
173+
within a certain time range.
174+
175+
You need to add the following script file.
176+
177+
```html
178+
<script src="https://unpkg.com/[email protected]/dist.min.js"></script>
179+
```
180+
181+
Define a layer class that extends `atlas.layer.WebGLLayer`.
182+
183+
```js
184+
class DeckGLLayer extends atlas.layer.WebGLLayer {
185+
186+
constructor(options) {
187+
super(options.id);
188+
189+
//Create an instance of deck.gl layer
190+
this._mbLayer = new deck.MapboxLayer(options);
191+
192+
//Create a renderer
193+
const deckGLRenderer = {
194+
renderingMode: "3d",
195+
onAdd: (map, gl) => {
196+
this._mbLayer.onAdd?.(map["map"], gl);
197+
},
198+
onRemove: (map, gl) => {
199+
this._mbLayer.onRemove?.(map["map"], gl);
200+
},
201+
prerender: (gl, matrix) => {
202+
this._mbLayer.prerender?.(gl, matrix);
203+
},
204+
render: (gl, matrix) => {
205+
this._mbLayer.render(gl, matrix);
206+
}
207+
};
208+
this.setOptions({ renderer: deckGLRenderer });
209+
}
210+
}
211+
```
212+
213+
This sample renders an arc-layer from the [deck.gl][deckgl] library.
214+
215+
![A screenshot showing an arc-layer from the Deck G L library.](./media/how-to-webgl-custom-layer/arc-layer.png)
216+
217+
## Next steps
218+
219+
Learn more about the classes and methods used in this article:
220+
221+
> [!div class="nextstepaction"]
222+
> [WebGLLayer][WebGLLayer]
223+
224+
> [!div class="nextstepaction"]
225+
> [WebGLLayerOptions][WebGLLayerOptions]
226+
227+
> [!div class="nextstepaction"]
228+
> [WebGLRenderer interface][WebGLRenderer interface]
229+
230+
> [!div class="nextstepaction"]
231+
> [MercatorPoint][MercatorPoint]
232+
233+
[getting_started_with_webgl]: https://developer.mozilla.org/en-US/docs/web/api/webgl_api/tutorial/getting_started_with_webgl
234+
[threejs]: https://threejs.org/
235+
[deckgl]: https://deck.gl/
236+
[glTF]: https://www.khronos.org/gltf/
237+
[OpenGL ES]: https://www.khronos.org/opengles/
238+
[WebGLLayer]: /javascript/api/azure-maps-control/atlas.layer.webgllayer
239+
[WebGLLayerOptions]: /javascript/api/azure-maps-control/atlas.webgllayeroptions
240+
[WebGLRenderer interface]: /javascript/api/azure-maps-control/atlas.webglrenderer
241+
[MercatorPoint]: /javascript/api/azure-maps-control/atlas.data.mercatorpoint

0 commit comments

Comments
 (0)