visgl / deck.gl

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

geojson rendering distorted on some Mac devices #4237

Closed Insane-neal closed 4 years ago

Insane-neal commented 4 years ago

Description

Some geojson objects are distorted on Mac devices

Repro Steps

I have tested on different computers and iPhone. On some devices, some objects were distorted heavily regardless the browser type. I tried Safari/Chrome/Firefox on these devices and all of them had problem. So I guess it is a precision error related to GPU.

image

image

map.zip

Environment (please complete the following information):

Pessimistress commented 4 years ago

Thanks for reporting. Looks like these devices are not reading the fp64 low part of the attributes correctly.

While we work on this, it's worth noting that there is still a limitation to the default precision that deck.gl provides. We use two 32-bit floats in the vertex shader to simulate a "double", which gets us roughly 23 * 2 = 46 bit of precision instead of the 52 bit from a real 64-bit float. On low-end GPUs, there is expected to be even more loss while doing arithmetic calculations with these numbers.

Your geometries are extremely small. At this scale, any precision issue on a low-end GPU becomes very prominent. For consistent results, I recommend pre-processing your geometries to use the LNGLAT_OFFSETS mode. Lnglat offsets can be much better presented by 32-bit floats. For reference, when the absolute values of the coordinates are smaller than 0.1 degrees, the max error is about 1e-8 degrees ~ 1mm. When the absolute values of the coordinates are around 170, like in your dataset, the max error is about 1.5e-5 ~ 1.5m.

function transformGeometry(geom, transformPoint) {
  if (Number.isFinite(geom[0])) {
    return transformPoint(geom);
  }
  return geom.map(p => transformGeometry(p, origin));
}

function processFeatures(features, transformPoint) {
  return features.map(feature => ({
    ...feature,
    geometry: {
      type: feature.geometry.type,
      coordinates: transformGeometry(feature.geometry.coordinates, transformPoint)
    }
  }));
}

// Usually the center of the bounding box
const coordinateOrigin = [116.3203, 39.8619];

new GeoJsonLayer({
  id: 'lnglat-offset',
  data: processFeatures(data.features, p => [p[0] - coordinateOrigin[0], p[1] - coordinateOrigin[1]],
  coordinateSystem: deck.COORDINATE_SYSTEM.LNGLAT_OFFSETS,
  coordinateOrigin,
  ...
})
Insane-neal commented 4 years ago

Thanks for the temporary solution and your explanation. It works as expected. Hope your can fix the errors on low-end machines and mobile devices. I will close this.

Pessimistress commented 4 years ago

@Insane-neal Can you try 8.1.0-alpha.3?

Insane-neal commented 4 years ago

@Pessimistress I'll try that now. Meanwhile, We found not only the geojson layer was distorted, but also the selection of it. On these devices, the selection of geojson objects by mouse clicking worked randomly. Was it caused by the same rounding error issue?

sebastibe commented 4 years ago

@Pessimistress We had a similar issue and 8.1.0-alpha.3 solved it. Thanks!

Insane-neal commented 4 years ago

@Pessimistress The 8.1.0-alpha.3 version solved our problem too. Thanks!

Pessimistress commented 4 years ago

The fix has been ported to 8.0.15.

sebastibe commented 1 year ago

@Pessimistress FYI. the problem re-appeared recently on Safari mobile with the release of iOS 17, even with the latest version of deck.gl and a recent iPhone.