-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
symbol-clip: Render tests, debug page and distance matrix rework #11065
Conversation
…iplication function
…amic-filter/render-tests # Conflicts: # src/style-spec/expression/index.js # src/style-spec/feature_filter/index.js # src/style-spec/reference/v8.json # src/style/evaluation_parameters.js # src/symbol/placement.js # src/ui/map.js
…amic-filter/render-tests
} | ||
} | ||
return ['main']; | ||
})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
threw in this fix for the microbenchmarks as well.
Good work Arindam, I like the thorough tests! One nitpicky question: can you explain the decision to put the new tests in such deeply nested folders? Do you expect us to add inside of I like the increased organization, but it's also bugging me a bit that it's inconsistent with the other tests (Others seem to be nested two directories deep, these new ones are four or five). |
Co-authored-by: Aidan H <aidan.hendrickson@mapbox.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Things look good on a detailed level, but I did want to clarify my understanding of the precise definition(s) of distance with respect to clipping before giving it a final 👍
@@ -52,10 +54,11 @@ class EvaluationContext { | |||
} | |||
|
|||
distanceFromCamera() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is distanceFromCamera
a descriptive name? It seems like this is used to compute the distance from the view center/look at rather than the distance from the camera.
What catches my attention is that the difference seems to add a strong radial dependence to the cutoff. I don't immediately see the pros/cons of the strong radial dependence, as illustrated in the highlighted region below. Is this the main criteria people would use to clip based on distance? I'm not opposed to it and can imagine that some of the factors which made fog challenging may factor into the decision, but I'm at least weighing the mental overhead of another similar but slightly differently defined distance field. Are there reasons not to use a distance metric similar in definition to fog?
distance-to-center < -0.5
:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this is how the fog distance field shifts around with pitch (this isnt a problem for fog because we only use it at high pitch where it doesnt shift) The shift is because of the translation the camera when pitching.
At pitch 0:
At pitch 20:
At pitch 60:
At pitch 80:
Whereas this stays locked at the center.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what I used to generate the geojson for the above viz
function generateDistanceScales() {
const center = map.getCenter();
const bearing = map.getBearing();
const rings = 20;
const step = 0.1;
const matrix = glMatrix.mat4.invert([], map.transform.mercatorFogMatrix);
const circles = [];
for (let i = 1; i <= rings; i++) {
const radius = step * i;
for(let th = 0; th < 360; th+= 20) {
const p = [radius * Math.sin(th * Math.PI/180), radius * Math.cos(th * Math.PI/180), 0];
const coord = new mapboxgl.MercatorCoordinate(...glMatrix.vec3.transformMat4([], p, matrix)).toLngLat();
const f = turf.point([coord.lng, coord.lat]);
f.properties['distance'] = `${(radius - 0.5 / Math.tan(map.transform.fov * 0.5)).toFixed(2)}`;
circles.push(f);
}
}
return turf.featureCollection(circles);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arindam1993 What's the advantage of this staying locked at the center? The fog behavior seems closer to a distance from camera operation. Wouldn't that be more intuitive for users than the radial behavior from map center, particularly if it could be consistent with fog?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because unlike fog this isn't a high-pitch only
use-case, users can do whatever they want with the pitch
and set much lower thresholds too if they wish. So imo having a nice and fixed reference frame is better so that the clipping boundaries arent moving around as much when pitching in the range of (0-40) deg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've created a notebook here which illustrates fog units (which would be my vote to reuse as symbol-clip units as well): https://observablehq.com/d/50ec70cf44480b1d
The behavior at medium and high pitch seems preferable to me. The units make a little less sense at very low pitch, though the symbol-clip feature also makes a lot less sense to me at zero pitch as well. It would be straightforward to transition to viewport-fixed units (viewport size = 1.0) at zero pitch so that they would always make sense, but again, I'd want to be certain of the use case of symbol-clip at zero pitch before strongly suggesting that.
Also, regarding the fog elevation estimation, I'd imagine we could neglect elevation sampling for this distance metric when terrain is enabled, and similar issues like the units falling away to the horizon at high pitch in high-elevation terrain would be much, much, much less apparent than fog.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talked to Arindam. One downside of the above is that it adds additional dependence on pitch, which would be nice to avoid since it'll make symbols hide/show more often when pitching. We're currently trying out ground-fixed planar lines (no pitch-dependence).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still struggling to understand the difference between how these approaches will effect symbol filtering. Do we have an example that more closely reflects real-world use case of this feature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got the planar lines implemented and tests updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SnailBones the problem is the foreshortening of the far distances.
Sample case:
filter: [ '<', ['distance-from-center'], 0.5]
Here the value of 0.5 means that: Clip this symbol in the region beyond what would be the top of the screen at 0 pitch
But since the fog distance measures a 3d distance from the camera to the plane, the value of the distance at the same geographic location increases as pitch increases, which means that what wasn't being clipped at 0 pitch gets clipped at a higher pitch. You can see this in the GIF @rreusser posted, the first line corresponds to fog_distance=0.5, it starts of at the water at 0 pitch and then gets squished inwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Nice work. 👏 Presumably this will suffer from some of the same challenges as fog when terrain is active, but I assume it simply won't matter since it'll be so much harder to notice.
const posMatrix = this.calculatePosMatrix(unwrappedTileID, this.cameraWorldSize); | ||
mat4.multiply(posMatrix, this.centerDistanceMatrix, posMatrix); | ||
|
||
cache[fogTileMatrixKey] = new Float32Array(posMatrix); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been on my todo list for a while to switch these all to plain Arrays so that they'd be double precision with GL also still accepting them.
Thanks for all the feedback 🙇 , the switch the planar lines was a really good move! |
…rom-camera` expressions (#10795) * Setup plumbing for pitch and distance-from-camera expressions * Add symbol-clip with support for pitch and distance-from-camera expressions * hackily working pitch expression * distance clipping * Track clipped state in JointPlacement and JointOpacity, reflect clipping using notUsed state in debug buffers * Rename distance-from-camera to distance-from-center * symbol-clip: splitting filter expressions into dynamic and static parts (#10923) * symbol-clip: dynamic filter style spec changes (#10977) * symbol-clip: Render tests, debug page and distance matrix rework (#11065) * WIP dynamic filter splitting stage 1 * Add tests for isDynamicFilter * More test cases for isDynamicFilter * Existing static filters get passed through unmodified. * WIP extracting static filters * Working case -> any translation * More tests for case -> any conversion * Add support for match branches * WIP: V0 of adding collapsing of dynamic expressions to true * more test cases * tests and some more refactoring * remove temory inspection code from unit tests * Fix dynamic filter detection * Fix failing spec test * Units tests hopefully :green: now * Add test to cover for `null` in expressions * Address CR comments and reduce number of temporary allocations * remove gl-matrix as dependency of style-spec and inline a matrix multiplication function * Fix lint issues * Add better error messages for expression compilation failures * Ensure location parameter is passed down * Remove symbol-clip from the style-spec * Remove unused property-expression type * Move filterSpec to v8.json and replace symbol-clip with dynamic filter * Fix unit tests * Fix most flow errors * finally flow is happy * Add expression validation code * Add api-supported tests for validation * Fix some failing unit tests * Ensure layer._featureFIlter is updated on main thread as well * Ensure layerType is passed down to validation * Fix flow and linting * Fix unit tests * Pass 1 of addressing CR comments * Add basic placementTime metric * Move to using total placement time * Fix lint errors * simplify placement time tracking * Fix silent conflict in with SymbolInstanceStruct changes * try benchmarking with filter splitting algorithm removed * Fix versions microbenchmark page * Revert "try benchmarking with filter splitting algorithm removed" This reverts commit 865f354. * Simplify by calculating distance using tile coordinates of the symbol directly * Use new specific centerDistanceMatrix * Sign flipping for consistency * add new debug page with distance visualizer * First set of pure distance based render tests * Pitch thresholding tests * Fix lint errors * More tests * Add first batch of point symbol render tests * Increase threshold * Increase allowed threshold for the correct tests 🤦 * remove flaky collision debug boxes instead * Move geojson test data to be in separate files instead of inlined into styles * Update flaky render test expectation * Fix distanceMatrix comment Co-authored-by: Aidan H <aidan.hendrickson@mapbox.com> * Switch to linear scale and update line placement tests * Update point placement tests * Update test expectations * Fix lint error * Remove flaky collision boxes Co-authored-by: Aidan H <aidan.hendrickson@mapbox.com> * Remove frametime logging change * Ensure that feature deserialization happens only when needed * Fix matrixKey naming leftover from copying fogMatrix code Co-authored-by: Karim Naaji <karim.naaji@gmail.com> * Rename matrices as per CR comments * Default layerType inside filter validation function. * add `VectorTileFeature` deserialization cache * Switch to matrix-free distance calculation * Add cache in Transform * Precompute bearing vector * prescale by windowScaleFactor * Inline `getSymbolFeature` * Lazy filter compilation * Move distance matrix calculation out to the debug page Co-authored-by: Aidan H <aidan.hendrickson@mapbox.com> Co-authored-by: Karim Naaji <karim.naaji@gmail.com>
This PR adds a bunch of render tests testing out various different code paths, I've grouped them at the first level by the type of
symbol-placement
used, so there are two folderspoint
andline
.The tests in those folders use the same filter expression, but with different data
Point
features for the point placement andLineString
features for line placement.I also implemented a new set of
centerDistanceMatrices
inTransform
to account for the small differences we need between the fog and symbol distance matrices. These differences ared
calculation for any anchor pointp
ends up beingThis is because the matrix defines a co-ordinate system centered at the map center with +y pointing away and +x pointing to the right.
I also added a debug page that uses this matrix + turf to generate some geojson that draws out the distance scale as an overlay.