-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Multiple Viewports #5214
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
Comments
We have an overlay pass. Do we want to execute those on the entire canvas or each viewport? It's only used for the shadow map debug views and Where do we put the credits by default? |
CC #3001 |
Having different scene modes will be possible with the first option. Would it be possible with the second? Are we maintaining backwards compatibility? It would be difficult with the first option, probably easy for the second option. |
All of the widgets created by |
What is the current progress? |
@yoyomule there is initial work in the viewports branch; however, it requires pretty significant changes to the core rendering engine so we couldn't justify the effort at the time. We'll revisit, but the timeline is TBA. You are welcome to pick up this work sooner if you are interested, see CONTRIBUTING.md. |
Requested on the forum: https://groups.google.com/forum/#!topic/cesium-dev/vNyg1-fVvfw |
Partial support added in #6958. |
Requested again on the forum: https://groups.google.com/d/msg/cesium-dev/SUqz4UGrSMA/F-l1ZuRTBwAJ
|
What is the current progress? |
Here's a use case on the forum where a user would like to use one DataSourceCollection (i.e. list of entities) across multple views: https://community.cesium.com/t/shareddatasources/35455/3 |
Specifically one would like to control the culling of tileset a bit more flexibly. Memory is costly here, so adding a second viewer is not quite the option and not helping with the culling issue at all. Out-of-frustum tiles get unloaded way to early and can cause faulty/flickering shadows in the scene. and a discussion on Unity: I'm not aware of a similar issue for JS, but having more control of Tileset culling and loading could certainly be welcome. This also affects Terrain Tiles to some lesser extent. |
Also brought up in #12553. |
iTwin.js solves this by having a single WebGL context. The render system object creates a HTMLCanvasElement and from it obtains the WebGL context. Back in 2017 when we implemented this, we observed that the blit operation could be slow in non-Chromium browsers, so we implemented an optimization that draws the WebGL content directly to the screen if only one viewport is in use, skipping the blit. We suspect (hope?) that this optimization is no longer necessary, but need to test. All WebGL resources for things like tilesets, decoration graphics, map imagery textures, etc are allocated from the shared WebGL context. They can be used by any number of viewports. Their lifetimes are tracked independently of the viewports and they are deterministically freed when no longer in use. |
While I'm not sure it'll be applicable to all of the desired use cases, a popular approach appears to be simulating multiple canvases with one canvas, viewports, and scissor tests. |
A few notes on implementing 3D Tiles and terrain selection for multiple views, based on having implemented a couple of different versions of this in cesium-native... There are two broad ways to approach it. Select a single set of tiles for all viewsOne is to run the tile selection algorithm once, producing a single set of tiles to display in all of the views. With this approach, a tile that is visible in any view is not culled, and the refinement decision is based on the worst SSE in any view in which the tile is visible. We've had this version in cesium-native for awhile now, and it's simpler in many ways. The major disadvantage is you may end up rendering too much detail in some views, because that detail is needed in other views, causing aliasing artifacts or lower performance. Make sure you avoid the silly bug we currently have in cesium-native where SSE is computed for all views, not just the ones where the tile is visible, because that can fail badly in some corner cases. For example, consider two cameras at the same location but one with a very narrow field of view and one with a very wide one. This configuration will end up loading detail suitable for the narrow FOV for the entire area visible in the wide FOV. Select an independent set of tiles for each viewThe other approach is to run the tile selection algorithm separately for each view, selecting a completely separate set of tiles for each view. This is slower, because it requires traversing the BVH multiple times (or at least, any way I've thought of to avoid this would add a lot of complexity and probably not significantly improve performance). And you'll need to make sure that the selected set of tiles is only rendered in the view to which it applies, which is tricky in Unreal and Unity, but probably less so when you have full control of the rendering engine as CesiumJS does. The total number of tiles to be loaded is also higher in this approach, too, at least to the extent you're able to skip lower levels of detail. We've recently implemented this approach in cesium-native in CesiumGS/cesium-native#1125. The major challenge was that the tile selection algorithm previously stored a "last selection result" in the So instead we use this new class called There's some explanation of how it works here: In cesium-native now, we actually support both of these broad approaches. There are multiple independent "view groups", each of which contains one or more views that select tiles together. Ownership and LifetimeOne part of this - especially the second approach - that was hard in cesium-native was tracking ownership and lifetime of Some of this is likely much easier in CesiumJS thanks to the garbage collector. But CesiumJS still unloads Tile content explicitly, so it needs to decide when to do so. In cesium-native, we wanted to allow the different view groups to tick independently. One might update at 60 FPS, while another only updates rarely. So we can't take a shortcut based on frames, such as, "if a Tile was used last frame, we need to keep it, and when unloading we should first unload the Tile that was last used in the oldest frame." In cesium-native we solved this by reference counting. Every view group holds a reference to each Tile instance that it traverses. When that reference count goes to zero, the Tile is added to the tail of a linked list of unused tiles. When the reference count goes back to 1, it is removed from that linked list. At any time, we can unload all of the tiles in the linked list, as the ones closest to the head are the last-recently-used. Except it's more complicated than that. cesium-native now also supports unloading entire unused external tilesets and their corresponding Tile subtrees. For external tileset content to be unloadable, all tiles in its subtree must first be unloaded, which means that all the subtree content can not be referenced. So here's the complicated (but effective and efficient) scheme:
Load PrioritizationWhen there are multiple views, each of which want to load different tiles, how do we decide which tiles to load first? At first, I thought we would need to come up with a prioritization metric that works across views. That would probably mean it is a function of SSE or something, not the distance-based priority metric we use in cesium-native (and CesiumJS, too, I think). Instead, we've decided to select tiles to load using a weighted round-robin algorithm. Each view has a "weight" which is initially 1.0 and can be configured by the user. When all views have equal weight, they get an equal chance to select the next tile to load. A view with double the weight of the others would get double the number of chances. I think this turned out to be pretty elegant and definitely recommend you use it (unless you have a better idea of course!). |
Allow for multiple viewports/camera views in a single canvas.
SceneManager
containing multipleScene
sSceneManager
contains all non-view dependent primitives.Scene
contains a copy of view dependent primitives.Globe
Scene
with a list ofViewport
s that contain a camera and viewport rectangle.The first option is more flexible but more complex. The second option is simpler but has a couple of constraints.
PrimitiveCollection
.ScreenSpaceCameraController
needs to know which viewport the input originated in.div
s. Potentially expensive.The text was updated successfully, but these errors were encountered: