Optimizing Cesium 3D Tileset for Real-Time Applications in Unreal Engine

Hi everyone,

I’m currently working on an Unreal Engine project using Cesium 3D Tileset Georeference for an immersive real estate platform, and I’ve encountered some performance challenges that I’d like advice on.

System and Setup:

  • GPU: RTX 4090
  • CPU: AMD 7950X3D
  • RAM: 64GB DDR5
  • Monitor Resolution: 3840x1440 (Ultra-wide 2K)

Observations:

  1. Horizon View (lots of Cesium visible):
  • FPS: 50-70
  • GPU Utilization: ~25%
  • CPU Utilization: ~5%
  1. Top-Down View (~2km² of Cesium visible):
  • FPS: 120+ (capped at 120)
  • GPU Utilization: ~65%
  • CPU Utilization: ~30%

It seems that performance significantly improves when zooming out to a more limited view of the tileset.

Question:

Are there recommended strategies or resources for optimizing Cesium in real-time Unreal Engine applications? Specifically:

  • How can I improve performance for horizon views with extensive Cesium datasets?
  • Are there settings, workflows, or optimizations in Cesium or Unreal Engine that you’d recommend?

Any advice, best practices, or resources for this use case would be greatly appreciated.

Thanks in advance for your help!

Hi @Immersion_Internal, welcome to the community!
Can you tell us which 3D Tiles tilesets you’re using? Also, have you changed any settings on the Cesium3DTilesets from their defaults? That frame rate sounds quite low on some very powerful hardware.

I’m not sure of the name. It’s from the Google API.

I’ve tried adding attachments, but new users can’t do that…

Here’s a copy and paste of the Unreal settings for the 3D tileset:

Begin Map
Begin Level
Begin Actor Class=/Script/CesiumRuntime.Cesium3DTileset Name=Cesium3DTileset_5 Archetype=“/Script/CesiumRuntime.Cesium3DTileset’/Script/CesiumRuntime.Default__Cesium3DTileset’” ExportPath=“/Script/CesiumRuntime.Cesium3DTileset’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5’”
Begin Object Class=/Script/CesiumRuntime.Cesium3DTilesetRoot Name=“Tileset” Archetype=“/Script/CesiumRuntime.Cesium3DTilesetRoot’/Script/CesiumRuntime.Default__Cesium3DTileset:Tileset’” ExportPath=“/Script/CesiumRuntime.Cesium3DTilesetRoot’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5.Tileset’”
End Object
Begin Object Class=/Script/CesiumRuntime.CesiumPolygonRasterOverlay Name=“CesiumPolygonRasterOverlay” ExportPath=“/Script/CesiumRuntime.CesiumPolygonRasterOverlay’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5.CesiumPolygonRasterOverlay’”
End Object
Begin Object Name=“Tileset” ExportPath=“/Script/CesiumRuntime.Cesium3DTilesetRoot’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5.Tileset’”
RelativeLocation=(X=31.984504,Y=-29903.060001,Z=226651.455746)
RelativeRotation=(Pitch=-0.000000,Yaw=-57.281591,Roll=0.000000)
Mobility=Static
End Object
Begin Object Name=“CesiumPolygonRasterOverlay” ExportPath=“/Script/CesiumRuntime.CesiumPolygonRasterOverlay’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5.CesiumPolygonRasterOverlay’”
Polygons(0)=“/Script/CesiumRuntime.CesiumCartographicPolygon’CesiumCartographicPolygon_0’”
MaximumTextureSize=4096
MaximumSimultaneousTileLoads=5
CreationMethod=Instance
End Object
Root=“Tileset”
Georeference=“/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.CesiumGeoreference_0”
CreditSystem=“/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.CesiumCreditSystemBP_C_0”
MaximumScreenSpaceError=8.000000
PreloadAncestors=False
PreloadSiblings=False
ForbidHoles=True
MaximumSimultaneousTileLoads=16
MaximumCachedBytes=1342
BodyInstance=(CollisionProfileName=“BlockAll”)
TilesetSource=FromUrl
CesiumIonServer=“/Script/CesiumRuntime.CesiumIonServer’/Game/CesiumSettings/CesiumIonServers/CesiumIonSaaS.CesiumIonSaaS’”
CreatePhysicsMeshes=False
WaterMaterial=“/Script/Engine.MaterialInstanceConstant’/Game/M1_assets/Materials/MI_RiverWater.MI_RiverWater’”
CustomDepthParameters=(RenderCustomDepth=True)
bIsMac=True
RootComponent=“Tileset”
ActorLabel=“Cesium3DTileset5”
FolderPath=“Cesium”
InstanceComponents(0)=“/Script/CesiumRuntime.CesiumPolygonRasterOverlay’CesiumPolygonRasterOverlay’”
End Actor
End Level
Begin Surface
End Surface
End Map

