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

Fill extrusion querying with terrain #10293

Merged
merged 14 commits into from
Jan 21, 2021
Merged

Fill extrusion querying with terrain #10293

merged 14 commits into from
Jan 21, 2021

Conversation

arindam1993
Copy link
Contributor

@arindam1993 arindam1993 commented Jan 14, 2021

Fixes #10252
Fixes #10286

For now I'm abandoning the approach in #10266 and instead porting the existing centroid encoding technique used in the fill extrusion vertex shader to CPU, with some minor differences. The main one being I perform all DEM lookup calculations in image-pixel space instead of uv space.

In order to retrive the centroid for a feature, I lookup the centroid directly from the attribute buffer centroidVertexArray. In order to do this I added an additional bit of metadata to featureIndex, which now also tracks the offset into the layoutVertexArray for the given feature.

Demo:

Screen.Recording.2021-01-14.at.10.54.30.AM.mov

Known Bugs:

  • hardcoding of -5 for height of the base, when its 0 and terrain is enabled lets picking work below terrain.
  • occasional crashes and exceptions near tile boundaries because of lack of clamp-to-edge behaviour on CPU side.

Launch Checklist

  • briefly describe the changes in this PR
  • include before/after visuals or gifs if this PR includes visual changes
  • write tests for all new functionality
  • document any changes to public APIs
  • manually test the debug page
  • apply changelog label ('bug', 'feature', 'docs', etc) or use the label 'skip changelog'
  • add an entry inside this element for inclusion in the mapbox-gl-js changelog: <changelog>Fix querying of fill-extrusions when terrain is enabled.</changelog>

src/shaders/fill_extrusion.vertex.glsl Outdated Show resolved Hide resolved
}

function elevationFromUint16(n: number): number {
return n / 7.3;
Copy link
Member

Choose a reason for hiding this comment

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

Needs a comment and/or constant for where 7.3 comes from.

const heightOffset = getTerrainHeightOffset(x, y, zBase, zTop, demSampler, centroid, exaggeration, lat);

const base = toPoint(vec3.transformMat4([], [x, y, heightOffset.base], m));
const top = toPoint(vec3.transformMat4([], [x, y, heightOffset.top], m));
Copy link
Member

Choose a reason for hiding this comment

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

We can get rid of two array allocations per point here by doing in-place matrix transforms (vec3.transformMat4(base, base, m)).

const slope = [
Math.min(0.25, meterToDEM * 0.5 * diffSum[0] / offset[0]),
Math.min(0.25, meterToDEM * 0.5 * diffSum[1] / offset[1])
];
Copy link
Member

Choose a reason for hiding this comment

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

Nit: a lot of temporary array allocations here that get immediately discarded. Should we inline some of these and keep more separate x/y variables?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea thats a good call it will make it more readable too


function flatElevation(demSampler: DEMSampler, centroid: vec2, lat: number): number {
const pos = [Math.floor(centroid[0] / 8), Math.floor(centroid[1] / 8)];
const span = [10 * (centroid[0] - pos[0] * 8), 10 * (centroid[1] - pos[1] * 8)];
Copy link
Contributor

Choose a reason for hiding this comment

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

Where is this 10 coming from?
And why does pos need to be rounded to the nearest 8?

Copy link
Contributor

@astojilj astojilj left a comment

Choose a reason for hiding this comment

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

Works great, even when querying parts of buildings above horizon.

Few questions.

@@ -185,7 +185,9 @@ createStructArrayType('feature_index', createLayout([
// the source layer the feature appears in
{ type: 'Uint16', name: 'sourceLayerIndex' },
// the bucket the feature appears in
{ type: 'Uint16', name: 'bucketIndex' }
{ type: 'Uint16', name: 'bucketIndex' },
// Offsetinto bucket.layoutVertexArray the vertcies for this feature appear in
Copy link
Contributor

Choose a reason for hiding this comment

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

some typos

function getTerrainHeightOffset(x: number, y: number, zBase: number, zTop: number, demSampler: DEMSampler, centroid: vec2, exaggeration: number, lat: number): { base: number, top: number} {
const ele = exaggeration * demSampler.getElevationAt(x, y, true, true);
const flatRoof = centroid[0] !== 0;
const centroidElevation = flatRoof ? centroid[1] === 0 ? exaggeration * elevationFromUint16(centroid[0]) : exaggeration * flatElevation(demSampler, centroid, lat) : ele;
Copy link
Contributor

@astojilj astojilj Jan 19, 2021

Choose a reason for hiding this comment

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

no need to sample elevation when on border (centroid[1] === 0).

Edit: ignore this please, flat roof is not sampled in this case.

const pixels = new Uint8Array(this.data.buffer);
if (clampToEdge) {
Copy link
Contributor

Choose a reason for hiding this comment

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

When does it happen? Buildings that cross tile border have height encoded in centroid and there's no need to sample.

Copy link
Contributor

Choose a reason for hiding this comment

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

For slope calculation, samples could be outside.
Lower clamp bound might need to be -1 (padded [0..511] range mapped to [-1..512]).

Copy link
Contributor Author

@arindam1993 arindam1993 Jan 20, 2021

Choose a reason for hiding this comment

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

Yes it happens for the slop calculation, as well as when elevation is sampled for a given vertex in getTerrainHeightOffset and when the vertex is outside of tile boundaries.

I updated the clamp ranges to account for padding.

Copy link
Contributor

@astojilj astojilj left a comment

Choose a reason for hiding this comment

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

LGTM % comment about lower clamp bound.

Copy link
Contributor

@ansis ansis left a comment

Choose a reason for hiding this comment

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

Looks good to me

One small nit: making the 7.3 a named constant in both the js file and the shader might be a bit clearer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
4 participants