3D forests polygons

Working on the code for the web 3D topographic map in which the forest polygons will be populated with 3D trees (like Swiss topo with vegetation).
First version working as intended but noticed quite heavy load on PC computer resources while displaying/generating forests with 3d trees. 3D trees model used is in glb format, size 124kb, and is part of my ion asset as 3D tileset.

My question for a community would be: is there any advice or recommendations how to improve speed processing and displaying large amount of 3D forests, and Im talking about country size areas. Is there any way to generate 3D forests and then save it for later usage in real time … something like geowebcache or something.

Thanks for any comment/advice/recommendation
Davor

Many instances of the same model (with variations in position, orientation, and size) can be represented with the (legacy) I3DM tile format, or by using the EXT_mesh_gpu_instancing glTF extension. In terms of rendering performance: You should be able to easily render a few ten thousand instances smoothly with that.

There is a thread that describes some context, even with the exact example of trees to make forests, at From I3dm to EXT_mesh_gpu_instancing? - #10 by bertt . The underlying repository that contains some example data sets, including examples that use EXT_mesh_gpu_instancing, can be found at GitHub - bertt/cesium_3dtiles_samples

2 Likes

Thank you very much for the informations!

For a couple of days trying to use 3Dtileset instead of glb as source of 3D trees for the forest areas, but cant make it visible on globe/map.

Workflow:
//Load csv file with lat, lon,height of the trees positions inside forest polygon.
Longitude,Latitude,Height
14.541356,44.478599,43.32
14.544385,44.478860,50.01

*//Load the 3D Trees tileset from Cesium Ion*
async function load3DTreesTileset() {
  try {
    const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(2886489); 

    viewer.scene.primitives.add(tileset);
    console.log("3D Trees tileset loaded successfully!");

                       ... code...

***// Place trees at the specified positions***
async function placeTreesAtPositions(treePositions, tileset) {
  const pos = treePositions[0]; // Test only the first tree
  const cartesianPosition = Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat, pos.height);

  const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(cartesianPosition);
  const scaleMatrix = Cesium.Matrix4.fromUniformScale(5.0); // Apply scaling
  Cesium.Matrix4.multiply(modelMatrix, scaleMatrix, modelMatrix);

  const instanceTileset = new Cesium.Cesium3DTileset({
	url: tileset.url,
	modelMatrix: modelMatrix,
  });

  viewer.scene.primitives.add(instanceTileset);

  console.log(`Tree (test) placed at: Longitude: ${pos.lon}, Latitude: ${pos.lat}, Height: ${pos.height}`);
}

everything works without any errors, coordinates & heights are correct but cant get trees 3dTiles to become visible on map/globe…

Even test version with points instead of 3D tiles working fine:

// Place trees at the specified positions
async function placeTreesAtPositions(treePositions) {
  const terrainProvider = viewer.terrainProvider;

  for (const pos of treePositions) {
    const cartographic = Cesium.Cartographic.fromDegrees(pos.lon, pos.lat, pos.height);
    const cartesianPosition = Cesium.Cartesian3.fromRadians(
      cartographic.longitude,
      cartographic.latitude,
      cartographic.height
    );

    const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(cartesianPosition);

    // Add 
    point representation at the position
    viewer.entities.add({
      position: cartesianPosition,
      point: {
        pixelSize: 5,
        color: Cesium.Color.GREEN
      }
    });

    console.log(`Tree placed at: Longitude: ${pos.lon}, Latitude: ${pos.lat}, Height: ${pos.height}`);
  }
}

[

Something doing wrong, and any help would be much appreciated!

There are a few things that are not clear here. And I’m not sure whether I misunderstood the goal, or you misunderstood some parts of the approach.

The code snippets that you posted are not complete. But it looks like you are creating a tileset, and then, creating many other tilesets, with the same url (!), but different modelMatrix values (for the different tree positions). If this is correct, then it seems to be unrelated to the approach that involves EXT_mesh_gpu_instancing.

The intended workflow here seems to be that you have that GLB file, and want to display many instances of this GLB file, at the cartographic positions that are stored in that CSV file. The main part of this could be accomplished by creating a GLB file that uses EXT_mesh_gpu_instancing to create the instances. The information for the instances (i.e. their positions) have to be derived from the cartographic positions. This can be a bit tricky (due to some coordinate system conversions that may be necessary). But even when you have the positions of the instances, there are still different options for representing where on earth these instances should be displayed. This information could be contained in the glTF itself. Or it could be stored as the tile.transform of a tile in a tileset.

And right now, it is not even clear whether you want a tileset, or a single GLB file that contains everything.

However, I did a few experiments, and created a snippet (based on the 3d-tiles-tools) that shows a possible approach. It offers the functionality to read a GLB and a CSV file (in the format that you showed) and create a GLB with EXT_mesh_gpu_instancing that contains the corresponding instances. Until now, this is only an experiment. But the goal is to work towards a solution for Extend tileset creation function to assign multiple positions · Issue #130 · CesiumGS/3d-tiles-tools · GitHub and Consider convenience functions to create instanced models · Issue #84 · CesiumGS/3d-tiles-tools · GitHub that may cover the most common use-cases. And the use case that you described probably is a pretty common one.

A comment with the experiment and further information is at Consider convenience functions to create instanced models · Issue #84 · CesiumGS/3d-tiles-tools · GitHub

It was my fault, primary in understanding which approach would be the best for the project.
After some testing decided to proceed with EXT_mesh_gpu_instancing, but was unable to create working script for generating tileset.json + instanced.glb from input glb 3D tree model and csv file with trees locations…

Will try again in the future when all of this exit experimental phase and there will be more manuals/examples/how-to available

There is no specific timeline for this feature. But any feedback about what you’d like to see as part of the functionality of the 3d-tiles-tools (either here, or as a comment in the issue where this is tracked), or which step in your attempt of creating the instanced GLB from the CSV did not work, could be helpful.

1 Like