Line trace passing through Cesium3DTileset on high LoD

Hi,

I’m using Cesium tile sets exported from Agisoft Metashape and need an as photorealistic representation of the photogrammetry data set as possible. This is why I try to have the highest level of detail possible e.g. I have currently set the Maximum Screen Space Error to 1.0 and I have enabled "Enforce Culled Screen Space Error" etc.

Also I want to mark spots in a tile set using line trace by channel e.g. to measure the distance between two points.

Unfortunately it seems that if the level of detail is high, the line trace passes through the many small tiles. “Create Physics Meshes” is enabled.

Is this a known behavior in Cesium for Unreal? Is it something that has to be fixed by exporting the tilesets differently from Metashape or can it be fixed in Unreal?

Or would I just have to find a trade-off point between “high enough LoD” and “trace still hits everywhere”?

I have also tried using “Sphere Trace By Channel” with a (in this case) large radius of 100 but it still mostly passes through everything.

Thanks in advance :slight_smile:


Cesium for Unreal discards triangles that are degenerate, according to the definition that Unreal itself uses. We found that if we didn’t do this and passed those triangles through to Unreal, then it would fail the physics mesh creation completely, and collisions with the entire tile would fail.

The code in Cesium for Unreal that discards these small triangles is here:

The code in Unreal with a similar check is here:
https://github.com/EpicGames/UnrealEngine/blob/5.1.1-release/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/TriangleMeshImplicitObject.cpp#L1576

So, as far as I’m aware, this is a limitation of Unreal Engine’s physics engine and not something we can fix in Cesium for Unreal.

Thanks for your response. It’s awesome how active you are in this forum. Thank you for your work :slight_smile:

I don’t know much about degenerate triangles. At which point do these triangles degenerate?
Is this something that’s depending on my Unreal Engine and Cesium for Unreal LoD and rendering settings?
Or are they already considered degenerate when the tiles are being exported from Metashape (in my case) and I could tweak the settings there?

Or is this something that just can’t be avoided if I want very high LoD with Cesium tiles?

I think the problem is that a) Metashape is creating a mesh with very small triangles, b) by setting the Max SSE low in Cesium for Unreal, you’re telling it to select a high-detail (and thus small-triangle) representation, c) Unreal’s physics engine has a rather unaccomodating view of degenerate triangles, declaring triangles degenerate when I might argue they’re just small.

I think it could be worthwhile to confirm that this is truly what’s happening, though. Perhaps set a breakpoint after the code in my first link above and compare the number of faces in faceRemap to the triangleCount. Is it discarding a lot of triangles?

Unfortunately my understanding of Visual Studio and C++ is very limited but I managed to get this debugging output for example. I haven’t found the correct settings yet for triangleCount to not be optimized away during debugging but since it’s defined above as int32 triangleCount = indices.Num() /3 and indices has length 432, I assume that all three of triangleCount length of triangles, and length of faceRemap are 144 at the breakpoint.

Stepping through to that breakpoint several times, the lengths/counts were always equal to each other.

I’m also getting these outputs. Could this have something to do with it?

[2023.10.23-11.37.49:286][ 65]LogStaticMesh: Warning: UStaticMesh::GetPhysicsTriMeshData: \\
CPU data not available on selected LOD (UseLODIndex=0, LODForCollision=0) \\
on 'StaticMesh /Game/WorldUEDPIE_0_CesiumGlobe.CesiumGlobe:PersistentLevel.Cesium3DTileset_1.CesiumGltfComponent_485.http://localhost:8000/densecloudtest_cesium/Data/b0/f30055.b3dm mesh 2 primitive 0.http://localhost:8000/densecloudtest_cesium/Data/b0/f30055.b3dm mesh 2 primitive 0'.

[2023.10.23-11.37.49:286][ 65]LogPhysics: Warning: UBodySetup::GetCookInfo: \\
ContainsPhysicsTriMeshData returned true, but GetPhysicsTriMeshData returned false. \\
This inconsistency should be fixed for asset '/Game/World/UEDPIE_0_CesiumGlobe.CesiumGlobe:PersistentLevel.Cesium3DTileset_1.CesiumGltfComponent_485.http://localhost:8000/densecloudtest_cesium/Data/b0/f30055.b3dm mesh 2 primitive 0.http://localhost:8000/densecloudtest_cesium/Data/b0/f30055.b3dm mesh 2 primitive 0'

I’m thinking for my use case I might just revert back to using FBX 3D models with Nanite instead of CesiumTiles and give the StaticMeshActors a CesiumGlobeAnchor component to place them in the Cesium World at the coordinates I know they have.