I have changed a few things following some forums that I’ve seen online. Here is an updated copy of my settings:
Begin Map
Begin Level
Begin Actor Class=/Script/CesiumRuntime.Cesium3DTileset Name=Cesium3DTileset_5 Archetype=“/Script/CesiumRuntime.Cesium3DTileset’/Script/CesiumRuntime.Default__Cesium3DTileset’” ExportPath=“/Script/CesiumRuntime.Cesium3DTileset’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5’”
Begin Object Class=/Script/CesiumRuntime.Cesium3DTilesetRoot Name=“Tileset” Archetype=“/Script/CesiumRuntime.Cesium3DTilesetRoot’/Script/CesiumRuntime.Default__Cesium3DTileset:Tileset’” ExportPath=“/Script/CesiumRuntime.Cesium3DTilesetRoot’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5.Tileset’”
End Object
Begin Object Class=/Script/CesiumRuntime.CesiumPolygonRasterOverlay Name=“CesiumPolygonRasterOverlay” ExportPath=“/Script/CesiumRuntime.CesiumPolygonRasterOverlay’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5.CesiumPolygonRasterOverlay’”
End Object
Begin Object Name=“Tileset” ExportPath=“/Script/CesiumRuntime.Cesium3DTilesetRoot’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5.Tileset’”
RelativeLocation=(X=31.984504,Y=-29903.060001,Z=226651.455746)
RelativeRotation=(Pitch=-0.000000,Yaw=-57.281591,Roll=0.000000)
Mobility=Static
End Object
Begin Object Name=“CesiumPolygonRasterOverlay” ExportPath=“/Script/CesiumRuntime.CesiumPolygonRasterOverlay’/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.Cesium3DTileset_5.CesiumPolygonRasterOverlay’”
Polygons(0)=“/Script/CesiumRuntime.CesiumCartographicPolygon’CesiumCartographicPolygon_0’”
MaximumTextureSize=4096
MaximumSimultaneousTileLoads=5
CreationMethod=Instance
End Object
Root=“Tileset”
Georeference=“/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.CesiumGeoreference_0”
CreditSystem=“/Game/2430_LeWil/Content/ImmersionProWil.ImmersionProWil:PersistentLevel.CesiumCreditSystemBP_C_0”
MaximumScreenSpaceError=24.000000
ForbidHoles=True
MaximumSimultaneousTileLoads=16
MaximumCachedBytes=67108864
LoadingDescendantLimit=16
EnforceCulledScreenSpaceError=True
BodyInstance=(CollisionProfileName=“BlockAll”)
LoadProgress=100.000000
TilesetSource=FromUrl
Url=“ImNotLettingYouStealMyAPIKeyBruh”
CesiumIonServer=“/Script/CesiumRuntime.CesiumIonServer’/Game/CesiumSettings/CesiumIonServers/CesiumIonSaaS.CesiumIonSaaS’”
CreatePhysicsMeshes=False
CustomDepthParameters=(RenderCustomDepth=True)
bIsMac=True
RootComponent=“Tileset”
ActorLabel=“Cesium3DTileset5”
FolderPath=“Cesium”
InstanceComponents(0)=“/Script/CesiumRuntime.CesiumPolygonRasterOverlay’CesiumPolygonRasterOverlay’”
End Actor
End Level
Begin Surface
End Surface
End Map

You don’t need your API key, but we do need to see the rest of the URL.

Did your new settings help at all? I noticed that you changed the MaximumScreenSpaceError from 8 to 24. That should have a significant positive impact on performance.

It might be helpful to try the Cesium for Unreal Samples project - particularly the Google level - and see what kind of frame rate you get there.

I see! This was more of a precautionary measure! My changes seem to have made a significant difference. Tiles are loading much faster now, culling is better, and there are fewer holes in the terrain. The frame rate is locked at a consistent 60fps, which is a huge improvement!

I’ll need to test at higher resolutions to be sure, but it seems like the bottleneck in Cesium has been mitigated for now.

Here’s the full URL I’ve been using:
https://tile.googleapis.com/v1/3dtiles/root.json?key=

Thank you for the suggestion to try the Cesium for Unreal Samples project! I’ll take a look at the Google level and compare the frame rates to see how it performs there.

Let me know if there are any other settings or tweaks you’d recommend exploring!