off center view

I have the following problem. I have an app that shows the view from the aircraft nose perspective. I show 3D scene and manipulate the camera with a simple function that uses camera.setView() when the aircraft moves.

function setCamera(lat, lon, height, direction, pitch, roll)

{

viewer.camera.setView({

destination: Cesium.Cartesian3.fromDegrees(lon, lat, height ),

orientation: {

heading: Cesium.Math.toRadians(direction), // value is 0.0 (north)

pitch: Cesium.Math.toRadians(-pitch) , // 0 - straight

roll: Cesium.Math.toRadians(-roll) // 0 - horizontal

}

});

It works fine and the aircraft nose always looks at the center of the screen as in the camera1.image

Now, the problem is that I want to hide a bit the view the camera/eye see, so the center of the screen (viewport) IS NOT where the camera/eye look at but is a bit offset. In other words, it would be like when having 2 eyes open I look at the same point and have a 120 fov. then I close left eye and see only 90 fov BUT I still look at the same point seeing 30deg to the left and 60 to the right. I visualised that in the camera2 image. The point at which I want to look is not the center of the screen and I see less to the left (and top as well in that example)

Currently I achieve that effect by rendering the full screen and then clipp the view I show on the web page (camera3 image) with the simple html setting:

@import url(Build.svs/Cesium/Widgets/widgets.css); #cesiumContainer { position: absolute; top: -33%; left: -10.35%; height:133%; width: 110.35%;

however the problem is the performance, because cesium will render in memory the full screen and the browser will show only clipped image. The bitmap that is rendered by Cesium is 50% bigger than the one I want to show and I hit performance issue as cesium is embedded into another 3D application that consumes a lot of GPU power.

So the question is how to achieve the same goal without the trick. I am not 3D expert, so I have no clue whether it is frustum related or camera related issue but I believe the goal could be achieved by rendering ONLY the required viewport.

Any help much appreciated

Marcin

I believe something I want to achieve is what is available in three.js using the following function:

camera = new THREE.PerspectiveCamera( for, aspect, near, far );
camera.setViewOffset( fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight );

wth example here: https://threejs.org/examples/webgl_multiple_canvases_grid.html

that allows multi screen rendering and would allow me to do what I want. Is is possible in Cesium ?

M.

Hi M,

I think you may be able to accomplish what you’re looking for by setting some of the following:

Gabby

Hi Gabby,

Thank you for your answer. I am aware of all those options however I could not find any documentation on how to use that specific options.

Look, at threejs the following function is self-explanatory

camera.setViewOffset( fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight );

I have the dimension of the full scene plus the exact location and size of the viewport I want to render. How to achieve the same function in Cesium is a question. I tried manipulating PersepctiveOffCenterFrustum and xOffset attrubutes of PerspectiveFrustum but no luck. Moreover I have no idea how to specify that fullWidth and fullHeight and then cut the view to specific viewport …

Any help/examples on using PersepctiveOffCenterFrustum. to achieve similar function as setViewOffset as in three.js would be much appreciated. I think it would be useful for the Cesium community, for example when someone would like to use Cesium in multiscreen scenario …

The only resource on the topic I found was the following one, however it does not explain how to use perspectiveOffCenterFrustum:

https://groups.google.com/forum/#!topic/cesium-dev/hoGEY8HHBjE

Marcin

Hi Marcin,

While looking for an example, I think what will work best for your use case is to keep the persepectiveFrustum and use an xOffset for horizontal offset or yOffset for vertical offset. An example of setting up the frustum with these parameter can be seen in our implementation of VR. We create two views, one for each eye, and then offset the perspective along the x axis slightly.

Thanks,

Gabby

Thanks Gabby, I already knew those 2 options but could not figure out how they work. Last days I experimented a bit and came to conclusion, than when using the offset, the eye point is still “looking” at the center of the viewer, however Cesium does not render the offseted area. Below an example in the SandCastle:

var viewer = new Cesium.Viewer(‘cesiumContainer’);

viewer.camera.frustum.yOffset= -(viewer.camera.frustum._offCenterFrustum.top - viewer.camera.frustum._offCenterFrustum.bottom)/2 ; // half height

viewer.camera.frustum.xOffset= -(viewer.camera.frustum._offCenterFrustum.left - viewer.camera.frustum._offCenterFrustum.right)/2 ; // half width

viewer.camera.setView({

destination: Cesium.Cartesian3.fromDegrees(11, 47, 9000),

orientation: {

heading: 0,

pitch: -Math.PI/2,

roll: 0

}

});

viewer.scene.debugShowFramesPerSecond =1;

and you can see the transparent part on top and left area.

Now, that is more less something I was looking for, i.e. with the trick to move the HTML element in which I embed cesium content, however I am not convinced it should work like that because you still render that empty area that is unnecessary. I noticed slight performance improvment when using the offset.

In three.js the setViewOffset , function cuts the scene so you could have multiple screen display, e.g.

What you want to do is definitely possible, see the Liquid Galaxy showcase for an example of using cesium on multiple screens using different, offset viewports.

For improved performance, you will definitely need to modify the frustum to properly cull the tiles you don’t want rendered. You may want to use the offset in combination with the html/css cropping. I’m not sure exactly what the solution is here, but for debugging, I suggest using the Cesium Inspector:

//Add Cesium Inspector

viewer.extend(Cesium.viewerCesiumInspectorMixin);

``

Check Terrain > Suspend LOD Updates then General > Show Frustum Planes. You can then move around the scene and “look” at the frustum and the tiles loaded.

If you’re getting that error for PerspectiveOffCenterFrustum, it must be a special use case for 2D mode.

Thanks,

Gabby

do you have example code to fulfill this feature likeLiquid Galaxy showcase?
i want only show half frustum, and this half fill the scream, but have no idea how to do it

do you find a better solution to fulfill this feature? it only hide some part of map , but not make the cutted pard fill the scream

Hi!

I am also looking for a solution here. The way I understand it, you can use the xoffset and yoffset to offset the PerspectiveFrustum to avoid rendering more than needed for each screen, but to select what goes on to which screen, we need to render the full view (across all screens) and then select with CSS that part that goes on the current screen.

@Gabby_Getz Thank you for your very helpful hints here. I haven’t found any other information source on this topic than this post. I do believe that the Liquid Galaxy is different, though, in that the screens there are not in one plane, but rather in a circle and for that use case, you just have to turn the camera to get the other screen rendered. No offset required. But for a grid of screens where the screens are all in one plane, we need to do the offset rendering.

Thanks in advance,
Best regards,
Stein :slight_smile:

Hi, We had few tries on this. Our main product is a video wall software that is distributed and one of our main features is displaying maps and data elements on them but do it on large video walls and distributedly on screen nodes. Even doing it on 2D is complicated by the way and was small part of my PhD research. We had several approaches on 3D using Cesium, which included matrix calculations. We also tried the Liquid galaxy approach, back in 2014 and than again on 2022 again, which does it only on X axis BTW and we tried to expand it to both axis and unfortunately it failed. We then did our own matrix calculations and in theory nailed it but in practice failed. It required access to cesium core code, even patching it was not enough since our understanding of cesium core code and its render cycles were inadequate to implement the changes without breaking the core cesium code. We had a one last run on few weeks ago this time using AI and failed again and we had to fallback to the basic approach suggested by Gabby, again. BTW, her approach does the job but has few performance problems in our case since the canvas size can be millions of pixels eventhough most of it will not render anything, it still bottlenecks render pipelines. If you are not doing it for a grid of screens and just an offset view on the same screen, it should not have the same problems we have I guess. The only problem you might encounter is it removes elements based on their center, so you may see tiles or geometry removed on the edges of the frustrum since the center of those element is outside the frustrum. We overcome this by expanding the frustrum with a small percentage. Anyone wondering can check how it performs in the video in our documentation BTW:https://lygos.io/docs/media/earth. On that page those screens connected to different computers all are set with offset parameters and the main one on control computer has the full view. As a person who spent days, maybe weeks on this, I can say that unless Cesium implements it itself with updating its core code with appropriate changes, and provides it with API similar to ThreeJs, it is currently close to impossible other than the approach suggested by Gabby.

Best

Bertan