-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Add support for cameraForBounds
on globe projection
#12138
Conversation
These animations are awesome and really help to understand the idea behind the code! I have few questions as this is a really fascinating topic! I see that you're finding the best fit for the camera frustum using an AABB in camera's coordinate space that's been built by encapsulating the AABB transformed from the ecef space. Why do you think it's necessary step to construct an intermediate AABB in ecef space first? Right now result of the algorithm seems to vary as a function of longitude and latitude as the bounding box is aligned in ecef space and not in camera space (your interactive demo is really useful for spotting things like these!) Taking this route you could first try to transform corners of the lat&lng bounds into world space (aka pixel space) using the globe matrix and then building the AABB. This could help with the aforementioned issue as the up vector in world space is always pointing to same direction because camera actually moves on a flat plane in mercator coordinates. In other words intermediate AABBs built this way should always be aligned with the tangent plane at the centroid location (I think). A slightly modified approach I've been thinking about is to simplify the problem into fitting points inside a frustum. It should be a fairly simple problem as camera centroid, bearing & pitch are fixed and only distance to the ground is changing. Given a set of points (corners of the lat&lng region in this case) and camera frustum planes you could find the closest intersection point between any pair of frustum planes and points and use that distance to move the camera forward. |
Thanks for giving a look!
Yes that's a good point, it's worth investigating whether we could skip an extra space transformation in order to reduce the longitude/latitude dependency by doing it directly in world space as you suggest, I'll investigate that as it might might also result in a better fit overall.
I investigated this, but unless I missed something, finding the closest intersection of the frustum planes aligned with a set of points may not always result in the camera being aligned or looking at the centroid, which I think is an important property of |
bdf4e15
to
50b5c03
Compare
7349c6f
to
0b71553
Compare
6eb2518
to
1dc1903
Compare
- Account for aspect ratio - Adjust for aspect ratio contribution - Support for pitch - Support on mercator - Add debug page Cleanup Cleanup Update _cameraForBoxAndBearing with new technique Update _cameraForBoxAndBearing with new technique for globe Account for transition Account for option max zoom Cleanups Fix case when there is no sphere intersection
Apply center offset
6ee28b1
to
825bd2b
Compare
fbb80cd
to
825bd2b
Compare
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 didn't get through all the math logic in detail, but basically I think this needs a few more passes of simplification — the code is a bit too verbose / repetitive in places, and adds quite a bit of bundle size (+1.3KB gzipped!) for the feature. Pointed out some low hanging fruits but there should be more opportunities to cut down / simplify.
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 and works great! I have few minor questions in the comments
let zoom = getZoom(this.zoom); | ||
let diff = Math.abs(zoom - getZoom(zoom)); | ||
let lastdiff; | ||
while (lastdiff !== diff) { |
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 this guaranteed to converge in all cases? Could there be a risk of an infinite loop due to floating point comparison?
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 should converge in a few iterations, but as a safeguard it may be wise to add a max iteration count or an epsilon comparison, as it's difficult to confirm that floating point comparison will not break this. This method will not be necessary in gl-native, as adaptive scaling to get constant globe size isn't applied yet.
Co-authored-by: Volodymyr Agafonkin <agafonkin@gmail.com>
Thanks for the review and helpful simplification suggestions, I've addressed most of them and will add more tests for the corner case of requesting entries such as [-180, 0], [180, 0]. Regarding the concern of size:
it will level-out with #12211 (once |
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 seeing some strange behavior with bounds surrounding a pole. The map usually zooms much further out than I would expect. Sometimes, when starting at high zoom and pitch, zoom doesn't change at all.
pole.bounds.mov
I'm also noticing that the globe will spin around rather than crossing the antimeridian, this seems to be an existing issue with map.easeTo()
.
bounds.spin.mov
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.
A few more nits but overall 👍
Co-authored-by: Volodymyr Agafonkin <agafonkin@gmail.com>
Co-authored-by: Volodymyr Agafonkin <agafonkin@gmail.com>
ed8f240
to
85351bd
Compare
That's a side from the method we adopted in #11951. Minimizing scaling towards the pole has the effect of not resolving the real zoom for a given altitude. Since we re-adjust the scaling to be constant instead of implicitly zooming in but aren't adjusting zoom at the same time, we may resolve a much higher zoom than if we were to zoom towards the pole, compared to before #11353. The current approach towards resolving altitude -> true z in this PR is an approximation: https://github.com/mapbox/mapbox-gl-js/pull/12138/files#diff-a2b3330768267b8c7996b8bf292fcd864e8b768f538436813b0d7e19f7202176R1988, which may introduce a fairly localized issue around the poles/extreme latitudes as you noticed. I think we can improve and put more effort into deriving true zoom if that becomes more of an issue in practice. A suggested fix towards the original issue of #11353 would be to adjust the zoom dynamically, so that such calculation are always correct, but this had other side effects since styling can depend on zoom. It's not a trivial problem and these are some of the trade-offs that we have to account for.
This isn't an issue directly related to this PR, and part of |
Fixes https://github.com/mapbox/gl-js-team/issues/479
This PR adds support for
cameraForBounds
on globe and updates the method used bycameraForBounds
to account fully for 3d perspective. A demo of the prototype to help visualize the new method is available here.Currently,
cameraForBounds
only takes into account the mapbearing
in 2d dimension. In order to use it on globe as well as extend the method to account forpitch
appropriately, the camera frustum adjustment has to be done in using the 3d bounding box of the coordinates we are fitting.The new method reconstructs a 3d bounding box from the perspective of the camera, as can be seen in the following video:
frustum-fit.mov
It's important to note that left and right planes aren't perfectly tight with the initial bounding box; this is an overall preferable behavior as we ensure that that the final camera placement is looking at the centroid of both the reconstructed aabb in camera space and the original bounds.
Launch Checklist
@mapbox/gl-native
if this PR includes shader changes or needs a native portmapbox-gl-js
changelog:<changelog>Add support for cameraForBounds with globe view</changelog>