LOD - Disable Distance Checks + Ensure Highest LOD

I’m having issues getting the LOD I’d like.

  1. MaximumScreenSpaceError is a confusing concept. Is there anyway to request a specific LOD #.

  2. What is the difference between MaximumScreenSpaceError on CesiumIonRasterOverlay vs on the Cesium3DTileSet (shown in Screenshot)?

  3. How do I force the highest LOD? I made a setting which changes the CesiumIonRasterOverlay’s at runtime and that seems to work OK up to a point though I’d like to go lower than 1. At least whatever LOD that is displaying at 1 is not the max since if I zoom in I can get higher ones.

  4. How do I prevent it from automatically swapping to lower LODs when the camera is far away? I disabled FogCulling but that didn’t seem to change anything. The LODs are still swapping if I move the camera further or closer.

  5. This last one may be unrelated cesium but I’m using a VR headset and when I turn my head quickly side to side the tiles flicker (disappear and then come back). I thought it may be the frustrum culling but I disabled that and its still happening. Any ideas what could cause that?

This screenshot is from the properties in the editor at runtime.

I changed MaximumScreenSpaceError from 8 to 2 and it didn’t help.

The issue is I want to view these tiles on a table in VR/AR while standing next to the table. When I am standing up the LOD is very poor/low quality. When I lean over and put my face next to the tiles the detail is fine/good quality. I’m trying to make the LOD be good quality even when the camera is far away.

Did a couple more tests. I set the ScreenSpaceError to 1, 0.1, and 0.0001. The 0.0001 just loaded very blurry low lod tiles. 0.1 had one good tile and rest were low lod. 1 seemed about the same as when I entered 2. Looked ok if I moved my headset close to the map and low lod when I moved further away.

Also I checked hierarchy when I moved my head side to side. It is deleting the tiles and recreating them.

I really just want a way for it to just set a Level of detail and load it. Don’t dynamically change based on distance. Don’t change based on frustrum/fog/etc. Let me do that. It doesn’t seem like disabling frustrum culling or disabling fog does anything. Is there another property/setting/class I am missing or is this a bug?

Hi @Mark_Grossnickle,

There’s no way to force 3D Tiles to render the highest LOD at all times. The nature of 3D Tiles is to load different levels of detail based on tile distance from the camera. Forcing every highest detail tile to load, no matter the view, would overwhelm the machine.

  1. What VR headset you’re using? I’ve personally experienced bugs with the Magic Leap because their cameras were reporting 1x1 dimensions on the device. This obviously interferes with the screen-space algorithm, and it would render much lower levels of detail than what I was seeing on PC.
  2. How are you scaling the 3D Tiles – are you using the Scale property on the CesiumGeoreference? Or are you modifying the Transform of the object?

@janine thank you!

It would be nice to let the developer decide if we are overloading the machine. I ideally don’t want the low, medium, etc levels of detail loaded and taking up memory. I want a single level and I want to control which level.

  1. We are using a variety. Quest 2, Quest Pro, Varjo XR 3, Hololens, etc. I’ve personally been testing on Quest 2 (PC link and without). PC Link and Varjo obviously would be able to handle any tile resolution.

  2. Scaling on CesiumGeoReference. Currently zoomed out is about 0.001. I was debating trying to switch to the transform if the 0.001 was messing up the math.

How can I prevent tiles from being destroyed when they leave the view?


As Janine said, this is not how 3D Tiles works. Except in limited circumstances, it can’t work this way. People request this from time-to-time, but that unfortunately doesn’t make it feasible.

Let’s say you’re using Cesium World Terrain + Bing Maps aerial. That means the full model is multiple terabytes of geometry and probably a petabyte of textures. Showing “the full LOD” is absolutely, positively, not going to happen on any of today’s hardware.

If you’re looking straight down, then it’s possible to show all the tiles at a single LOD appropriate for the view. And this is exactly what Cesium for Unity will already do. Which LOD to use can be controlled by the Maximum Screen Space Error. Its more confusing then “choose a level number”, perhaps, but it’s necessary in non-trivial situations. What if there’s a mountain on the left side of the screen, but a valley on the right? The mountain is much closer to the camera, so it needs to be shown with more detail. If you showed the valley with that same detailed LOD, you’d be loading and rendering a lot more tiles than necessary.

And most people don’t look straight down. They look out at the horizon. Showing the same LOD for the nearby and the far away parts of such a scene could never work. Attempting to use the same LOD across the scene would either mean a blurry mess up close, or an exorbitant amount of data (many many gigabytes) in the distance.

This isn’t a 2D map. View-dependent LOD is necessary, and it can’t be “choose a single discrete level.”

For your use-case, the best solution would probably be to add a virtual camera above the table and looking down at it. That would keep the table at a minimum LOD, while also allowing more detail to be loaded when the user presses their face up against the table. We don’t have a great way to do this yet in Cesium for Unity, unfortunately (unlike Cesium for Unreal).

I set the ScreenSpaceError to 1, 0.1, and 0.0001. The 0.0001 just loaded very blurry low lod tiles. 0.1 had one good tile and rest were low lod.

That’s very strange. Might help to see some screenshots.

Thanks for the help!

I’m not sure why you say “it can’t be choose a single discrete level”.

Below is basically my use case. I helped write HoloMaps back in 2016. We used BingMaps, WRLD, and MapBox. I wrote the code to switch between any of those providers. Each of those providers provided the ability to select what LOD you wanted and could send you all the tiles at that LOD. I’m now consulting on another project and the three things that I would love to see are:

  1. Be able to disable making further away tiles at a lower LOD. I thought disabling FOG would do this. What does that do instead? Currently if I place a map on the table then the closer tiles are higher LOD and further tiles are LOD and it looks ridiculous. The rationale you are giving for not having this feature doesn’t apply to my use case. Users expect the entire table to look the same. I’ll look into the virtual camera solution once I fix the build error. Thanks for your help on that thread as well.
  2. Disable tiles from destroying when I look around. I thought that disabling frustrum culling would do that but it does not. If I am sitting at the table and I turn my head to talk to someone and turn back to look at the map, the map is done and reloading from scratch (low LOD and slowly looking better as it downloads better tiles). How can I disable that?

Lower wish list:
3. Be able to pick the LOD. I’m not going to pick something that requires terabytes. Trust the devs a bit and give them some flexibility to use your maps in ways you may not expect is all I am saying. The screenerror code for setting LOD is probably great for most 3D use cases. I have no idea. But currently its not working in my use case and it would be lovely to just say give me tiles at X LOD. Perhaps normalize a scale 0-100 or something. Bing, MapBox, etc all allowed for this functionality and I’m surprised Cesium does not.

I’ll see what I can do on my own. Greatly appreciate the virtual camera suggestion. I saw a ticket in git about decoupling with Camera::main so I’ll start there. If you have any other suggestions to achieve the same things please let me know. Especially the destroy tiles. Shouldn’t disabling frustum stop that from happening? Thank you!!

Be able to disable making further away tiles at a lower LOD.

Disabling that is simply not an option. It’s inherent to how the whole thing works. And, in the general case, how it has to work. I understand it could work differerently for your particular use-case. I’m not opposed to adding such an option, but it’s probably not a priority for Cesium in the short term. A pull request is welcome, but we’ll need to talk about how it fits in with the rest of the system. Running out of memory and crashing the first time the user tips the camera toward the horizon is, of course, not an acceptable solution.

I thought disabling FOG would do this. What does that do instead?

Fog culling makes very distant tiles use a lower LOD or even be culled completely.

Disable tiles from destroying when I look around. I thought that disabling frustrum culling would do that but it does not.

You probably need to set culledScreenSpaceError to the same as maximumScreenSpaceError (16 by default). By default, culled tiles are not refined to the same level as non-culled ones.

You may also find it useful to enable forbidHoles.

Be able to pick the LOD. I’m not going to pick something that requires terabytes.

Are you sure? Virtually any fixed LOD in which you can see buildings risks loading gigabytes, at least, simply by tipping the camera toward the horizon. Last I checked, tools like MapBox severely limit the possible camera angles, perhaps for just this reason.

Anyway, the inability to choose a particular LOD isn’t some arbitrary restriction we imposed on users for their own safety. It’s just that the tile selection algorithm doesn’t work that way in the first place. There’s not even a fixed notion of “an LOD” in 3D Tiles.

I suspect that more flexibility in the camera (which is planned) will solve your use-case pretty well, without the need to choose an LOD directly.

Thanks Kevin!

The gigabyte thing isn’t a problem. We are using your bounding box code to only load the tiles in a bounding box. The use case is just loading a handful of tiles in a 2.5foot radius that is placed in front of the user.

I updated the native code to call a static method on a monobehavior instead of Camera::main to request the camera. If there isn’t an instance of the monobehavior it returns camera.main. Otherwise it returns the instance’s camera property. I then placed that camera above the area we are displaying and that has fixed the LOD issue. It is no longer getting blurry away from the user. Still would be nice to set the LOD I want instead of just randomly changing screenError property and hoping it gives the LOD I want. But all good if I am in the minority there.

Anyways, I’m still getting the tiles being destroyed when I move the main camera quickly (VR headset so just tilting head side to side) which is confusing me since I don’t see any instances of camera.main or camera::main outside of the one I removed. The getAllCameras and updateView? It has to be in CameraManager or Cesium3DTilesetImpl right? Can you think of anywhere else I should look?


Spinning my wheels a bit on this one. If I move my VR headset slowly side to side or up/down the tiles do not get destroyed. Its a quick movement that cause it to reset. Logs are showing the camera properties (position, up, forward, fieldofview,etc) are stable but I’m wondering if it is the unityWorldToTileset and pCoordinateSystem as those change based on the camera’s position.

Side note, there is the enableOcclusionCulling which is one of the things I was requesting earlier. It’s just not brought into unity as a property.

Thoughts I found it… but I did not. It only happens in PC link so I think it is related to editor code. I’m not sure why sometimes it appears to be fixed and other times it is there. Since the client mainly doesn’t use PC Link at this point, I’m going to move onto something else but if anyone has ideas I’m all ears.

Hmm I’m not exactly sure, but in the Editor, we do explicitly use Editor viewport cameras to select tiles in addition to Camera.main. Why that would make tiles disappear, though, I really don’t know. It might help to see a video of the behavior. Is it only reproducible with VR hardware?