Possible to change values of tileset without RecreateTileset()

We are developing a VR application and would love to be able to dynamically change certain values of the tileset like “Maximum Screen Space Error” and “Enable Frustum Culling” without the whole tileset reloading.

Our idea is when a user is flying around the globe or even in a city the Screen Space Error could be relatively high to increase performance while moving around, but when the user stops and lingers around I would like to increase the resolution of the tileset by dropping the Screen Space Error. This would allow the user to see much more detail in the tiles.

Currently the implementation of setting these values with their public setters calls RecreateTileset(), which makes the whole tileset start to load from scratch again, which is not ideal for what we are trying to do.

Is there any way to achieve what I’m trying to in the current version?

No, there’s no workaround for that currently. It wouldn’t be a huge code change, though, to make the setters for those properties instead update the equivalent parameter in the existing Tileset instance held on the C++ side, rather than recreating it. We’d welcome a pull request for that if you’re up for it.

Would that be a change to how the C++ is called on Cesium Unity side or a change to how the setters are set up on the Cesium Native side? Or both?

I don’t mind looking into the change and seeing what I can do. I will say my confidence in C# is higher than in C++ though I should be able to make my way around some simple changes in the C++ side.

It would likely require changes to both the C# and C++ code.

On the C# side, in all of the properties that can be changed without recreating the tileset, you’d just replace the call to RecreateTileset with a call to UpdateTilesetOptions. Then that UpdateTilesetOptions would be implemented in C++ to query the new values of the options from the Cesium3DTileset instance and assign them to the TilesetOptions instance on the native Tileset.

1 Like

Hey Kevin, I started looking into making this change. I’m having issues with Reinterop.

I made a change in Cesium3DTilesetImpl.cpp I added this function Directly under the RecreateTileset function in that file.

void Cesium3DTilesetImpl::UpdateTilesetOptions(
    const DotNet::CesiumForUnity::Cesium3DTileset& tileset) {
  if (this->_pTileset) {
    TilesetOptions options = this->_pTileset->getOptions();
    options.maximumScreenSpaceError = tileset.maximumScreenSpaceError();
    options.preloadAncestors = tileset.preloadAncestors();
    options.preloadSiblings = tileset.preloadSiblings();
    options.forbidHoles = tileset.forbidHoles();
    options.maximumSimultaneousTileLoads = tileset.maximumSimultaneousTileLoads();
    options.maximumCachedBytes = tileset.maximumCachedBytes();
    options.loadingDescendantLimit = tileset.loadingDescendantLimit();
    options.enableFrustumCulling = tileset.enableFrustumCulling();
    options.enableFogCulling = tileset.enableFogCulling();
    options.enforceCulledScreenSpaceError = tileset.enforceCulledScreenSpaceError();
    options.culledScreenSpaceError = tileset.culledScreenSpaceError();
    // options.enableLodTransitionPeriod = tileset.useLodTransitions();
    // options.lodTransitionLength = tileset.lodTransitionLength();
    options.showCreditsOnScreen = tileset.showCreditsOnScreen();
    this->_pTileset->setOptions(options);
  }
}

I then added this line to the Cesium3DTilesetImpl.h:
void UpdateTilesetOptions(const DotNet::CesiumForUnity::Cesium3DTileset& tileset);

Then inside ConfigureReinterop.cs I added this line
tileset.UpdateTilesetOptions();

And in the Cesium3DTileset.cs file I added this:
public partial void UpdateTilesetOptions();

Then when returning to Unity to try and get Reinterop to rebuild the changes I get errors in the console
NotImplementedException: The native implementation is missing so Update cannot be invoked. This may be caused by a missing call to CreateImplementation in one of your constructors, or it may be that the entire native implementation shared library is missing or out of date.

I feel like I’m missing some small step in the process but I for the life of me haven’t figured to what I’m missing. This dev flow is very new to me so I’m pretty sure it is something I’m doing wrong.

Also to note when I remove the line from ConfigureReinterop.cs the editor no longer throws errors and the tileset loads but obviously doesn’t have the changes I want to access.

So I figured out my issue, I forgot to recompile the c++ using CMake.

Now I can see my other mistakes like setOptions not being a property of tileset :slight_smile:

I’ll keep plugging away at the change and see if I can get it to work.

So I ended up getting it to work the way I wanted to but it required a change on cesium-native side as well just the addition of the setOptions function in Tileset.cpp and the declaration in the header file.

Wondering if there is a way to set the options on the tileset without the need to add this function. I see that getOptions returns a pointer of the options object so I thought I could just change the values of that and it would work but sadly that did not work. So I just added this small function and called it with the new changed options object.

void Tileset::setOptions(const TilesetOptions& options) {
  this->_options = options;
}

Getting the options from the tileset and then setting properties on it should work. In fact, if you have something like this working with your code change:

tileset.setOptions(newOptions);

Then it should work just as well with:

tileset.getOptions() = newOptions;

But setting individual properties is probably better. It might help to share your (non-working) code.

Just tested and yeah tileset.getOptions() = newOptions does indeed work the way you suggested.

The full code I have now is as following:

void Cesium3DTilesetImpl::UpdateTilesetOptions(
    const DotNet::CesiumForUnity::Cesium3DTileset& tileset) {
  if (this->_pTileset) {
    TilesetOptions options = this->_pTileset->getOptions();
    options.maximumScreenSpaceError = tileset.maximumScreenSpaceError();
    options.preloadAncestors = tileset.preloadAncestors();
    options.preloadSiblings = tileset.preloadSiblings();
    options.forbidHoles = tileset.forbidHoles();
    options.maximumSimultaneousTileLoads = tileset.maximumSimultaneousTileLoads();
    options.maximumCachedBytes = tileset.maximumCachedBytes();
    options.loadingDescendantLimit = tileset.loadingDescendantLimit();
    options.enableFrustumCulling = tileset.enableFrustumCulling();
    options.enableFogCulling = tileset.enableFogCulling();
    options.enforceCulledScreenSpaceError = tileset.enforceCulledScreenSpaceError();
    options.culledScreenSpaceError = tileset.culledScreenSpaceError();
    // options.enableLodTransitionPeriod = tileset.useLodTransitions();
    // options.lodTransitionLength = tileset.lodTransitionLength();
    options.showCreditsOnScreen = tileset.showCreditsOnScreen();
    this->_pTileset->getOptions() = options;
  }
}

What I was doing prior to the setOptions() which is now replaced, was assuming that because options is set like so TilesetOptions options = this->_pTileset->getOptions(); that I didn’t need to “set” it back as I thought it was a reference to the real property and changes I made on that object would reflect onto the tileset. So the code just ended after setting all the options.value.

I created a PR for my changes.

It’s not a reference because you haven’t declared it as such. Change this:

TilesetOptions options = this->_pTileset->getOptions();

To this:

TilesetOptions& options = this->_pTileset->getOptions();

And it will no longer be necessary to do the this->_pTileset->getOptions() = options at the end.

Thank you for the PR!

Oh neat, that syntax is new to me good to know. Willing to change any of my changes to fit best practices y’all recommend.

1 Like