geo-data / cesium-terrain-builder

A C++ library and associated command line tools designed to create terrain tiles for use in the Cesium JavaScript library
Other
718 stars 342 forks source link

Quantized-mesh output support #55

Closed ahuarte47 closed 6 years ago

ahuarte47 commented 6 years ago

Provides some new features:

Details: https://www.linkedin.com/pulse/fast-cesium-terrain-rendering-new-quantized-mesh-output-alvaro-huarte/

kvuorine commented 6 years ago

Seems very good so far during my tests, well done.

Performance of Cesium took a leap forward compared to heightmap terrain tiles.

There is one problem, when I tried to play with --mesh-qfactor option, ctb-tile segfaulted.

ahuarte47 commented 6 years ago

Thanks @kvuorine. About --mesh-qfactor error, may I have your settings or data to try fix it?

kvuorine commented 6 years ago

With commands below you can get some of the data I am working with, I tested that this dataset produces --mesh-qfactor error too

wget http://kartat.kapsi.fi/files/korkeusmalli/hila_2m/etrs-tm35fin-n2000/L4/L41/L4141E.tif http://kartat.kapsi.fi/files/korkeusmalli/hila_2m/etrs-tm35fin-n2000/L4/L41/L4141G.tif http://kartat.kapsi.fi/files/korkeusmalli/hila_2m/etrs-tm35fin-n2000/L4/L41/L4141F.tif http://kartat.kapsi.fi/files/korkeusmalli/hila_2m/etrs-tm35fin-n2000/L4/L41/L4141H.tif
gdalbuildvrt merged.vrt L4141?.tif
mkdir terrain
ctb-tile -o terrain -f Mesh -g 1.1 merged.vrt
ahuarte47 commented 6 years ago

ok, I'll review this as soon as possible

ahuarte47 commented 6 years ago

Hi @kvuorine, I have fixed this option. Thanks for your notice!

Rik79 commented 6 years ago

Hello @ahuarte47 ! I tried to use this code to generate quantized mesh for Cesium and it works very well. Thank you! :+1: :1st_place_medal:

I had only an issue when i tried to generate tiles from two different adjacent tiff images (from SRTM dataset) : on the seam between these tiles there is a "canyon", a crack. I am sure that the tiffs data are correct, they are perfectly adjacent.

I launched "ctb-tile" 2 times, each with a tile and on the seam this is the result...

do you have some advice? should be the two tiles concatenated before launch ctb-tile?

The result...

ahuarte47 commented 6 years ago

Hi, I think you need an unique MDT that covers all area in order to execute the ctb-tile only once. You could create a virtual raster with "gdalbuildvrt" to virtually create an unique source from many individual files.

You can see a previous comment to how to use or read about "gdalbuildvrt" tool:

gdalbuildvrt merged.vrt L4141?.tif
mkdir terrain
ctb-tile -o terrain -f Mesh -g 1.1 merged.vrt
Rik79 commented 6 years ago

Ok thank you very much, i will try this command! (Probably this is the solution, but i am asking the need of memory for the entire world tileset!)

Looking at the image is interesting to note that the first generated tileset on the right is "cutted", the second on the left is "seamed" to globe. Futhermore looking far where the tiles are loaded with minor zoom level the canyon appers to be larger. These can be clues to uderstand. I am wondering if "ctb-tile" has an option not to seam to the ground level the tileset border.

About the generation of the "layout.json" file, also this works very well, but again in my case with two tiles generated it is not very usefull. Could be interesting a tool that analize the directory tree and from this generate the layout.json.

All this things let me understand that my approach is not correct. :)

Rik79 commented 6 years ago

Ok, as not said. :)

"gdalbuildvrt" solves perfectly the problems, also the "layer.json" one. Thank you a lot! :)

ediebold commented 6 years ago

Is there a technical reason as to why the new "-l" option is separate from the actual terrain generation? For large datasets, generating the layer.json file still takes quite a while.

ahuarte47 commented 6 years ago

Hi @ediebold, there is none technical reason. But I thought it seems better two separate tasks, I can be wrong but it looks more versatile. You could create the layer.json of existing old terrain sets, or update only a specific level without overwriting an existing json file (You could have edited it with your own settings). If you update a level, only the limits of it are calculated.

kvuorine commented 6 years ago

How about creating layer.json if there is none when generating tiles, but update layer.json only with command line option selected?

I have been testing --mesh-qfactor option which now doesn't crash the program, but I don't quite get the purpose of this option because tileset size on disk doesn't seem to vary at all when testing different values. @ahuarte47 could you explain it a bit?

