Skip to content
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

Support for overlaying one 3D Tiles tileset with another (clipping) #47

Closed
kring opened this issue Jul 31, 2020 · 9 comments
Closed

Support for overlaying one 3D Tiles tileset with another (clipping) #47

kring opened this issue Jul 31, 2020 · 9 comments
Assignees
Labels
enhancement New feature or request

Comments

@kring
Copy link
Member

kring commented Jul 31, 2020

So that we can have a "base globe" tileset and then overlay smaller, more detailed areas from another tileset. For this issue, we only need something good enough for the primary use-case of "show a globe, let the user zoom in to a more detailed area" and we should aim to keep it simple. But if it's not much more time consuming to implement the latest approach in CesiumJS, we should do that instead.

@kring
Copy link
Member Author

kring commented Dec 8, 2020

Currently we have a hacked-up system based on a list of "cutout" rectangles. Cutouts can only be used with raster overlays, and they work by a) setting the alpha value to 0.0 of any pixels in overlays inside any cutout rectangle, and b) applying the overlay's alpha value as an opacity mask.

This has some problems:

  1. It doesn't affect physics. We can still collide with the cut-out portions of the mesh. It may be possible to solve this without changing the fundamental approach by using Physical Material Masks (https://udn.unrealengine.com/s/question/0D72L000002UcHGSA0/detail). These are only available in Chaos, though, which is (afaict) still not he default in UE 4.25.
  2. It only works when we're using raster overlays.
  3. Raster overlay alpha shouldn't necessarily be interpreted as an opacity mask. Sometimes it should just let underlying layers shine through.
  4. We can't do 3D cutouts.
  5. Rectangles aren't the ideal way of cutting out a 2D footprint. Polygons would probably be easier to work with.

CesiumJS uses clipping planes, but it's not clear if we can do that in the UE material system.

I don't know what the right answer is here, it will take a lot of research. Given that a perfect solution may be elusive, we will probably need to focus on some key motivating use-cases in the first release.

@kring kring changed the title Minimal support for overlaying one 3D Tiles tileset with another Support for overlaying one 3D Tiles tileset with another (clipping) Dec 8, 2020
@kring kring modified the milestones: Basic 3D Globe, Initial Release Dec 8, 2020
@kring kring removed this from the Initial Release milestone Feb 25, 2021
@kring
Copy link
Member Author

kring commented Apr 1, 2021

Talking to some potential users yesterday, it became clear that it's probably not sufficient to just clip away the model. It's also necessary to blend between the two models so that we don't get cliff faces or holes where they meet. Adjusting vertices so that the two datasets line up probably requires assuming that the datasets are 2.5D-ish. The same folks were saying that in the rare case where the datasets aren't 2.5D at the place they meet, they sometimes (in the past) have created custom geometry in 3ds max or whatever to join them, and then blend the bigger dataset with the custom geometry further back.

@argallegos
Copy link
Contributor

One more thought on this - the ideal solution will allow you to inverse the clipping mask. This will be important for projects using just one section of Cesium World Terrain, or any other large tileset, and so they should be able to define a volume where only tiles within the volume are loaded. It would be awesome if we could make it as simple as a checkbox on the mask/volume to invert it.

I don't know how the previous solution worked, but if we could prevent tiles outside the volume from loading at all, that would be optimal and solve the collision issue.

I also think that ideally this would look like rectangular prism/cuboid (or spherical, or whatever is easiest) volume that players could drag in and scale to fit their needs. Ideally they'd be able to drag in multiple, and select which tilesets got clipped on a per-clipping actor basis. I'm kind of picturing Unreal's Geometry Brush Actors, which are used for prototyping levels. You can set these 3D brushes to be additive or subtractive, which is very cool, though I don't think we would be able to implement clipping volumes in exactly the same way.

@kring
Copy link
Member Author

kring commented Apr 16, 2021

UE has a thing called Procedural Meshes. We can create one from a normal static mesh, and then do a Slice Procedural Mesh on it to cut it with a plane and optionally cap the sliced edge with geometry.

Pretty fun demo using it here: https://www.youtube.com/watch?v=oIdKxYYQBdw

It also slices the collision mesh, but apparently only if it's a "simple convex collision", which ours are not (or at least not guaranteed to be).

@kring kring added the enhancement New feature or request label Apr 27, 2021
@kring kring added this to To do in Cesium for Unreal Apr 28, 2021
@kring
Copy link
Member Author

kring commented May 4, 2021

I was hoping there would be a place to insert some extra logic to "filter out" collisions with clipped-away parts of a mesh just-in-time. i.e., after a collision between a pawn and a tileset is detected, check to see if the collision is actually with a clipped away part of that tileset, and ignore the collision if it is.

There are some good tricks for discarding the clipped-away parts when rendering, so if we could do something like this for collision queries we could potentially save ourselves the trouble of actually modifying tile meshes for clipping.

So I spent awhile tracing through how collision works, starting with UPrimitiveComponent::MoveComponentImpl. Unfortunately, I wasn't able to see any way to do it.

Once a collision is detected inside MoveComponentImpl, the rest of the system is notified via a call to UPrimitiveComponent::DispatchBlockingHit. I believe if this method simply did nothing, then the collision would effectively be discarded. So that seems like a likely place to insert the necessary logic. Unfortunately it has two problems:

  • It's not virtual, so we can't override it with custom logic.
  • Even if we could, it's dispatched on the moving object, so we'd have to override it in every Actor that can potentially collide with a Tileset, not just in the Tileset itself.

So unfortunately this looks like a dead end, at least without modifying the engine.

@kring kring self-assigned this May 4, 2021
@kring kring moved this from To do to In progress in Cesium for Unreal May 4, 2021
@nithinp7
Copy link
Contributor

nithinp7 commented May 4, 2021

@kring I went down the rabbit hole for a couple hours today and I found two potential leads for "physics culling".

  1. The first is that we can set the collisions settings on the tileset to "overlap" pawns instead of "block" them. This will generate OnComponentBeginOverlap and OnComponentEndOverlap events that can be bound to local functions in UGltfPrimitiveComponent. So far I've been able to print out a test string when the pawn flies through the tileset, so this function would be a good spot to put the culling checks inside. But here we have the opposite problem, now we don't know how to trigger the regular physics collision sequence when the overlap event happens not to be inside the culling volume. I was hoping DispatchBlockingHit would do the job, but it does not seem to cause any physics to happen. Still there may be a way to trigger the regular physics sequence by digging further into the engine code and determining where the regular collision handling is triggered. Of course we could also manually try to calculate the physics handling. For pawns at least it might be as simple as just killing the velocity in the collision normal direction and displacing the pawn back along the normal until it isn't colliding, but this wouldn't be generalizable.

  2. The second lead I found was from this link: https://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/guide/Manual/AdvancedCollisionDetection.html#contact-modification
    I was able to find a few references to contact modification within the engine source also found folks talking about it on the Unreal forums here: https://forums.unrealengine.com/t/collision-modify-callback-unexpected-behaviour/128982
    TLDR: Contact modification is a way to alter the calculated contacts after the collision detection phase and before the collision resolution phase; which is exactly what we want.

@nithinp7
Copy link
Contributor

nithinp7 commented May 4, 2021

Also some more talk about contact modification on UDN: https://udn.unrealengine.com/s/question/0D52L00004luiWbSAI/controlling-character-vs-rb-collision-response

@nithinp7 nithinp7 self-assigned this May 6, 2021
@nithinp7
Copy link
Contributor

Just to keep this issue in-the-loop as far as what is being worked on, the priority as I understand it is:

  • 2.5D clipping, visual only + avoid unneeded requests from cesium-native
  • 2.5D clipping of physics meshes as well
  • Full 3D clipping (I'm not sure if this is needed or even wanted yet)

For 2.5D, I'm planning on using Unreal splines to define arbitrary concave polygons to cull, I think it will be a convenient interface for users. On the other hand, I'm not sure what the best interface would be for users to define arbitrary 3D polygons if we decide that's something we want to do as well.

@kring kring removed their assignment May 19, 2021
@kring
Copy link
Member Author

kring commented Sep 2, 2021

Fixed in #446, even if there's more we can imagine doing in the future.

@kring kring closed this as completed Sep 2, 2021
Cesium for Unreal automation moved this from In progress to Done Sep 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Development

No branches or pull requests

3 participants