WebGL is funny – programming in very low level style in JavaScript. This sample plots 86T points using this technology. .

The code is very straightforward, the only thing is to how points are initially loaded and scaled (instead of reloading each time when map moves).

All points are initially transformed to tile size of 256 x 256 pixels at zoom level 0 and then re-scaled/re-shifted based on the current position of the map. drawingOnCanvas is called from L.CanvasOverlay each time map needs to be drawn (move, zoom)

function drawingOnCanvas(canvasOverlay, params) {
gl.clear(gl.COLOR_BUFFER_BIT);
// -- set base matrix to translate canvas pixel coordinates -> webgl coordinates
mapMatrix.set(pixelsToWebGLMatrix);
var bounds = leafletMap.getBounds();
var topLeft = new L.LatLng(bounds.getNorth(), bounds.getWest());
var offset = LatLongToPixelXY(topLeft.lat, topLeft.lng);
// -- Scale to current zoom
var scale = Math.pow(2, leafletMap.getZoom());
scaleMatrix(mapMatrix, scale, scale);
translateMatrix(mapMatrix, -offset.x, -offset.y);
// -- attach matrix value to 'mapMatrix' uniform in shader
gl.uniformMatrix4fv(u_matLoc, false, mapMatrix);
gl.drawArrays(gl.POINTS, 0, numPoints);
}

More information and insipiration I took from this site

To illustrate how variables are passed from JavaScript to shaders used in above example, here are two figures from the book- figure 5.7 on p. 149, and figure 5.3 on p.144.

This figure shows single buffer (interleaved)that is used fro both coordinates and size. In similar way single buffer is constructed in the example here:

var vertBuffer = gl.createBuffer();
var vertArray = new Float32Array(verts);
var fsize = vertArray.BYTES_PER_ELEMENT;
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertArray, gl.STATIC_DRAW);
gl.vertexAttribPointer(vertLoc, 2, gl.FLOAT, false,fsize*5,0);
gl.enableVertexAttribArray(vertLoc);
// -- offset for color buffer
gl.vertexAttribPointer(colorLoc, 3, gl.FLOAT, false, fsize*5, fsize*2);
gl.enableVertexAttribArray(colorLoc);

Thanks for this, it is really a great tutorial!
I am trying it out with very narrow points and it doesn’t work as expected, I assume because the calculations are done on the zoom 0 and there are rounding issues (the points appear aligned on a evenly spaced grid).
I wasn’t able to understand if there is a way to handle this. Is there a way to make the LatLongToPixelXY method work for the current zoomlevel?
Thanks

this is most likely rounding issue,
here is a sample of calculating initial point position at zoom 11, called _groundZoom, from where _groundWorldSize is calculated and passed to GLMath.* function to get pixels coordinates in that zoom level.

var _groundZoom = 11; // — reference zoom level where pixel coordinates are calculated
var _tileSize = 256;
var _groundZoomScale = Math.pow(2, _groundZoom);
var _groundWorldSize = _tileSize * _groundZoomScale;

//– from transform.js in mapbox-gl-js lat/lon absolute pixel coords convertion
GLMapMath.lngX = function(lon, worldSize) {
return (180 + lon) * (worldSize || this.worldSize) / 360;
};
//– from transform.js in mapbox-gl-js latitude to absolute y coord
GLMapMath.latY = function(lat, worldSize) {
var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360));
return (180 – y) * (worldSize || this.worldSize) / 360;
},

// — to get point for ‘groundWorldSize…
point = { x: GLMapMath.lngX(data.geometry.coordinates[0], _groundWorldSize), y: GLMapMath.latY(data.geometry.coordinates[1], _groundWorldSize) };

Hi, thanks for your reply. I am trying to do the proposed change. Since I couldn’t find a reference to GLMapMath I just took the methods you supplied. The result are huge x,y values outside the range. am I right that this needs to be applied in LatLongToPixelXY with the proper zoomlevel?

above functions will give you X,Y in pixel size at defined zoomlevel which gives very large number with deeper zooms. It might be problem (but I havn’t faced it so the problem might lie somewhere else).
it is hard to say where problem is without facing it, any sample /gist to showcase this ?

