World Scenery 3.0 coastlines

From FlightGear wiki
Jump to navigation Jump to search

World Scenery 3.0 uses a texture of landclass information, typically with 10-25m resolution. For coastlines in particular, this creates an obvious sharp edge with right angles.

WS3.0 coastline just using a 10m raster with no vector data, showing the coastline problem
WS3.0 coastline using OSM vector data. Note the artifacts where the data doesn't line up.
Current state-of-the-art coast rendering, using OSM data for both raster and coastline definition. Martinique


This page describes various techniques/experiments to find a better solution.

Current Rendering

The current "state of the art" is to is to create a second texture at much higher resolution and paint the coastline onto this. The fragment shader then mixes the standard resolution landclass and the much higher resolution coastline texture. This has the advantage of being able to mix the data together nicely.

We currently support both generating this higher resolution raster at scenery generation time and also at runtime. Both the generation of the texture and the shader are currently quite basic and would benefit from further development from anyone interested in this area.

The significant downside is the increased memory occupancy of the additional texture and the added complexity of the shader.

This still leaves an issue that the elevation mesh is completely regular, so where steep slopes meet the sea, the high water mark can be a half way up a slope! The shader creates cliffs and beaches instead of water depending on the steepness of the elevation mesh. We also force any vertex that is in the sea to 0 elevation.

OpenStreetMap or other vector coastline data

OpenStreetMap has line data for coastlines and water bodies. This is vector data, so can be rendered at higher apparent resolution than the landclass data. The gencoastline.py script in fgmeta/ws30 uses this to generate a series of lat/lon points that FlightGear can then use.

There is a problem where the OSM coastline (defined as the mean high water mark) doesn't exactly match the landclass raster due to projection discrepancies or simply because of state of the tide at the time that a satellite image was taken.

Ideally the coastline of the raster will match the OSM coastline as closely as possible, and perhaps overlap slightly.

To do this:

  1. Reclassify the Ocean as NODATA (0.0)
  1. Use the GDAL Fill nodata to fill out the edges for radius 10. You will now have a raster as if the sea level has dropped. Use one of the following
    • gdal_fillnodata.py -md 10 -b 1 -of GTiff <original_file> <new_file>
    • r.fill.stats using the mode as the statistical method
  2. Get a shapefile of the coastline from OSM. The simplest way is to download the WGS84 split polygons from here: https://osmdata.openstreetmap.de/data/land-polygons.html. You may wish to pre-process these to clip to the rough extents of your scenery to reduce the size of the file.
  1. Load the OSM shapefile and Use Clip raster by mask layer this will cut out the landmass much more accurately than before.
    • gdalwarp -overwrite -of GTiff -tr 0.00015600000000000002 -9.000000000000003e-05 -tap -cutline <vector.osm> -cl multipolygons <input> <output>
  2. Use the GDAL Fill nodata to fill out the edges for radius 1. This ensures that there is "land" underneath the shoreline itself.
    • gdal_fillnodata.py -md 1 -b 1 -of GTiff <input> <output>
  3. Use the standard Fill NoData cells to fill the NoData with the correct Ocean landclass.
    • gdal_calc.py -A <input> --NoDataValue=44 --calc="A" --outfile <output>


The genVPB.py script performs these steps.

Experiments

Direct model generation

Initial experiments using the same approach as roads (overlaying an additional tri-strip for the coastline) did not blend well with the underlying landclass mesh.

Scenery-time generation of detailed coastline raster

fgmeta/ws30/gencoastlineraster.py generates a raster file that can be loaded by FG at runtime. This is quite effective and leverages python raster packages. The downside is the additional disk space.

Thought Experiments

Nearest Neighbour Encoding

The landclass texture currently has unused channels. It would be possible to use one of those channels to encode information about the neighbouring texels. This could be used for mixing coastline fragments better. For example, encoding whether the 8 surrounding texels are water or land could be done in 8 bits, conveniently 256 different values. A separate texture could be conceived that defined a different shape of coastline for each of the 256 combinations, probably with some perturbations to avoid obvious repetition.