Yeah I agree, it seems that there are no degenerate triangles, at least not in that particular tile that you’re looking at.

You might be on to something with those messages. I’ve never seen such messages before, and searching the UE source it seems they’re new in UE 5.3. The first message is reported here:
https://github.com/EpicGames/UnrealEngine/blob/5.3.1-release/Engine/Source/Runtime/Engine/Private/StaticMesh.cpp#L7287

But looking at that code, it’s not obvious why we should be in there at all. Would you mind seting a breakpoint on the UE_LOG line linked above and share the call stack you’re seeing?

First of all: Please tell me if we reach a point where you no longer have the time, capacity, or patience to investigate this issue. I’m interested in getting it solved but as I said, I could also probably make my use case work with FBX. :slight_smile:

This is the debug call stack that shows up immediately after loading into a level with one of the tilesets. (btw, it’s not just a single tile set, the behavior is the same for multiple. All of them have been generated with metashape, though)

Just for good measure I’ve let the tiles validator check the tileset, however I have not enough knowledge about 3D tiles to really interpret the output:

And these are the settings I used in metashape to build the tiled model. (Exporting with different tile sizes made no difference when it comes to the original issue of the line trace passing through so I decided to create the tilesets with as few separate files as possible.)

grafik

Thanks, that call stack is really interesting!

It appears that you have CreateNavCollision enabled on the tileset. And in UE 5.3, at least (or perhaps in all versions, I’m not sure), creating nav collision requires physics meshes. Because the physics meshes won’t exist yet at that point (they’re added a few lines below!), UE creates them automatically. And that fails, at least in some cases, because the source mesh data isn’t available on the CPU.

I think the solution is easy: move the call to CreateNavCollision after the code that adds the physics meshes and sets bCreatedPhysicsMeshes to true.

I’m not sure if that will help at all with your line traces, but I think it’s worth a try.

You should also consider turning off NavCollision if you’re not using it.

I’ve finally come around to check on this issue again.

While I still don’t know what causes the triangles to be degenerate when exporting our tiled models as Cesium tilesets from our photogrammetry software(s), I can confirm that this bit of code is actually the culprit.

After changing it to this code, collision works on the entire tileset like we would want it to. Although I do see now why you would want to ignore the degenerate triangles, it does seem very computationally intensive and memory-heavy :sweat_smile:

  for (int32 i = 0; i < triangleCount; ++i) {
    const int32 index0 = 3 * i;
    int32 vIndex0 = indices[index0 + 1];
    int32 vIndex1 = indices[index0];
    int32 vIndex2 = indices[index0 + 2];

    triangles.Add(Chaos::TVector<int32, 3>(vIndex0, vIndex1, vIndex2));
    faceRemap.Add(i);
}

That’s interesting @arbertrary, thanks for letting us know.

We actually added that code because Unreal itself seemed to be using a similar check to detect degenerate triangles, and, when it detected one, it seemed to disable physics for the entire mesh, not just the degenerate triangle. So we added some code to filter them out ahead of time, so at least the bulk of the mesh would work.

I don’t know if something has changed in UE since, or if there’s as bug in this code such that it doesn’t work correctly with certain meshes, or something else. If you learn more details, let us know. Otherwise we will try to investigate more deeply ourselves soon.

In the meantime I thought about adding a boolean option to Cesium3DTileset called e.g. ForceBuildChaosTriangleMeshes or something like that. So that only if it is checked, the degenerate triangles are not discarded.

I’ve piped this option all the way from Cesium3DTileset.cpp to the BuildChaosTriangleMeshes function in CesiumGltfComponent.cpp but I’m pretty sure that that’s not the best way to approach that. I’m not (yet) a C++ dev unfortunately. :sweat_smile:

In Cesium3DTileset the function createOffGameThread is called and from there on in CesiumGltfComponent.cpp it’s:

loadModelAnyThreadPart 
-> loadNode 
-> loadMesh 
-> loadPrimitive 
-> BuildChaosTriangleMeshes

so I’ve added this boolean as parameter to each of those functions and the code in BuildChaosTriangleMeshes then looks like this and does indeed work.

