iTowns / itowns

A Three.js-based framework written in Javascript/WebGL for visualizing 3D geospatial data
http://www.itowns-project.org
Other
1.07k stars 290 forks source link

[PROPOSAL] `PlanarLayer` : match terrain tiles with an actual TMS #2290

Open mgermerie opened 4 months ago

mgermerie commented 4 months ago

After reading #2240 and #2244, and discussing it with @Desplandis, we thought of an improvement on PlanarLayer. Here is what we found out.

Your Environment

Context

When creating a PlanarView, user has to specify an extent. This extent defines the view's terrain extent. It is used as the root level for terrain tiles subdivision, just like the root level of any given TMS. It is therefore subdivided into a quadtree according to the position of the camera. However, this quadtree does not correspond with any known and referenced TMS. This causes issues when trying to display data arranged in a given TMS (from a TMSSource or a WMTSSource). Indeed, the extent and zoom level of terrain tiles do not match those of the TMS tiles, as described in the picture bellow.

Présentation

When displaying data arranged in a TMS on a terrain, the zoom level of terrain tiles is used to fetch the corresponding data within the TMS. Therefore, on the image above, the red tile (which matches with the user specified extent at the PlanarView creation) will display data from the black tile (the matching level tile in data TMS). This gives the feeling that user specified extent is not accounted for, as stated in #2240.

These considerations make PlanarView incompatible with data arranged in a TMS (excepted obviously if the extent specified for the PlanarView is the exact same one as the one of the TMS root tile).

Proposal

The terrain subdivision of a PlanarView should follow a TMS, which could be parametrized by user. The extent parameter of a PlanarView constructor should only define what part of this TMS is actually displayed as terrain in the scene.

To do so, we thought of three implementation options :

Option 1 : Create the terrain as a sub-tree of the TMS quadtree

We could build terrain tiles according to a specific TMS. The root tile of the terrain would match the smallest TMS tile that contains the whole extent parametrized by user. This terrain root tile is illustrated in the first column of the table bellow, where n is the zoom level of the smallest TMS tile described earlier. The terrain root tile could then be subdivided normally, following the TMS. We could add some culling to this mechanism, to only display tiles that intersect the user specified extent, as illustrated in the last three columns of the table bellow.

TMS zoom level n
Terrain zoom level 0
TMS zoom level n + 1
Terrain zoom level 1
TMS zoom level n + 2
Terrain zoom level 2
mixed zoom levels
image1 image2 image3 image4

For this implementation, we would need to store the zoom level of the TMS tile matching terrain's root tile (n in the example above). It should then be added to the terrain zoom level to fetch the correct data within the TMS arranged dataset.

A downside of this solution is that the terrain displayed does not precisely match the extent specified by user.

Option 2 : Generate odd size terrain tiles from TMS

An other option would be to generate terrain tiles corresponding to the intersection of TMS tiles and the view's extent.

In this solution, we would two things :

Knowing which TMS tiles are visible and having the method described in the second point above, we would be able to generate terrain tiles both matching the TMS quadtree and contained within the view's extent. These resulting terrain tiles are illustrated in blue in the table bellow.

TMS zoom level 0 TMS zoom level 1 TMS zoom level 2 mixed zoom levels
image11 image12 image13 image14

This solution solves the downside of the first option, since we only display terrain and data that are within the extent specified by user. However, its major flaw is that we would get a lot of terrain tiles with unique shapes. This would limit the use of a single Geometry shared by all terrain tiles, and most likely alter performances.

Option 3 : Create the terrain that matches the entire TMS and clip it

A final solution we found out is to create a terrain whose subdivision is just a copy of the TMS subdivision. This is more or less what is already done in a GlobeView. The terrain root tile would copy the TMS root tile, and so on for each subdivided tiles.

To only display terrain and data within the view's extent, we could add two processes :

The terrain copies the entire TMS Culling : we only process tiles that intersect the extent Clipping of the remaining terrain to exclude areas outside the extent
image111 image112 image113

In this solution, all terrain tile can share the same Geometry, and only terrain and data within the view's extent are displayed. This makes it, in @Desplandis' and in my opinion, the best choice.

Open discussion

Maybe we missed an easier solution. If so, don't hesitate to add it in comments. Also, I found the subject difficult to describe with text so @Desplandis, don't hesitate to edit the comment if I forgot something :wink:

Desplandis commented 3 months ago

Woah, this is exhaustive and easy to understand, nice job! x)

jailln commented 3 months ago

Thanks for the detailed and clear explainations! I also like the third option for all the reasons you've already mentioned :)