visgl / deck.gl

WebGL2 powered visualization framework
https://deck.gl
MIT License
12.18k stars 2.09k forks source link

Point-Cloud visual artifact #3367

Closed denholtz closed 5 years ago

denholtz commented 5 years ago

Description

I'm using a point-cloud layer as a heatmap, and I'm seeing some visual artifacts. They occur more frequently closer to the edge of the canvas. See screenshot below.

visual_artifacts

Repro Steps

I'm not sure how to provide steps to reproduce this as I'm visualizing data from a secured API, but I'll provide what I can.

`<DeckGL controller initialViewState={INITIAL_VIEW_STATE} layers= {[ new GeoJsonLayer({ id:"base-map", data:COUNTRIES, stroked: true, filled: true, lineWidthMinPixels: 1, opacity: 1, getLineDashArray:[3, 3], getLineColor: [0,0,0], getFillColor: [60,60,60] }), new PointCloudLayer({ id: 'point-cloud-layer', data: map.data, pickable: false, coordinateSystem: COORDINATE_SYSTEM.LNGLAT, sizeUnits:'meters', pointSize: 30000, getPosition: d => d[map.parameters.fields] ? [d.lon, d.lat] : [600,600], getColor, opacity: 1, }) ] }

`

Environment:

Logs

Nothing showing up in logs.

Pessimistress commented 5 years ago

So Mercator projection does not produce a uniform space: https://en.wikipedia.org/wiki/Mercator_projection#/media/File:Mercator_with_Tissot's_Indicatrices_of_Distortion.svg 1 meter is bigger at higher latitudes than near the equator (1 / Math.cos(latitude * Math.PI / 180)).

For better performance, deck.gl treats 1 meter as a constant anywhere inside the same viewport. This is usually sufficient when we are dealing with a city or a country. The assumption no longer works in your use case, where you are literally looking at the whole spectrum. Towards higher latitudes, gaps start to appear between your points, creating the visual artifact.

I'd leave it open for discussion whether we should add special treatment for additional precision at this zoom level. Meanwhile, you can try a few things:

import * as d3 from 'd3-geo';

const projection = d3.geoEqualEarth();

const layers = [new PointCloudLayer({
  id: 'points'
  data: map.data,
  coordinateSystem: COORDINATE_SYSTEM.IDENTITY,
  getPosition: d => projection([d.lon, d.lat]),
  ...
})];
denholtz commented 5 years ago

Thanks for the detailed response.

There's a heatmap layer in draft stage on the Deck.gl road map that would fit my use case very nicely, and possibly suffer less from the performative projection calculations. I'd love to see that in a future release. As far as additional precision at that zoom level for existing layers, I don't know how significant the loss of performance would be, so it's hard to judge if that would help. The screenshot above is ~ 1 million data points, and some of the other data sets I'm working with are higher spatial resolution so would potentially be much more.

tgorkin commented 5 years ago

An experimental version of the heatmap layer will be included in deck.gl 7.2. You can try out a pre-release version by pointing to a beta version of the published npm package: https://www.npmjs.com/package/deck.gl/v/7.2.0-beta.1

Docs here: https://github.com/uber/deck.gl/blob/master/docs/layers/heatmap-layer.md

denholtz commented 5 years ago

Very cool. Thanks!