ahuarte47 commented 6 years ago

Thanks everybody for your advices, I will try to integrate the -l option as complementary to -f option, but it will require me to do many changes in the original base code, but indeed it seems more logic.

About --mesh-qfactor option, it is supposed larger values should mean minor amount of triangles with minor quality. As my little tutorial said, the process takes care of an input geometric error to safely merge each pair of triangles with its parent one if there is not a visible loss of quality. The factor multiplies the default error value, larger values should mean minor quality.

Did not you notice any change? You can set "wireframe" rendering mode in Cesium to compare between different factors

ahuarte47 commented 6 years ago

Hi @kvuorine, I changed the code, now CTB creates the layer.json if there is none when generating tiles. Thanks everybody!

kvuorine commented 6 years ago

@ahuarte47 Thanks for your support.

I did notice difference in terrain. I just thought simplified mesh would take less space on disk and be quicker to serve over net. I guess simple mesh still reduces rendering workload.

I tried to read your docs/tutorials earlier but that registration barrier was just too much for me.

epifanio commented 6 years ago

How to serve the generated tiles? @ahuarte47 I guess storing them on a simple apache directory is not an option, right? I tried to copy some tiles here temp-tiles (they are using the same files used by @kvuorine ) sand-castle example returns:

An error occurred in "CesiumTerrainProvider": An error occurred while accessing https://epinux.com/epinux_data/shared/data/terrain2/layer.json.
ahuarte47 commented 6 years ago

Set as URL the root directory: https://epinux.com/epinux_data/shared/data/terrain2/

without the json file.

ahuarte47 commented 6 years ago

Also, You have clone the missing level-0 folder from the other existing one (You can google about it, you will find this trick).

https://github.com/geo-data/cesium-terrain-builder/issues/1 or https://github.com/geo-data/cesium-terrain-builder/issues/2

UPDATE: You could read this, it notices some steps to take care (Search... "So I got 65 000 terrain tiles").

kvuorine commented 6 years ago

@epifanio , I also have following apache directives for the directory

AddType application/octet-stream terrain
AddEncoding gzip terrain

Not sure if quantized-mesh requires them, but I had problems serving heightmap tiles without those.

muratkendir commented 6 years ago

Hi, I finally rendered our first city-level quantized-mesh terrain with help of Alvaro's CTB. Thanks for all kind of useful information.

2018-03-20 10_55_52-cesium demo_sm

epifanio commented 6 years ago

Hi, I'm still having troubles with the missing tiles issue. I tried several time to debug the issue but I can't figure it uout ... I still have the missing 0.terrain isue. In my last attmpt I'm serving the tiles directly from the /root/Apps/ Cesium forlder using nodejs server.js this is exactly what I did:

mkdir Cesium
wget -O Cesium/Cesium-1.43.zip https://github.com/AnalyticalGraphicsInc/cesium/releases/download/1.43/Cesium-1.43.zip
cd Cesium
unzip Cesium-1.43.zip

On OSX, using safari as the browser, I got the following in the JS console:

[Log] An error occurred in "w": Failed to obtain terrain tile X: 0 Y: 0 Level: 0. (Cesium.js, line 477)
[Log] An error occurred in "w": Failed to obtain terrain tile X: 1 Y: 0 Level: 0. (Cesium.js, line 477)

Can you help me to understand what I'm missing/doing wrong?

ahuarte47 commented 6 years ago

I think you need the other root terrain tile: https://epinux.com/epinux_data/shared/data/terrain/0/1/0.terrain

You should have both: https://epinux.com/epinux_data/shared/data/terrain/0/0/0.terrain https://epinux.com/epinux_data/shared/data/terrain/0/1/0.terrain

epifanio commented 6 years ago

@ahuarte47 I moved the tiles inside the cesium app so to make them "available" to cesium without using apache (I thought it was a correct way to avoid apache .htaccess (which I also tried)). I do have my app running on 8000 same host at the moment. I'll try again with apache as well.

I made the tiles i'm using [zip -r tiles.zip Apps/tiles/] avaialble at tiles.zip

ahuarte47 commented 6 years ago

I don't have this "...Apps\tiles\0\0\1.terrain"

ahuarte47 commented 6 years ago

I load your terrain with this root folder: 0.zip

epifanio commented 6 years ago

I see, I manually added it thinking that's was a missing tiles , my several attempts to debug..

