Created Camera, Animation and Frame State (markdown)
@@ -0,0 +1,77 @@
|
||||
## Cameras
|
||||
|
||||
Concepts like "center" and "resolution" only have meaning for 2D top-down views of the map. As soon as the view tilts the position of the view is different from the position at the center of the viewport, and resolution varies across the viewport. In 3D the position at the center of the viewport could be considered to be the point at which a ray traced from the camera through that pixel intersects the terrain, the surface of the underlying ellipsoid model, or even be undefined if the ray does not intersect the globe (e.g. the camera is pointing at the sky).
|
||||
|
||||
For this reason, if views other than simple 2D views are to be supported, the current concepts of "center", "resolution" are inadequate. The concept of a view, or camera, needs to be separated from the map, and different camera classes will be needed for different views:
|
||||
|
||||
2D top-down: position (center), resolution, heading (rotation), cartographic projection
|
||||
|
||||
2D with tilt: position, height, heading, tilt, cartographic projection
|
||||
|
||||
3D cartesian: position, height, heading, tilt, roll, cartographic projection, perspective projection parameters
|
||||
|
||||
3D globe: position, height, heading, tilt, roll, perspective projection parameters (cartographic projection is generally fixed at EPSG:4326)
|
||||
|
||||
See [Google Earth API View](https://developers.google.com/earth/documentation/reference/interface_g_e_view) and [Cameras in Cesium](https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Scene/Camera.js#L30).
|
||||
|
||||
## Frame state
|
||||
|
||||
If rendering is delayed (e.g. by deferring it to the next `requestAnimationFrame`) then the value returned by `map.getCenter()` will be different to the center actually rendered. This will cause confusion, and may cause subtle bugs. Therefore, it is important to keep track of what exactly was rendered, and to track this separately from the "desired" parameters.
|
||||
|
||||
The proposal includes the creation of a "frame state" class that is (a) populated to describe what *should* be rendered and (b) preserved to record what actually *was* rendered. By modifying the frame state before it is passed to the renderer, effects such as animations can easily be achieved with a flexible, generic framework.
|
||||
|
||||
|
||||
## Basic flow
|
||||
|
||||
1. When it is time to render (for example when we just got our `requestAnimationFrame` callback), the map creates an initial frame state containing the current time, camera, viewport size, and layer settings.
|
||||
|
||||
2. Zero or more pre-render hooks are called with the frame state. These pre-render hooks can modify the frame state in place, e.g. to animate the camera. Pre-render hooks can also deregister themselves, which is used, for example, for animation hooks when the animation that they control is complete.
|
||||
|
||||
3. The updated frame state is passed to the renderer. The renderer effectively does a "diff" between the last rendered state and the updated frame state to minimise actual changes to the DOM. The renderer can further update the frame state, e.g. to indicate which data sources were used in the rendering.
|
||||
|
||||
4. The final frame state is saved in the map so it can be used to for viewport-to-map transformations and vice versa.
|
||||
|
||||
5. The map fires a `postrender` event indicating that a new frame has been rendered.
|
||||
|
||||
|
||||
## How various things would work
|
||||
|
||||
Side-by-side demo: the two maps bind their cameras, rather than binding their individual center/resolution/rotation/projection properties. By careful binding of properties with some transformations, it should be possible to do side-by-side 2D and 3D views.
|
||||
|
||||
Attribution control: this listens for `postrender`, reads the list of data sources directly from the frame state and updates itself accordingly. This avoids the expensive re-calculation of what was visible that the attribution control does currently, and it allows the attribution to be more precise. For example, if a renderer used an interim tile from a different zoom level, it can record this in the frame state.
|
||||
|
||||
Overlays: this also listens for `postrender`, and simply updates its position. Note that this means that the overlay and the map always stay in sync, and that the overlays only update their positions when the map is re-rendered, avoiding unwanted redraws due to (say) multiple calls to `map.setCenter()`
|
||||
|
||||
Animated zooms, kinetic pan: these install a pre-render hook that update the camera position as a function of time, and de-register themselves when they are complete.
|
||||
|
||||
Interruptible interaction-initiated animations (e.g. mousewheel zoom in interrupted by mousewheel zoom out): there is a maximum of one pre-render hook for these which is *replaced* when the user initiates a new change.
|
||||
|
||||
Scheduling a redraw when a tile loads: the renderer calls `map.requestRenderFrame()`.
|
||||
|
||||
|
||||
|
||||
## Advantages
|
||||
|
||||
Many features can now just listen for `postrender` rather than having to listen for all camera events (`center_changed` / `resolution_changed` / `rotation_changed` / `projection_changed`). This both decouples features from the camera representation and drastically simplifies their implementation.
|
||||
|
||||
Animations, including multi-faceted ones like a rotating fly to and zoom, are easily scripted and work with all renderers. All animations are handled by the same architecture, there are no special cases. Any parameter can be animated, e.g. a layer's saturation or brightness. The framework is completely general and not restricted to only camera-related parameters.
|
||||
|
||||
High quality animation: the frame state includes a timestamp that can be used for precise tweening of any parameter.
|
||||
|
||||
Renderers are stupid, making them easy to write (e.g. the renderer knows nothing about animation).
|
||||
|
||||
All of the advantages of the request render frame (explicit behaviour, freezing/unfreezing, no reliance on non-deterministic behaviour, support for platforms without rAF).
|
||||
|
||||
All updates to the DOM are synchronized with `requestAnimationFrame`, via the `postrender` event.
|
||||
|
||||
Corresponds closely to needs of WebGL and (eventual) Canvas 2D renderers. DOM renderer can easily be adapted (see below).
|
||||
|
||||
|
||||
## Possible downsides
|
||||
|
||||
Traversing frame state to determine diff to render is more CPU/memory intensive than just responding instantaneously to events. This is only likely to be a problem for maps with many, many layers.
|
||||
|
||||
|
||||
## DOM renderer notes
|
||||
|
||||
No CSS transitions, CSS properties are computed as a function of time when needed, the DOM is only ever modified during actual calls to render(), other changes (e.g. loaded images) are queued, no clever scaling algorithms: maintain a single DIV per layer with tile images in their original size, this DIV per layer is then transformed with a single CSS transform. Exception: CSS transition can be used to fade in tiles.
|
||||
Reference in New Issue
Block a user