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

ENH: Removes elevation max zoom from exaggeration calculation for raster-dem sources #9789

Merged
merged 5 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions debug/hillshade.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
top: 10px;
right: 10px;
border-radius: 3px;
width: 120px;
width: 140px;
border: 1px solid rgba(0,0,0,0.4);
font-family: 'Open Sans', sans-serif;
}
Expand Down Expand Up @@ -76,7 +76,7 @@
map.addSource('mapbox-dem', {
"type": "raster-dem",
"url": "mapbox://mapbox.terrain-rgb",
"tileSize": 256
"tileSize": 256,
});
map.addLayer({
"id": "Mapbox data",
Expand Down Expand Up @@ -106,9 +106,25 @@
// where hillshading sits in the Mapbox Outdoors style
}, 'waterway-river-canal-shadow');

// Add variant of Hillshade that overzooms beyond zoom 7.
// Note: source tiles are 512, so the following only goes up to native zoom 7.
map.addSource('mapbox-dem-z8', {
"type": "raster-dem",
"url": "mapbox://mapbox.terrain-rgb",
"tileSize": 256,
"maxzoom": 8
});
map.addLayer({
"id": "Mapbox data to Z8",
"source": "mapbox-dem-z8",
"type": "hillshade",
"layout": {
"visibility": "none"
}
}, 'waterway-river-canal-shadow');
});

var toggleableLayerIds = ['Mapbox data', 'Terrarium data'];
var toggleableLayerIds = ['Mapbox data', 'Terrarium data', 'Mapbox data to Z8'];