Hmmm, I think I understand what you mean, but thought the offset would take care of that. I went crazy trying (you will find many LatLongToPixelXY* methods :-) ). I uploaded my last tries in this share db folder. I didn’t create the gist because the json should be at least a bit datarich. I hope that is ok: https://www.dropbox.com/sh/z97iia6gldsgox4/AACWWxqmP0D7BKXa2F2eJ2yWa?dl=0

The dataset is a small zoom of a laserscan dataset, and you should be able to see trees on the terrain in greyscale.
As it is now, it should open up and visualize the dots as per your code and zooming in will produce the grid. I also tried to visualize squares instead of dots but also failed due to ignorance in webgl, so you will find some changes due to that. Thanks

Hello! I’ve also the grid problem on near Points. How can i usw your function with the zoom level. My pixel coordinates also huge and outside of the range. What can I do?

I’ve finally combine this blog (and it’s wonderful inspiration) into a lib here if interested: http://robertleeplummerjr.github.io/Leaflet.glify/ I’m excited now because we support both points and polygons.

Really cool. Very clever!

Thanks for this, it is really a great tutorial!

I am trying it out with very narrow points and it doesn’t work as expected, I assume because the calculations are done on the zoom 0 and there are rounding issues (the points appear aligned on a evenly spaced grid).

I wasn’t able to understand if there is a way to handle this. Is there a way to make the LatLongToPixelXY method work for the current zoomlevel?

Thanks

this is most likely rounding issue,

here is a sample of calculating initial point position at zoom 11, called _groundZoom, from where _groundWorldSize is calculated and passed to GLMath.* function to get pixels coordinates in that zoom level.

var _groundZoom = 11; // — reference zoom level where pixel coordinates are calculated

var _tileSize = 256;

var _groundZoomScale = Math.pow(2, _groundZoom);

var _groundWorldSize = _tileSize * _groundZoomScale;

//– from transform.js in mapbox-gl-js lat/lon absolute pixel coords convertion

GLMapMath.lngX = function(lon, worldSize) {

return (180 + lon) * (worldSize || this.worldSize) / 360;

};

//– from transform.js in mapbox-gl-js latitude to absolute y coord

GLMapMath.latY = function(lat, worldSize) {

var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360));

return (180 – y) * (worldSize || this.worldSize) / 360;

},

// — to get point for ‘groundWorldSize…

point = { x: GLMapMath.lngX(data.geometry.coordinates[0], _groundWorldSize), y: GLMapMath.latY(data.geometry.coordinates[1], _groundWorldSize) };

Hi, thanks for your reply. I am trying to do the proposed change. Since I couldn’t find a reference to GLMapMath I just took the methods you supplied. The result are huge x,y values outside the range. am I right that this needs to be applied in LatLongToPixelXY with the proper zoomlevel?

above functions will give you X,Y in pixel size at defined zoomlevel which gives very large number with deeper zooms. It might be problem (but I havn’t faced it so the problem might lie somewhere else).

it is hard to say where problem is without facing it, any sample /gist to showcase this ?

Hmmm, I think I understand what you mean, but thought the offset would take care of that. I went crazy trying (you will find many LatLongToPixelXY* methods :-) ). I uploaded my last tries in this share db folder. I didn’t create the gist because the json should be at least a bit datarich. I hope that is ok: https://www.dropbox.com/sh/z97iia6gldsgox4/AACWWxqmP0D7BKXa2F2eJ2yWa?dl=0

The dataset is a small zoom of a laserscan dataset, and you should be able to see trees on the terrain in greyscale.

As it is now, it should open up and visualize the dots as per your code and zooming in will produce the grid. I also tried to visualize squares instead of dots but also failed due to ignorance in webgl, so you will find some changes due to that. Thanks

Hello! I’ve also the grid problem on near Points. How can i usw your function with the zoom level. My pixel coordinates also huge and outside of the range. What can I do?

Hi,

I’m late at the party, but I managed to resolve this problem by emulating double precision on WebGL, and integrating this on Leaflet.

I created a demo file here :

https://faistos18.github.io/webGL_leaflet_precise_points

I will try to integrate it to a library if I have time for this.

nice ! thanks for letting us know !

I’ve finally combine this blog (and it’s wonderful inspiration) into a lib here if interested: http://robertleeplummerjr.github.io/Leaflet.glify/ I’m excited now because we support both points and polygons.

:) great job, Robert !

*fist bump*