maplibre / maplibre-gl-js

MapLibre GL JS - Interactive vector tile maps in the browser
https://maplibre.org/maplibre-gl-js/docs/
Other
6.32k stars 689 forks source link

Add API support for adjusting camera roll angle, extend pitch angle range #4717

Open ssokol opened 1 day ago

ssokol commented 1 day ago

User Story

As a developer I can programmatically adjust the roll angle of the camera from 0 (level) to +/- 180° and I can programmatically adjust the pitch angle from 0° (looking down) to 180° (looking directly up) so that I can accurately represent the spatial orientation of the observer when displaying maps with 3D terrain.

Rationale

I am looking to use MapLibre in an aviation application to implement what is commonly know as "Synthetic Vision" - a feature which provides a virtual "view from the cockpit". To be able to accurately represent the this view, I need to be able to adjust the roll angle of the camera to match the roll angle of the airplane. You can see a similar system at a distinct roll angle here:

https://blog.foreflight.com/wp-content/uploads/2014/12/800x600-refined-terrain.png

From what I can find, the transformCameraUpdate callback currently allows programmatic control of bearing, center, elevation, pitch, and zoom (with pitch limited to 0° - 60°). Perhaps this could be extended to include the roll parameter and to accept pitch values from 0 (straight down) to 180 (straight up).

It might also be useful to allow for all of these parameter to be incorporated into the parameter objects for map.flyTo() and map.easeTo(). The way the Synthetic Vision app works, a server feeds situation data (location, altitude, track, speed, etc.) over a WebSocket at between 10-20 Hz. The handler for the WebSocket moves the camera using a string of very short duration flyTo or easeTo operations. Adding the ability to update situational parameters directly would simplify the process.

Impact

This won't have any real impact on users who only need a basic down-and-forward level view, but it will go a long way towards making MapLibre more useful for certain simulations, games, and situational awareness applications.

HarelM commented 1 day ago

Thanks for taking the time to open this issue. In general, I think this can be a nice (although niche) addition to this lib. The main caveat I can think of is which tile to fetch and show. But feel free to push this forward.

ssokol commented 21 hours ago

Thanks!

I'm slowly making my way through the library - long time Javascript user, first time Typescript user. I hope to be able to submit a PR, but it will probably need some help from those more fluent in the language. One question for you...

I haven't been able to find a way to manually set the camera altitude in feet or meters above median sea level. I kind of expected the easeTo and flyTo functions to have an altitude parameter, indicating the camera altitude at the end of the move.

Is there an API call to set the camera altitude independent of the zoom level? I see references to altitude in the camera.ts and map.ts files, but the altitude seems to be an output based on the current zoom level rather than something that can be preset programmatically.

HarelM commented 18 hours ago

Zoom level is highly tide to altitude, it has deep historic roots and causes a lot of grief with terrain related stuff. You can use cameraFromTo I believe to calculate some stuff, IIRC.

ssokol commented 18 hours ago

Thanks. I'll look into that. I was just reading over the discussion of deterministic values on #4688 and it seems like the camera controls and associated motion methods may have come from the purely 2D world, where 'zoom' makes far more sense than 'altitude', and where pitch simply isn't a concept.

In testing some ideas I've discovered that the "center" parameter has very different meanings depending on if there is a pitch angle set. With a zero pitch (essentially a 2D map), center places the camera exactly where I expect it to. With a pitch value set, the lib appears to set the "gaze" or "focal point" of the camera at the "center" location, rather than the camera itself. Probably useful for some things, but challenging to use for a PoV application.

I wonder if 3D / terrain apps might be better off with a different camera control model. This would make center, altitude, bearing, pitch, and roll fixed and deterministic - these position the camera. The "gaze" or "focal point" is then determined by the zoom level (and optionally some additional parameters if needed). For my app, zoom will be constant throughout since it emulates what a human would see looking out the front window of an airplane.

Do you think there might be interest in a large bounty (perhaps funded by several participants) for a project that builds out a more 3D-centric "mode" or set of APIs?

HarelM commented 10 hours ago

I don't have a good answer to the question about if there is an interest, and if someone would like to pay for it. One thing to note is that one can switch from 2D to 3D and the expectation is to be at the same "position", so a concept where center means different things in respect to terrain may be problematic. API-wise, I think Cesium has implemented something with unreal engine that allows looking from the ground up, might be interesting to look at what they did. The concept of zoom is very much coupled to level of details (vector rendering) so that needs to be taken into account as well...