for (var i = 0; i < toggleableLayerIds.length; i++) {
var id = toggleableLayerIds[i];
Expand Down
7 changes: 3 additions & 4 deletions src/render/draw_hillshade.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ function drawHillshade(painter: Painter, sourceCache: SourceCache, layer: Hillsh
if (painter.renderPass !== 'offscreen' && painter.renderPass !== 'translucent') return;

const context = painter.context;
const sourceMaxZoom = sourceCache.getSource().maxzoom;

const depthMode = painter.depthModeForSublayer(0, DepthMode.ReadOnly);
const colorMode = painter.colorModeForRenderPass();
Expand All @@ -31,7 +30,7 @@ function drawHillshade(painter: Painter, sourceCache: SourceCache, layer: Hillsh
for (const coord of coords) {
const tile = sourceCache.getTile(coord);
if (tile.needsHillshadePrepare && painter.renderPass === 'offscreen') {
prepareHillshade(painter, tile, layer, sourceMaxZoom, depthMode, StencilMode.disabled, colorMode);
prepareHillshade(painter, tile, layer, depthMode, StencilMode.disabled, colorMode);
} else if (painter.renderPass === 'translucent') {
renderHillshade(painter, tile, layer, depthMode, stencilModes[coord.overscaledZ], colorMode);
}
Expand Down Expand Up @@ -60,7 +59,7 @@ function renderHillshade(painter, tile, layer, depthMode, stencilMode, colorMode

// hillshade rendering is done in two steps. the prepare step first calculates the slope of the terrain in the x and y
// directions for each pixel, and saves those values to a framebuffer texture in the r and g channels.
function prepareHillshade(painter, tile, layer, sourceMaxZoom, depthMode, stencilMode, colorMode) {
function prepareHillshade(painter, tile, layer, depthMode, stencilMode, colorMode) {
const context = painter.context;
const gl = context.gl;
const dem = tile.dem;
Expand Down Expand Up @@ -99,7 +98,7 @@ function prepareHillshade(painter, tile, layer, sourceMaxZoom, depthMode, stenci

painter.useProgram('hillshadePrepare').draw(context, gl.TRIANGLES,
depthMode, stencilMode, colorMode, CullFaceMode.disabled,
hillshadeUniformPrepareValues(tile.tileID, dem, sourceMaxZoom),
hillshadeUniformPrepareValues(tile.tileID, dem),
layer.id, painter.rasterBoundsBuffer,
painter.quadTriangleIndexBuffer, painter.rasterBoundsSegments);

Expand Down
5 changes: 1 addition & 4 deletions src/render/program/hillshade_program.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export type HillshadePrepareUniformsType = {|
'u_image': Uniform1i,
'u_dimension': Uniform2f,
'u_zoom': Uniform1f,
'u_maxzoom': Uniform1f,
'u_unpack': Uniform4f
|};

Expand All @@ -55,7 +54,6 @@ const hillshadePrepareUniforms = (context: Context, locations: UniformLocations)
'u_image': new Uniform1i(context, locations.u_image),
'u_dimension': new Uniform2f(context, locations.u_dimension),
'u_zoom': new Uniform1f(context, locations.u_zoom),
'u_maxzoom': new Uniform1f(context, locations.u_maxzoom),
'u_unpack': new Uniform4f(context, locations.u_unpack)
});

Expand Down Expand Up @@ -86,7 +84,7 @@ const hillshadeUniformValues = (
};

const hillshadeUniformPrepareValues = (
tileID: OverscaledTileID, dem: DEMData, maxzoom: number
tileID: OverscaledTileID, dem: DEMData
): UniformValues<HillshadePrepareUniformsType> => {

const stride = dem.stride;
Expand All @@ -100,7 +98,6 @@ const hillshadeUniformPrepareValues = (
'u_image': 1,
'u_dimension': [stride, stride],
'u_zoom': tileID.overscaledZ,
'u_maxzoom': maxzoom,
'u_unpack': dem.getUnpackVector()
};
};
Expand Down
21 changes: 11 additions & 10 deletions src/shaders/hillshade_prepare.fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ uniform sampler2D u_image;
varying vec2 v_pos;
uniform vec2 u_dimension;
uniform float u_zoom;
uniform float u_maxzoom;
uniform vec4 u_unpack;

float getElevation(vec2 coord, float bias) {
Expand Down Expand Up @@ -44,23 +43,25 @@ void main() {
float h = getElevation(v_pos + vec2(0, epsilon.y), 0.0);
float i = getElevation(v_pos + vec2(epsilon.x, epsilon.y), 0.0);

// here we divide the x and y slopes by 8 * pixel size
// Here we divide the x and y slopes by 8 * pixel size
// where pixel size (aka meters/pixel) is:
// circumference of the world / (pixels per tile * number of tiles)
// which is equivalent to: 8 * 40075016.6855785 / (512 * pow(2, u_zoom))
// which can be reduced to: pow(2, 19.25619978527 - u_zoom)
// we want to vertically exaggerate the hillshading though, because otherwise
// it is barely noticeable at low zooms. to do this, we multiply this by some
// scale factor pow(2, (u_zoom - u_maxzoom) * a) where a is an arbitrary value
// Here we use a=0.3 which works out to the expression below. see
// nickidlugash's awesome breakdown for more info
// which can be reduced to: pow(2, 19.25619978527 - u_zoom).
// We want to vertically exaggerate the hillshading because otherwise
// it is barely noticeable at low zooms. To do this, we multiply this by
// a scale factor that is a function of zooms below 15, which is an arbitrary
// that corresponds to the max zoom level of Mapbox terrain-RGB tiles.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terrarium also matches this and goes up to 15 for max zoom.

// See nickidlugash's awesome breakdown for more info:
// https://github.com/mapbox/mapbox-gl-js/pull/5286#discussion_r148419556
float exaggeration = u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3;

float exaggerationFactor = u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3;
float exaggeration = u_zoom < 15.0 ? (u_zoom - 15.0) * exaggerationFactor : 0.0;

vec2 deriv = vec2(
(c + f + f + i) - (a + d + d + g),
(g + h + h + i) - (a + b + b + c)
) / pow(2.0, (u_zoom - u_maxzoom) * exaggeration + 19.2562 - u_zoom);
) / pow(2.0, exaggeration + (19.2562 - u_zoom));

gl_FragColor = clamp(vec4(
deriv.x / 2.0 + 0.5,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions test/integration/render-tests/hillshade-maxzoom/default/style.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"version": 8,
"metadata": {
"test": {
"height": 256,
"width": 256,
"description": "This test verifies that setting a lower maxzoom on the raster-dem source produces the same output as a higher maxzoom (hillshade-accent-color/default) when the map zoom level is lower than the maxzoom (i.e., maxzoom does not alter rendering at lower zooms)"
}
},
"center": [-113.26903, 35.9654],
"zoom": 11,
"sources": {
"source": {
"type": "raster-dem",
"tiles": [
"local://tiles/{z}-{x}-{y}.terrain.png"
],
"maxzoom": 12,
"tileSize": 256
}
},
"layers": [
{
"id": "background",
"type": "background",
"paint": {
"background-color": "white"
}
},
{
"id": "hillshade",
"type": "hillshade",
"source": "source"
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"version": 8,
"metadata": {
"test": {
"height": 256,
"width": 256,
"description": "This test verifies that setting a maximum zoom on the raster-dem source lower than the layer results in overzooming the source."
}
},
"center": [-113.26903, 35.9654],
"zoom": 13,
"sources": {
"source": {
"type": "raster-dem",
"tiles": [
"local://tiles/{z}-{x}-{y}.terrain.png"
],
"maxzoom": 12,
"tileSize": 256
}
},
"layers": [
{
"id": "background",
"type": "background",
"paint": {
"background-color": "white"
}
},
{
"id": "hillshade",
"type": "hillshade",
"source": "source"
}
]
}