EDIT 2: I have created a pull request on github, just so that I can better share the code changes I made: Add option to enforce BuildChaosMeshTriangles for degenerate triangles by arbertrary · Pull Request #1456 · CesiumGS/cesium-unreal · GitHub

 for (int32 i = 0; i < triangleCount; ++i) {
   const int32 index0 = 3 * i;
   int32 vIndex0 = indices[index0 + 1];
   int32 vIndex1 = indices[index0];
   int32 vIndex2 = indices[index0 + 2];

   if (forceBuildChaosTriangleMeshes) {
       triangles.Add(Chaos::TVector<int32, 3>(vIndex0, vIndex1, vIndex2));
       faceRemap.Add(i);
   } else{
       if (!isTriangleDegenerate(
               vertices.X(vIndex0),
               vertices.X(vIndex1),
               vertices.X(vIndex2))) {
         triangles.Add(Chaos::TVector<int32, 3>(vIndex0, vIndex1, vIndex2));
         faceRemap.Add(i);
       }
   }

It does, however, produce a lot of the following warnings and only once on editor startup (at least it seems like that right now) the Error callstack at the bottom. Both do not cause the editor to crash or the collision to not work.

LogPhysics: Warning: (Invalid Normal from ConvertQueryImpactHit) Non-normalized OutResult.Normal from hit conversion: X=0.000 Y=0.000 Z=0.000 (Component- CesiumGltfPrimitiveComponent /Game/Maps/CesiumWorld/UEDPIE_0_Globe.Globe:PersistentLevel.Cesium3DTileset_3.CesiumGltfComponent_7.CesiumGltfPrimitiveComponent_2)
LogPhysics: Warning: Start Loc(X=-1372.168 Y=5104.144 Z=-658.756), End Loc(X=-26133.757 Y=-31954.970 Z=-23318.980), Hit Loc(X=-1865.093 Y=4366.414 Z=-1109.849), ImpactNormal(X=0.000 Y=0.000 Z=0.000) NormalPreSafeNormalize(X=0.000 Y=0.000 Z=0.000)
LogPhysics: Warning: (Invalid Normal from ConvertQueryImpactHit) Non-normalized OutResult.Normal from hit conversion: X=0.000 Y=0.000 Z=0.000 (Component- CesiumGltfPrimitiveComponent /Game/Maps/CesiumWorld/UEDPIE_0_Globe.Globe:PersistentLevel.Cesium3DTileset_3.CesiumGltfComponent_20.CesiumGltfPrimitiveComponent_6)
LogPhysics: Warning: Start Loc(X=-1472.014 Y=5123.337 Z=-649.842), End Loc(X=-1727.085 Y=4042.166 Z=-1103.723), Hit Loc(X=-1664.978 Y=4305.417 Z=-993.209), ImpactNormal(X=0.000 Y=0.000 Z=0.000) NormalPreSafeNormalize(X=0.000 Y=0.000 Z=0.000)
LogOutputDevice: Error: === Handled ensure: ===
LogOutputDevice: Error: Ensure condition failed: OutResult.Normal.IsNormalized()  [File:D:\build\++UE5\Sync\Engine\Source\Runtime\Engine\Private\Collision\CollisionConversions.cpp] [Line: 76] 
LogOutputDevice: Error: Stack: 
LogOutputDevice: Error: [Callstack] 0x00007ffbf12123b5 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf1195c70 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf11d407c UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf125fce9 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf13d93f1 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf1b50c57 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf1bd19d5 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf5374502 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf53775b8 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a7b8 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf5319da1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a1e1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a7b8 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf5319da1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a1e1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a7b8 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf5319da1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a1e1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a7b8 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf5319da1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a1e1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a7b8 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf5319da1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a1e1 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534a7b8 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf5349777 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf503d280 UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf534828f UnrealEditor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf0bbaacd UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf0bbcd2d UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf0bcf70c UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf0bcf7bd UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf0b99e51 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf2b987eb UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf2b9fd32 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf57e1c9f UnrealEditor-Core.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf57e22ae UnrealEditor-Core.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf57eeeb0 UnrealEditor-Core.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf2bc75aa UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf2bd0bfe UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf1c89839 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbf1c967a2 UnrealEditor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbed9658f8 UnrealEditor-UnrealEd.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffbee5bea06 UnrealEditor-UnrealEd.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff7ecf28af2 UnrealEditor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff7ecf4d28c UnrealEditor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff7ecf4d37a UnrealEditor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff7ecf50854 UnrealEditor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff7ecf66984 UnrealEditor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff7ecf69d7a UnrealEditor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffce9d47344 KERNEL32.DLL!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffcebd3cc91 ntdll.dll!UnknownFunction []

Thanks for opening the PR! We’ll take a closer look at this soon.