removing it this is the log I have:

in the html I point to the tiles directory (no apache):

    var terrainProvider = new Cesium.CesiumTerrainProvider({
      url: 'tiles/'
    });

Log:

[Log] An error occurred in "w": Failed to obtain terrain tile X: 0 Y: 0 Level: 0. (Cesium.js, line 477)
[Log] An error occurred in "w": Failed to obtain terrain tile X: 1 Y: 0 Level: 0. (Cesium.js, line 477)

Using apache dir I have a cross origin problem (I'm googling about it):

html code:

    var terrainProvider = new Cesium.CesiumTerrainProvider({
      url: 'https://epinux.com/epinux_data/shared/data/tiles/'
    });
    viewer.terrai

Log:

[Error] Origin http://epinux.com:8000 is not allowed by Access-Control-Allow-Origin.
[Error] Failed to load resource: Origin http://epinux.com:8000 is not allowed by Access-Control-Allow-Origin. (layer.json, line 0)
[Error] XMLHttpRequest cannot load https://epinux.com/epinux_data/shared/data/tiles/layer.json due to access control checks.
[Log] An error occurred in "w": An error occurred while accessing https://epinux.com/epinux_data/shared/data/tiles/layer.json. (Cesium.js, line 477)

I tried to change https://epinux.com:8000 with http://localhost:8000 but then the log says:

[Log] An error occurred in "w": An error occurred while accessing https://localhost/epinux_data/shared/data/tiles/layer.json. (Cesium.js, line 477)
[Error] Failed to load resource: An SSL error has occurred and a secure connection to the server cannot be made. (layer.json, line 0)

finally removing https and using http, the log is:

[Error] Failed to load resource: Could not connect to the server. (layer.json, line 0)

I can leave the process running if usual to debug

ahuarte47 commented 6 years ago

Sorry, these errors are related with Cesium deployment. I only can say a last try, edit your "web.config" in Cesium root folder adding this:

<httpProtocol>
  <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Headers" value="origin, x-requested-with, content-type" />
      <add name="Content-Encoding" value="gzip" />
  </customHeaders>
</httpProtocol>
epifanio commented 6 years ago

That's a bit frustrating, I started from scratch on my laptop (before was on a remote server) I can run Cesium with its own server.js or just storing the Cesium directory under the apache root dir. I can run all the examples. In having Cesium served via apache I do not have the control origin error (both "tiles" and "cesium app" are served by apache on localhost on my laptop) but the tiles are giving me the same error:

[Log] An error occurred in "w": Failed to obtain terrain tile X: 0 Y: 0 Level: 0. (Cesium.js, line 477)
[Log] An error occurred in "w": Failed to obtain terrain tile X: 1 Y: 0 Level: 0. (Cesium.js, line 477)

btw ... this log is not very useful.

the only thing left to try is to add the .htaccess inside the root /tiles/ directory. I'm gonna try with this .htaccess:

Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with,
content-type"

<IfModule mod_headers.c>
  <FilesMatch "\.(png|jpeg)$">
    SetEnvIf Origin ":" IS_CORS
    Header set Access-Control-Allow-Origin "*" env= IS_CORS
  </FilesMatch>
</IfModule>

AddType application/octet-stream terrain
AddEncoding gzip terrain
epifanio commented 6 years ago

no luck, actually trying to load the page with chrome instead of safari, the cesium widget doesn't load at all with a nice message:

screen shot 2018-03-23 at 3 46 27 pm

webgl works because the src examples (e.g.: HelloWorld) works fine.

I'm gonna write on the mailing list to seek help, I already bloated the whole thread here :) Huge thanks for the help!

ediebold commented 6 years ago

did something change here recently? I was able to build fine a week ago, but now I am encountering issues. I'm using GDAL 2.1.3

ahuarte47 commented 6 years ago

This change was done in parent branch.

ediebold commented 6 years ago

Huh, didn't realise the original repo was even still active. Okay, I'll go upgrade my GDAL

ahuarte47 commented 6 years ago

Hi @ediebold, I did a minor change, do you can build now?

ediebold commented 6 years ago

I upgraded my GDAL to 2.2.2 - but have hit a new issue (with and without that minor change, so definitely a 2.2 issue).

Compiler message is:

../src/libctb.so: undefined reference to `GDALCreateOverviewDataset(GDALDataset*, int, int)' collect2: error: ld returned 1 exit status tools/CMakeFiles/ctb-tile.dir/build.make:98: recipe for target 'tools/ctb-tile' failed make[2]: [tools/ctb-tile] Error 1 CMakeFiles/Makefile2:202: recipe for target 'tools/CMakeFiles/ctb-tile.dir/all' failed make[1]: [tools/CMakeFiles/ctb-tile.dir/all] Error 2 Makefile:127: recipe for target 'all' failed make: *** [all] Error 2

markerikson commented 6 years ago

Yeah, my understanding is that that method is no longer even being exported in GDAL 2.2. The signature was also changed, but it's not being exported, so you can't link to it. (This discussion should probably be moved over to #15 .)

ediebold commented 6 years ago

I am testing the quantized mesh output now- but just to confirm, do we still need to add any missing base tiles ourselves? Is this something we could make ctb-tile do automatically? This is really the only thing preventing the automatic hosting of ctb-tile output.

ediebold commented 6 years ago

Also, I've done some tests, and this branch works fantastic for me.

markerikson commented 6 years ago

Yeah, my initial tests with a couple different source terrain datasets show it seems to be working well.

I'm actually hoping to write up a blog post after I've had a chance to generate a complete dataset.

ediebold commented 6 years ago

Okay, I've found one problem.

It seems that the layer.json's available array isn't being filled out for all the layers. I am processing a dataset that goes down to zoom level 16. However, when viewed with the generated layer.json file, I can't get past zoom level 12. This is true for both quantized mesh and heightmap. When I build a heightmap tileset and delete the entire available entry from the json, I can see all the levels of detail.

Edit: I added the missing layer's availabiltiy to the json file manually, and it fixed the problem. Of my 17 zoom levels (0 included), only 13 had entries in the available list initially.

Edit 2: Just to confirm, running with the -l flag doesn't help.

ediebold commented 6 years ago

Okay, I've hit another issue. Not 100% sure this belongs here, but this place seems to be where problems get fixed.

I've made a VRT which is a combination of two SRTM 30m files, and a DEM we collected ourselves. I used gdalwarp and gdal_translate to make sure all three files had the same projection and band type.

Everything goes fine for the first 10 levels of depth (level 16 till 7), but then I get this error message:

ERROR 1: Integer overflow : nSrcXSize=22062, nSrcYSize=30960
ERROR 1: IReadBlock failed at X offset 0, Y offset 0
ERROR 1: GetBlockRef failed at X block offset 0, Y block offset 0
Error: Could not read heights from raster
ERROR 1: Integer overflow : nSrcXSize=22268, nSrcYSize=31465
ERROR 1: IReadBlock failed at X offset 0, Y offset 0
ERROR 1: GetBlockRef failed at X block offset 0, Y block offset 0
Error: Could not read heights from raster

This leaves me with no tiles at a zoom level lower than 7 (i.e. I have tiles from 16 to 7). The folder structure for zoom level 6 exists, but is empty. I know this is a VRT issue since the individual files all work fine

Edit: Interestingly, I made another VRT out of the files, but set the resolution to "lowest", rather than "highest", as it was before. This seems to prevent the issue, but obviously isn't a solution since I'm after the higher resolution of the other DEM. Setting the resolution to "average" also fixes the problem, but also isn't what I'm after.

Edit 2: Even though the process fails out early, it still produces a layer.json file. Everything seems fine, except for the available list, which is obviously missing the early zoom levels. Interestingly, it has the details for level 6, the level it is failing out on:

"available": [
    [  ]
   ,[  ]
   ,[  ]
   ,[  ]
   ,[  ]
   ,[  ]
   ,[ { "startX": 114, "startY": 29, "endX": 114, "endY": 29 } ]
   ,[ { "startX": 228, "startY": 59, "endX": 229, "endY": 60 } ]
   ,[ { "startX": 457, "startY": 118, "endX": 459, "endY": 120 } ]
   ,[ { "startX": 915, "startY": 236, "endX": 918, "endY": 241 } ]
   ,[ { "startX": 1831, "startY": 472, "endX": 1837, "endY": 483 } ]
   ,[ { "startX": 3663, "startY": 944, "endX": 3675, "endY": 967 } ]
   ,[ { "startX": 7327, "startY": 1888, "endX": 7350, "endY": 1934 } ]
  ]

Without being familiar with the code, this suggests to me that the issue is separate from the layers.json construction at least.

markerikson commented 6 years ago

@ediebold : the "Integer Overflow" issue appears to be the same thing as #28 and https://github.com/geo-data/cesium-terrain-builder/issues/37#issuecomment-252857173 .

Another option besides building multiple VRT levels may be using gdaladdo to add overviews for your dataset.

ediebold commented 6 years ago

I just came here to say I'd found the answer, but you beat me to it.

I've done the fix from #37 , but it's worth noting that doing so breaks the layer.json creation- since layer.json is only created if one doesn't already exist. To get around this, you need to re-call ctb-tile with the "-l" flag. Of course, at the moment, this still runs into my first issue - I don't get all the zoom levels in the layers.json file.

ahuarte47 commented 6 years ago

Both issues (Missing root tile for CesiumJS, and "Integer Overflow" error) are old known issues but not related with Quantized-mesh output.

I could fix some of them (first one looks easy to develop), but I have the doubt if it is better to create specific pull requests in order to do not mix features. Any thoughts?

kvuorine commented 6 years ago

@ahuarte47 I think that Missing root tile issue is not a bug in ctb-tile but Cesium should be fixed to handle this.

I see no sense in generating empty tiles for terrain or imagery.

I opened an issue https://github.com/AnalyticalGraphicsInc/cesium/issues/6301 for this while ago but closed it when I found that "missing" root tile was causing my problem with only half of the globe rendered when no terrain tile for the other half. I'm thinking of reopening it and explaining myself better.

Edit: Cesium already handles this for imagery tiles.

ediebold commented 6 years ago

@ahuarte47 - I agree about the scope of this pull request. However, this main repo has been effectively dead for years. Would it be better if we just began raising issues in your fork?

Also, what about the issue with layers.json? That would almost certainly be an issue for this pull request?

ahuarte47 commented 6 years ago

Hi @kvuorine

I think that Missing root tile issue is not a bug in ctb-tile but Cesium should be fixed to handle this.

I agree, but does it have sense add a new option to workaround this issue now?

I opened an issue AnalyticalGraphicsInc/cesium#6301 for this while ago but closed it when I found that "missing" root tile was causing my problem with only half of the globe rendered when no terrain tile for the other half. I'm thinking of reopening it and explaining myself better.

+1

ahuarte47 commented 6 years ago

Hi @ediebold

I agree about the scope of this pull request. However, this main repo has been effectively dead for years. Would it be better if we just began raising issues in your fork?

I am going to do my best, but I can not offer official support for this.

Also, what about the issue with layers.json? That would almost certainly be an issue for this pull request?

I think the best option is to do not create the layer.json if any error occurs and no all scales are specified when executing the tool. it seems congruent me.

ediebold commented 6 years ago

@ahuarte47

I think you misunderstood which issue I’m talking about. I meant this comment:

https://github.com/geo-data/cesium-terrain-builder/pull/55#comment-376384683

It seems that the layer.json’s availability list is required for quantized mesh terrains, so I can’t not include it. Based on the fact that only a few zoom levels are missing, I’m hoping it’s just a typo somewhere.

ahuarte47 commented 6 years ago

Sorry, I am going to try explain my point, only the json file will be created if -l option or all levels are specified (from 0 to....).

ctb-tile -s 16 -e 5 -p geodetic -f Terrain -o C:\folder raster.tif No create the json file although it does not exist.

ctb-tile -s 16 -e 0 -p geodetic -f Terrain -o C:\folder raster.tif Create the json file if it does not exist.

ctb-tile -l -s 16 -e 5 -p geodetic -f Terrain -o C:\folder raster.tif ctb-tile -l -s 16 -e 0 -p geodetic -f Terrain -o C:\folder raster.tif Always trying to create the json file.

-l option does not open any input raster file, only travels by all tiles to count them. You can always execute it with all levels.

If you get some "Integer Overflow" error, you would have to execute, by example:

ctb-tile -s 16 -e 7 -p geodetic -f Terrain -o C:\folder raster_05m_resolution.tif ctb-tile -s 6 -e 0 -p geodetic -f Terrain -o C:\folder raster_10m_resolution.tif ctb-tile -s 16 -e 0 -p geodetic -f Terrain -o C:\folder raster_5m_resolution.tif -l

Edit: In order to avoid confusion, I think it is better to create the json file only when -l option is specified. "Integer overflow" error will not create more corrupt json files. And also, this step will be more fast than previous versions because of it take advantage of available CPU/Threads. ok?

ahuarte47 commented 6 years ago

I added a new "cesium-friendly" option to force the creation of the missing root tile when the 0-level is included in the command settings. It copies the existing file to the missing location. If everybody think that is bad option, I rollback this commit.