Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] "Cesium OSM Buildings" 3d tiles dataset not working with loaders.gl #3144

Open
tdurand opened this issue Oct 18, 2024 · 6 comments
Open
Labels
bug Something isn't working

Comments

@tdurand
Copy link

tdurand commented Oct 18, 2024

Loader

CesiumIonLoader (Tiles3DLoader)

Description

I am looking to display the OSM Buildings dataset from Cesium using deck.gl (and loaders.gl) (3D tiles data)

Unfortunately nothing displays (no buildings), after some investigation I found out that:

  • Loaders.gl requests properly the tileset.json , but do not go further down
  • The tileset load returns NaN for zoom value (which may be normal as it is a worldwide dataset, not localized somewhere)
  • Moving the map do not trigger any further fetch of tiles from this tileset

When trying to debug, it seems that loaders.gl is not working well with this tileset boundingVolume, and when it checks if it should go deeper just returns without getting down to the child tiles. (some more details here)

Thanks for having a look

Expected Behavior

I would expect OSM buildings to load like on this example of Cesium : https://sandcastle.cesium.com/?src=Cesium%20OSM%20Buildings.html&label=ion%20Assets

image

Steps to Reproduce

Minimal repro based on the loaders.gl example for 3D Tiles: https://github.com/tdurand/test-cesium-osmbuildings/blob/main/app.tsx

Deployed here: https://test-osmbuildings.vercel.app/

export default function App({
  mapStyle = "https://basemaps.cartocdn.com/gl/dark-matter-nolabels-gl-style/style.json",
  updateAttributions,
}: {
  mapStyle?: string;
  updateAttributions?: (attributions: any) => void;
}) {
  const [initialViewState, setInitialViewState] = useState(INITIAL_VIEW_STATE);

  const onTilesetLoad = (tileset: Tileset3D) => {
    // Recenter view to cover the new tileset
    console.log(tileset);
    const { zoom, cartographicCenter } = tileset;
    const [longitude, latitude] = cartographicCenter;

    console.log(longitude);
    console.log(latitude);
    console.log(zoom); // Zoom is NaN
    
    setInitialViewState({
      ...INITIAL_VIEW_STATE,
      longitude: cartographicCenter[0],
      latitude: cartographicCenter[1],
      zoom: zoom || 17,
    }); 
  };

  const tile3DLayer = new Tile3DLayer({
    id: "tile-3d-layer",
    data: "https://assets.ion.cesium.com/96188/tileset.json",
    loader: CesiumIonLoader,
    loadOptions: { "cesium-ion": { accessToken: ION_TOKEN } },
    onTilesetLoad,
  });

  return (
    <DeckGL
      layers={[tile3DLayer]}
      initialViewState={initialViewState}
      controller={true}
    >
      <Map reuseMaps mapStyle={mapStyle} />
    </DeckGL>
  );
}

Environment

  • Framework version: latest
  • Browser: Chrome / Firefox
  • Node: latest stable
  • OS: Windows

Logs

For reference, the root tileset.json content

{
    "asset": {
        "version": "1.0",
        "tilesetVersion": "57181480-e706-11ee-857d-e18e4a3674dc",
        "extras": {
            "ion": {
                "defaultStyle": {
                    "color": "Boolean(${feature['cesium#color']}) ? color(${feature['cesium#color']}) : color('#ffffff')"
                },
                "terrainId": 1,
                "georeferenced": true,
                "movable": false
            }
        }
    },
    "properties": {
        "elementType": {},
        "elementId": {},
        "cesium#color": {},
        "cesium#estimatedHeight": {
            "maximum": 1102,
            "minimum": -16
        },
        "building": {},
        "shop": {},
        "source": {},
        "name": {},
        "wheelchair": {},
        "access": {}
    },
    "extensionsUsed": [
        "3DTILES_batch_table_hierarchy"
    ],
    "geometricError": 154134.67955991725,
    "root": {
        "geometricError": 77067.33977995862,
        "boundingVolume": {
            "region": [
                -3.1415925942485985,
                -1.4599681618940228,
                3.141545370875028,
                1.4502639200680947,
                -385.0565011513918,
                5967.300616082603
            ]
        },
        "content": {
            "uri": "root.b3dm"
        },
        "children": [
            {
                "geometricError": 77067.33977995862,
                "boundingVolume": {
                    "region": [
                        -3.1415925942485985,
                        -1.4599681618940228,
                        0.00003951949025290761,
                        1.4502639200680947,
                        -165.10238794752343,
                        5915.2067650589615
                    ]
                },
                "content": {
                    "uri": "0-0-0.json"
                }
            },
            {
                "geometricError": 77067.33977995862,
                "boundingVolume": {
                    "region": [
                        -0.00003125012025695847,
                        -1.4035456116211558,
                        3.141545370875028,
                        1.4277331959733954,
                        -385.0565011513918,
                        5967.300616082603
                    ]
                },
                "content": {
                    "uri": "0-1-0.json"
                }
            }
        ],
        "refine": "ADD"
    }
}

No response

@tdurand tdurand added the bug Something isn't working label Oct 18, 2024
@sraimund
Copy link

Yes, it looks like that the cullingVolume.computeVisibilityWithPlaneMask() function needs to be further examined.

As a workaround, the visibility can be checked by simply calculating 2D intersections between tiles and view bounding box. The dataset is displayed when changing the following lines of tile-3d.ts in updateVisibility():

this._visibilityPlaneMask = this.visibility(frameState, parentVisibilityPlaneMask);
this._visible = this._visibilityPlaneMask !== CullingVolume.MASK_OUTSIDE;

to

const bounds = frameState.viewport.getBounds();
this._visible = !(this.boundingBox[0][0] > bounds[0] && this.boundingBox[0][1] > bounds[1]
    && this.boundingBox[1][0] < bounds[2] && this.boundingBox[1][1] < bounds[3]);

grafik

@tdurand
Copy link
Author

tdurand commented Dec 14, 2024

thanks for this pointer 🤙🤙, will have a look !

@sraimund
Copy link

The calculated bounding volume box from the 3D tiles region is incorrect, especially for large extents. The root tile of the OSM Buildings dataset covers nearly the global extent and the derived box is just a slice, thus no children will be loaded.

I've created a codepen for testing: https://codepen.io/sraimund/pen/ByBRWZY

Loaders.gl (createBoundingVolume({ region })):
deck

Cesium.js (OrientedBoundingBox.fromRectangle):
cesium

Cesium has fixed this issue exactly five years ago:
CesiumGS/cesium#8475

@ibgreen
Copy link
Collaborator

ibgreen commented Dec 21, 2024

@tdurand @sraimund Thanks for raising this and for the detailed root causing and codepen

Cesium has fixed this issue exactly five years ago: CesiumGS/cesium#8475

That makes some sense, as loaders.gl forked the Cesium code about 6 years ago, so we did miss some fixes.
It doesn't look too hard to apply these fixes, however in contrast to Cesium which is a more monolithic code base where everything can be edited in the same repository, the deck.gl ecosystem is designed as a more composable architecture, which means that Cesium 3D tiles code was separated between math.gl, loaders.gl and deck.gl repositories.

As far as I can tell, the big addition here is a new method to the oriented bounding box class, and once that is in place the remaining changes in loaders.gl will be quite small.

The place to contribute the new method would be here https://github.com/visgl/math.gl/blob/master/modules/culling/src/lib/bounding-volumes/oriented-bounding-box.ts

If someone puts up a PR, we will help with publishing a new version of math.gl

@sraimund
Copy link

For a start, I could port the code successfully to the built file 'bounding-volume.js': https://gist.github.com/sraimund/a638cf5a3eff3a75fa7f7c9bc3644128 Next, I will add TypeScript and split the code, and try to push it to math.gl.

@ibgreen
Copy link
Collaborator

ibgreen commented Jan 4, 2025

@sraimund math.gl changes landed and published in 4.2.0-alpha.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants