-
Notifications
You must be signed in to change notification settings - Fork 86
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
Add ability to exclude tiles by implementing a C# class. #248
Conversation
The above avoids loading tiles that are entirely outside of the area of interest. But we may also want to clip the partially-overlapping tiles so they aren't drawn outside the box. This can be accomplished with a custom material. First, make a copy of Click Double-click Click the if (abs(position.x) > 500.0 || abs(position.y) > 500.0 || abs(position.z) > 500.0) alpha = 0.0; else alpha = 1.0; The idea is that if the world position of the currently-rendered pixel is outside our box, which is centered at the origin and is 1000 meters long in all directions, then we'll set the alpha value of this pixel to 0.0 so it won't be rendered. The code here can be adjusted for other box dimensions or other shapes entirely. Click the "Position" node and change the Wire the output of the custom function to the "A" slot of the Multiply node. Connect the "A" channel of the It should look something like this: Save the material, and then select the Cesium3DTileset and change the "Opaque Material" property to the The end result is that pixels outside the box aren't drawn, and tiles entirely outside the box aren't even loaded. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kring looks good for the most part! I left a handful of comments. I tested the example you provided and it works well, though I had two concerns:
- The example excluder gets less accurate when the tileset itself is transformed. For example, here the box collider is at (0, 0, 0), but the tileset has been shifted, and the excluded tiles are off:
If it's too complicated to make a fix, we can merge this preliminary support and open a follow-up PR, but just let me know.
- If I try to invert the
ShouldExclude
condition in the example, nothing shows up. That is, if the function is defined as so:
public override bool ShouldExclude(Cesium3DTile tile)
{
return this._box.bounds.Intersects(tile.bounds);
}
This doesn't make sense to me intuitively, because I'd expect to be cutting out a square in the tileset, instead of limiting the tileset to a square. But maybe I'm missing something?
This turned out to be a problem with the example |
This surprised me at first, too, but it's actually correct. If you invert the condition, any tile that intersects the box at all will be excluded. The root tile intersects the box, so it's excluded. No further tiles are considered. If you want to exclude tiles that are completely inside the box, that's written as
(Edit: My original version wasn't quite right, but I've confirmed the edited version above works) |
One thing that doesn't work quite right is when the CesiumTileExcluder is not on the same GameObject as the Cesium3DTileset, and there is a non-identity transformation between them. For example, if the excluder is on the CesiumGeoreference (a reasonable thing to do!) and the tileset has an offset relative to the georeference (also fairly common). I'm working on it. |
This depends on CesiumGS/cesium-native#613 now. |
I think the major functionality is all in place now. I still need to fill in the missing docs and address your other comments. Thanks for the thorough review @j9liu! |
Co-authored-by: Janine Liu <32226860+j9liu@users.noreply.github.com>
I think I've addressed everything now. Let me know what you think, @j9liu! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kring These changes look great! Just one more issue: if I remove my excluder component from a tileset (I was moving components between the tileset and georeference in edit mode), it will still try to access it, resulting in this error:
Also, if anyone's interested, I made the excluder script interactive and responsive to changes:
public class CesiumBoxExcluder: CesiumTileExcluder
{
private BoxCollider _boxCollider;
private Bounds _bounds;
public bool invert = false;
protected void OnEnable()
{
this._boxCollider = this.gameObject.GetComponent<BoxCollider>();
this._bounds = new Bounds(this._boxCollider.center, this._boxCollider.size);
}
protected void Update()
{
this._bounds.center = this._boxCollider.center;
this._bounds.size = this._boxCollider.size;
}
public bool CompletelyContains(Bounds bounds)
{
return Vector3.Min(this._bounds.max, bounds.max) == bounds.max &&
Vector3.Max(this._bounds.min, bounds.min) == bounds.min;
}
public override bool ShouldExclude(Cesium3DTile tile)
{
if (!this.enabled)
{
return false;
}
if (this.invert)
{
return this.CompletelyContains(tile.bounds);
}
return !this._bounds.Intersects(tile.bounds);
}
}
Thanks @j9liu, I fixed that error when removing the excluder. One remaining problem is that the excluder does not automatically take effect when you add it; you need to refresh the tileset first. I thought about changing CesiumTileExcluder.OnEnable to automatically refresh all Cesium3DTilesets in children, but that will often be redundant. I think the tileset will need to keep track of which excluders it knows about, and then CesiumTileExcluder.OnEnable can check itself against that list and only refresh the tileset if its missing. |
@j9liu this is ready. Adding an excluder immediately affects the tilesets now. It works more or less the same way as raster overlays. I also updated the top post in this PR with the latest version of the example |
Looks great @kring ! I'll merge after CI passes. |
The BoxCollider‘s world postion didn’t move but the clipping plane move with camera moving. |
Please post to the community forum rather than commenting on closed PRs. The problem is caused by origin shifting, which keeps the origin of the Unity coordinate system near the camera in order to avoid vertex precision artifacts. The easiest solution is to disable origin shifting by removing the component from the DynamicCamera. This will be fine if you stay within a relatively small area. |
@JackMoljerc If you don't want to disable origin shifting, you can also convert your desired position into ECEF or longitude / latitude coordinates. Then, in the |
Next time, I promise. |
@kring @j9liu Thanks for the great work! It was really easy to follow the steps! So I followed every step (without the alpha clipping) Saved my unity project - but now every time I try and open it, it crashes immediately. - Maybe because of the missing alpha clipping? Thanks for your help, appreciated! |
@JonathanWiii I wouldn't expect the lack of alpha clipping to cause a crash. Do you have a call stack or any other details about it? I'm using 2021.3 (patch release varies, and shouldn't matter I hope). URP is the pipeline I was using. The alpha clipping setting exists on both the Shader and Material. On the shader, it's here: |
How to pass dynamic values instead of 500 that you have used in the example? |
@jolly17ify You could create a Vector3 Parameter in the shader and then set the shader values. Then set the param to exposed |
Is there any way to make multiple tiles to exculde on the same world? |
Sure. You can put whatever logic you like in your CesiumTileExcluder-derived class and in your custom material. |
When I am using the shader to clip the part of a tile that is not required and changing the Vector3 parameter in the shader, it doesn't clip automatically and I have to always re-update the material using following: |
Just a reminder everyone: please post questions to the community forum, not here! Setting the tileset's |
Hi @peterclemenko, Please direct questions like these to our community forum! From there, both the Cesium team and other community members will be able to help. You may have already posted there, but I want to remind everyone to move these questions and discussions to the appropriate place. We reserve Github for feature requests and confirmed bug reports. Thank you all! 😄 |
Hi, |
@06simtech perhaps you missed the message above?
To answer your question, Vision Pro is not a supported platform at all. But if you post to the community forum with a lot more details - starting with how you've managed to run the plugin on Vision Pro! - then maybe we'll have some ideas. |
Depends on CesiumGS/cesium-native#608
Added
CesiumTileExcluder
, which is a C# version of cesium-native'sITileExcluder
.The idea is that we can add a C# class like this to our project:
And then add an instance of this class as a component on the
Cesium3DTileset
or any of its parents, up to and including theCesiumGeoreference
.With that in place, cesium-native will call the
ShouldExclude
method for each tile that it is considering loading or rendering. This will happen a lot, so this method needs to be fast. Return true to skip loading and rendering that tile. Return false to load it and render it as normal.In the implementation above, a user-defined BoxCollider is also attached to the same GameObject as the CesiumBoxExcluder. Any tiles that intersect this BoxCollider are loaded and rendered, others are not. So tiles that are entirely outside of the box are ignored. The given tile's
bounds
property is an axis-aligned bounding box in the same coordinate system as theCesiumBoxExcluder
, so it's easy to do tests like this.In this screenshot, the BoxCollider is the green box in the middle of Melbourne. All of the visible tiles are at least partially inside the box:
If we disable the CesiumBoxExcluder, all the tiles load as normal:
Also in this PR: Extended Reinterop to allow constructors of blittable value types to be called from C++. On the C++ side, these are exposed as
Constrct
methods rather than C++ constructors so that brace initialization can continue to be used to initialize fields without calling into C#.